Re: [PATCH] D33705: [CGVTables] Finalize SP before attempting to clone it
For some reason your comments aren't showing up on Phabricator, so replying via email - hope everybody sees it. If SPs are now all finalized early - I'm assuming there's some other code > that finalizes SPs that's no longer needed? > Not all of them, just the one before cloning. I wanted to make the minimal change possible here, since this already seems like a bit of a hack to work around the fact that we can't properly forward variadic function calls at the IR level. > Also - this seems like a layering/separation issue - does other code call > into the DI as casually/explicitly as this code being added to CGVTables? > (Or should the callback go through some more generic entry point in > CGDebugInfo to delegate/handle that?) & is there nothing in CGDebugInfo > that is already called back in a timely fashion to handle this? I'm > guessing what's needed is a "IR has finished being generated for this > function, opt/codegen is about to start"? That seems like a good generic > callback & probably shouldn't be coming from something called CGVTables? > (presuming there's a more general place to put that) > I suppose there's CGDebugInfo::EmitFunctionEnd, so if we did want to finalize every SP as soon as we're done with it, we could put an explicit call to that extent there. Frankly though I don't really know the clang code too well, I just want to unbreak LLVM ;). ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24371: Add diagnostics to require_constant_initialization
Go for it On May 31, 2017 20:07, "Eric Fiselier via Phabricator" < revi...@reviews.llvm.org> wrote: > EricWF added a comment. > > @loladiro The patch doesn't apply correctly to the test. Do you mind if I > hijack this and fix it? > > > Repository: > rL LLVM > > https://reviews.llvm.org/D24371 > > > > ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r304451 - [SemaCXX] Add diagnostics to require_constant_initialization
Author: kfischer Date: Thu Jun 1 13:54:16 2017 New Revision: 304451 URL: http://llvm.org/viewvc/llvm-project?rev=304451&view=rev Log: [SemaCXX] Add diagnostics to require_constant_initialization Summary: This hooks up the detailed diagnostics of why constant initialization was not possible if require_constant_initialization reports an error. I have updated the test to account for the new notes. Reviewed By: EricWF Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D24371 Modified: cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/test/SemaCXX/attr-require-constant-initialization.cpp Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=304451&r1=304450&r2=304451&view=diff == --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jun 1 13:54:16 2017 @@ -6,6 +6,17 @@ void Sema::CheckCompleteVariableDeclarat << Init->getSourceRange(); Diag(attr->getLocation(), diag::note_declared_required_constant_init_here) << attr->getRange(); +if (getLangOpts().CPlusPlus11) { + APValue Value; + SmallVector Notes; + Init->EvaluateAsInitializer(Value, getASTContext(), var, Notes); + for (auto &it : Notes) +Diag(it.first, it.second); +} else { + Diag(CacheCulprit->getExprLoc(), + diag::note_invalid_subexpr_in_const_expr) + << CacheCulprit->getSourceRange(); +} } } else if (!var->isConstexpr() && IsGlobal && Modified: cfe/trunk/test/SemaCXX/attr-require-constant-initialization.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-require-constant-initialization.cpp?rev=304451&r1=304450&r2=304451&view=diff == --- cfe/trunk/test/SemaCXX/attr-require-constant-initialization.cpp (original) +++ cfe/trunk/test/SemaCXX/attr-require-constant-initialization.cpp Thu Jun 1 13:54:16 2017 @@ -7,9 +7,9 @@ #define ATTR __attribute__((require_constant_initialization)) // expected-note 0+ {{expanded from macro}} -int ReturnInt(); +int ReturnInt(); // expected-note 0+ {{declared here}} -struct PODType { +struct PODType { // expected-note 0+ {{declared here}} int value; int value2; }; @@ -20,20 +20,20 @@ struct PODType { struct LitType { constexpr LitType() : value(0) {} constexpr LitType(int x) : value(x) {} - LitType(void *) : value(-1) {} + LitType(void *) : value(-1) {} // expected-note 0+ {{declared here}} int value; }; #endif -struct NonLit { +struct NonLit { // expected-note 0+ {{declared here}} #if __cplusplus >= 201402L constexpr NonLit() : value(0) {} constexpr NonLit(int x) : value(x) {} #else - NonLit() : value(0) {} + NonLit() : value(0) {} // expected-note 0+ {{declared here}} NonLit(int x) : value(x) {} #endif - NonLit(void *) : value(-1) {} + NonLit(void *) : value(-1) {} // expected-note 0+ {{declared here}} ~NonLit() {} int value; }; @@ -43,7 +43,7 @@ struct StoresNonLit { constexpr StoresNonLit() : obj() {} constexpr StoresNonLit(int x) : obj(x) {} #else - StoresNonLit() : obj() {} + StoresNonLit() : obj() {} // expected-note 0+ {{declared here}} StoresNonLit(int x) : obj(x) {} #endif StoresNonLit(void *p) : obj(p) {} @@ -82,6 +82,12 @@ void test_basic_start_static_2_1() { const int non_global = 42; ATTR static const int &local_init = non_global; // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initialization' attribute here}} +#if __cplusplus >= 201103L + // expected-note@-3 {{reference to 'non_global' is not a constant expression}} + // expected-note@-5 {{declared here}} +#else + // expected-note@-6 {{subexpression not valid in a constant expression}} +#endif ATTR static const int &global_init = glvalue_int; ATTR static const int &temp_init = 42; } @@ -89,8 +95,18 @@ void test_basic_start_static_2_1() { ATTR const int &temp_ref = 42; ATTR const int &temp_ref2 = ReturnInt(); // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initialization' attribute here}} +#if __cplusplus >= 201103L +// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}} +#else +// expected-note@-5 {{subexpression not valid in a constant expression}} +#endif ATTR const NonLit &nl_temp_ref = 42; // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initialization' attribute here}} +#if __cplusplus >= 201103L +// expected-note@-3 {{non-literal type 'const NonLit' cannot be used in a constant expression}} +#else +// expected-note@-5 {{subexpression not val
r304470 - [CGDebugInfo] Finalize SubPrograms when we're done with them
Author: kfischer Date: Thu Jun 1 16:14:03 2017 New Revision: 304470 URL: http://llvm.org/viewvc/llvm-project?rev=304470&view=rev Log: [CGDebugInfo] Finalize SubPrograms when we're done with them `GenerateVarArgsThunk` in `CGVTables` clones a function before the frontend is done emitting the compilation unit. Because of the way that DIBuilder works, this means that the attached subprogram had incomplete (temporary) metadata. Cloning such metadata is semantically disallowed, but happened to work anyway due to bugs in the cloning logic. rL304226 attempted to fix up that logic, but in the process exposed the incorrect API use here and had to be reverted. To be able to fix this, I added a new method to DIBuilder in rL304467, to allow finalizing a subprogram independently of the entire compilation unit. Use that here, in preparation of re-applying rL304226. Reviewers: aprantl, dblaikie Differential Revision: https://reviews.llvm.org/D33705 Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp cfe/trunk/lib/CodeGen/CGDebugInfo.h cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=304470&r1=304469&r2=304470&view=diff == --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Thu Jun 1 16:14:03 2017 @@ -3263,7 +3263,7 @@ void CGDebugInfo::EmitInlineFunctionStar void CGDebugInfo::EmitInlineFunctionEnd(CGBuilderTy &Builder) { assert(CurInlinedAt && "unbalanced inline scope stack"); - EmitFunctionEnd(Builder); + EmitFunctionEnd(Builder, nullptr); setInlinedAt(llvm::DebugLoc(CurInlinedAt).getInlinedAt()); } @@ -3332,7 +3332,7 @@ void CGDebugInfo::EmitLexicalBlockEnd(CG LexicalBlockStack.pop_back(); } -void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { +void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn) { assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); unsigned RCount = FnBeginRegionCount.back(); assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch"); @@ -3344,6 +3344,9 @@ void CGDebugInfo::EmitFunctionEnd(CGBuil LexicalBlockStack.pop_back(); } FnBeginRegionCount.pop_back(); + + if (Fn && Fn->getSubprogram()) +DBuilder.finalizeSubprogram(Fn->getSubprogram()); } llvm::DIType *CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.h?rev=304470&r1=304469&r2=304470&view=diff == --- cfe/trunk/lib/CodeGen/CGDebugInfo.h (original) +++ cfe/trunk/lib/CodeGen/CGDebugInfo.h Thu Jun 1 16:14:03 2017 @@ -367,7 +367,7 @@ public: void EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, QualType FnType); /// Constructs the debug code for exiting a function. - void EmitFunctionEnd(CGBuilderTy &Builder); + void EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn); /// Emit metadata to indicate the beginning of a new lexical block /// and push the block onto the stack. Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=304470&r1=304469&r2=304470&view=diff == --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Thu Jun 1 16:14:03 2017 @@ -348,7 +348,7 @@ void CodeGenFunction::FinishFunction(Sou // Emit debug descriptor for function end. if (CGDebugInfo *DI = getDebugInfo()) -DI->EmitFunctionEnd(Builder); +DI->EmitFunctionEnd(Builder, CurFn); // Reset the debug location to that of the simple 'return' expression, if any // rather than that of the end of the function's scope '}'. ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r362855 - [analyzer] Add werror flag for analyzer warnings
Author: kfischer Date: Fri Jun 7 16:34:00 2019 New Revision: 362855 URL: http://llvm.org/viewvc/llvm-project?rev=362855&view=rev Log: [analyzer] Add werror flag for analyzer warnings Summary: We're using the clang static analyzer together with a number of custom analyses in our CI system to ensure that certain invariants are statiesfied for by the code every commit. Unfortunately, there currently doesn't seem to be a good way to determine whether any analyzer warnings were emitted, other than parsing clang's output (or using scan-build, which then in turn parses clang's output). As a simpler mechanism, simply add a `-analyzer-werror` flag to CC1 that causes the analyzer to emit its warnings as errors instead. I briefly tried to have this be `Werror=analyzer` and make it go through that machinery instead, but that seemed more trouble than it was worth in terms of conflicting with options to the actual build and special cases that would be required to circumvent the analyzers usual attempts to quiet non-analyzer warnings. This is simple and it works well. Reviewed-By: NoQ, Szelethusw Differential Revision: https://reviews.llvm.org/D62885 Modified: cfe/trunk/include/clang/Driver/CC1Options.td cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h cfe/trunk/lib/Frontend/CompilerInvocation.cpp cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp cfe/trunk/test/Analysis/override-werror.c Modified: cfe/trunk/include/clang/Driver/CC1Options.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=362855&r1=362854&r2=362855&view=diff == --- cfe/trunk/include/clang/Driver/CC1Options.td (original) +++ cfe/trunk/include/clang/Driver/CC1Options.td Fri Jun 7 16:34:00 2019 @@ -166,6 +166,9 @@ def analyzer_config_compatibility_mode : def analyzer_config_compatibility_mode_EQ : Joined<["-"], "analyzer-config-compatibility-mode=">, Alias; +def analyzer_werror : Flag<["-"], "analyzer-werror">, + HelpText<"Emit analyzer results as errors rather than warnings">; + //===--===// // Migrator Options //===--===// Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h?rev=362855&r1=362854&r2=362855&view=diff == --- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h Fri Jun 7 16:34:00 2019 @@ -245,6 +245,9 @@ public: /// strategy. We get better code coverage when retry is enabled. unsigned NoRetryExhausted : 1; + /// Emit analyzer warnings as errors. + unsigned AnalyzerWerror : 1; + /// The inlining stack depth limit. // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls). unsigned InlineMaxStackDepth = 5; @@ -297,7 +300,7 @@ public: AnalyzerDisplayProgress(false), AnalyzeNestedBlocks(false), eagerlyAssumeBinOpBifurcation(false), TrimGraph(false), visualizeExplodedGraphWithGraphViz(false), UnoptimizedCFG(false), -PrintStats(false), NoRetryExhausted(false) { +PrintStats(false), NoRetryExhausted(false), AnalyzerWerror(false) { llvm::sort(AnalyzerConfigCmdFlags); } Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=362855&r1=362854&r2=362855&view=diff == --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original) +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Fri Jun 7 16:34:00 2019 @@ -309,6 +309,7 @@ static bool ParseAnalyzerArgs(AnalyzerOp Args.hasArg(OPT_analyzer_viz_egraph_graphviz); Opts.DumpExplodedGraphTo = Args.getLastArgValue(OPT_analyzer_dump_egraph); Opts.NoRetryExhausted = Args.hasArg(OPT_analyzer_disable_retry_exhausted); + Opts.AnalyzerWerror = Args.hasArg(OPT_analyzer_werror); Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); Opts.AnalyzeNestedBlocks = Modified: cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp?rev=362855&r1=362854&r2=362855&view=diff == --- cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Fri Jun 7 16:34:00 2019 @@ -83,10 +83,11 @@ void ento::createTextPathDiagnosticConsu namespace { cla
Re: [PATCH] D24372: [libcxx] Sprinkle constexpr over compressed_pair
loladiro updated this revision to Diff 72581. loladiro added a comment. back to _VSTD::forward, address review comments, add tests for non-empty deleter and unique_ptrs of arrays. Repository: rL LLVM https://reviews.llvm.org/D24372 Files: include/memory test/std/utilities/memory/unique.ptr/unique.ptr.runtime/constinit.pass.cpp test/std/utilities/memory/unique.ptr/unique.ptr.single/constinit.pass.cpp Index: test/std/utilities/memory/unique.ptr/unique.ptr.single/constinit.pass.cpp === --- /dev/null +++ test/std/utilities/memory/unique.ptr/unique.ptr.single/constinit.pass.cpp @@ -0,0 +1,70 @@ +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03 + +#include +#include + +#ifndef _LIBCPP_SAFE_STATIC +#define _LIBCPP_SAFE_STATIC +#endif + +// This is basically std::default delete, except that it is not empty such that +// we test a different code path in the implementation +template struct nonempty_delete { + uint32_t sentinel; + inline constexpr nonempty_delete() noexcept : sentinel(0xDEADBEEF) {} + template + constexpr inline nonempty_delete( + const nonempty_delete &, + typename std::enable_if::value>::type * = + 0) noexcept : sentinel(0xBAADF00D) {} + inline void operator()(Tp *ptr) const noexcept { +assert(sentinel == 0xDEADBEEF || sentinel == 0xBAADF00D); +delete ptr; + } +}; + +extern std::unique_ptr a; +extern std::unique_ptr b; +extern std::unique_ptr> c; +extern std::unique_ptr> d; +void *tramplea = std::memset(&a, 0xab, sizeof(a)); +void *trampleb = std::memset(&b, 0xab, sizeof(b)); +void *tramplec = std::memset(&a, 0xab, sizeof(c)); +void *trampled = std::memset(&b, 0xab, sizeof(d)); +_LIBCPP_SAFE_STATIC std::unique_ptr a; +_LIBCPP_SAFE_STATIC std::unique_ptr b(nullptr); +_LIBCPP_SAFE_STATIC std::unique_ptr> c; +_LIBCPP_SAFE_STATIC std::unique_ptr> d(nullptr); + +int main() { + // Check that the initialization of 'a' was performed before the + // initialization of 'tramplea'. + for (size_t n = 0; n != sizeof(a); ++n) +assert(reinterpret_cast(tramplea)[n] == 0xab); + // Check that the initialization of 'b' was performed before the + // initialization of 'trampleb'. + for (size_t n = 0; n != sizeof(b); ++n) +assert(reinterpret_cast(trampleb)[n] == 0xab); + // Check that the initialization of 'c' was performed before the + // initialization of 'tramplec'. + for (size_t n = 0; n != sizeof(c); ++n) +assert(reinterpret_cast(tramplec)[n] == 0xab); + // Check that the initialization of 'd' was performed before the + // initialization of 'trampled'. + for (size_t n = 0; n != sizeof(d); ++n) +assert(reinterpret_cast(trampled)[n] == 0xab); + // Put a unique_ptr object back so that the global dtor is valid. + new (&a) std::unique_ptr; + new (&b) std::unique_ptr; + new (&c) std::unique_ptr>; + new (&d) std::unique_ptr>; +} Index: test/std/utilities/memory/unique.ptr/unique.ptr.runtime/constinit.pass.cpp === --- /dev/null +++ test/std/utilities/memory/unique.ptr/unique.ptr.runtime/constinit.pass.cpp @@ -0,0 +1,70 @@ +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03 + +#include +#include + +#ifndef _LIBCPP_SAFE_STATIC +#define _LIBCPP_SAFE_STATIC +#endif + +// This is basically std::default delete, except that it is not empty such that +// we test a different code path in the implementation +template struct nonempty_delete { + uint32_t sentinel; + inline constexpr nonempty_delete() noexcept : sentinel(0xDEADBEEF) {} + template + constexpr inline nonempty_delete( + const nonempty_delete &, + typename std::enable_if::value>::type * = + 0) noexcept : sentinel(0xBAADF00D) {} + inline void operator()(Tp *ptr) const noexcept { +assert(sentinel == 0xDEADBEEF || sentinel == 0xBAADF00D); +delete[] ptr; + } +}; + +extern std::unique_ptr a; +extern std::unique_ptr b; +extern std::unique_ptr> c; +extern std::unique_ptr> d; +void *tramplea = std::memset(&a, 0xab, sizeof(a)); +void *trampleb = std::memset(&b, 0xab, sizeof(b)); +void *tramplec = std::memset(&a, 0xab, sizeof(c)); +void *trampled = std::memset(&b, 0xab, sizeof(d)); +_LIBCPP_SAFE_STATIC std::unique_ptr a; +_LIBCPP_SAFE_STATIC std::unique_ptr b(nu
Re: [PATCH] D24372: [libcxx] Sprinkle constexpr over compressed_pair
loladiro added a comment. Before I commit this, I just realized __libcpp_compressed_pair_imp& operator=(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_assignable<_T1>::value && is_nothrow_copy_assignable<_T2>::value) { _T1::operator=(__p.first()); __second_ = __p.second(); return *this; } is only constexpr in C++14, right? Repository: rL LLVM https://reviews.llvm.org/D24372 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24372: [libcxx] Sprinkle constexpr over compressed_pair
loladiro updated this revision to Diff 72712. loladiro added a comment. Some extra _AFTER_CXX11 that may be necessary - please double check me here, C++11 constexpr rules are not exactly my specialty ;). Repository: rL LLVM https://reviews.llvm.org/D24372 Files: include/memory test/std/utilities/memory/unique.ptr/unique.ptr.runtime/constinit.pass.cpp test/std/utilities/memory/unique.ptr/unique.ptr.single/constinit.pass.cpp Index: test/std/utilities/memory/unique.ptr/unique.ptr.single/constinit.pass.cpp === --- /dev/null +++ test/std/utilities/memory/unique.ptr/unique.ptr.single/constinit.pass.cpp @@ -0,0 +1,70 @@ +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03 + +#include +#include + +#ifndef _LIBCPP_SAFE_STATIC +#define _LIBCPP_SAFE_STATIC +#endif + +// This is basically std::default delete, except that it is not empty such that +// we test a different code path in the implementation +template struct nonempty_delete { + uint32_t sentinel; + inline constexpr nonempty_delete() noexcept : sentinel(0xDEADBEEF) {} + template + constexpr inline nonempty_delete( + const nonempty_delete &, + typename std::enable_if::value>::type * = + 0) noexcept : sentinel(0xBAADF00D) {} + inline void operator()(Tp *ptr) const noexcept { +assert(sentinel == 0xDEADBEEF || sentinel == 0xBAADF00D); +delete ptr; + } +}; + +extern std::unique_ptr a; +extern std::unique_ptr b; +extern std::unique_ptr> c; +extern std::unique_ptr> d; +void *tramplea = std::memset(&a, 0xab, sizeof(a)); +void *trampleb = std::memset(&b, 0xab, sizeof(b)); +void *tramplec = std::memset(&a, 0xab, sizeof(c)); +void *trampled = std::memset(&b, 0xab, sizeof(d)); +_LIBCPP_SAFE_STATIC std::unique_ptr a; +_LIBCPP_SAFE_STATIC std::unique_ptr b(nullptr); +_LIBCPP_SAFE_STATIC std::unique_ptr> c; +_LIBCPP_SAFE_STATIC std::unique_ptr> d(nullptr); + +int main() { + // Check that the initialization of 'a' was performed before the + // initialization of 'tramplea'. + for (size_t n = 0; n != sizeof(a); ++n) +assert(reinterpret_cast(tramplea)[n] == 0xab); + // Check that the initialization of 'b' was performed before the + // initialization of 'trampleb'. + for (size_t n = 0; n != sizeof(b); ++n) +assert(reinterpret_cast(trampleb)[n] == 0xab); + // Check that the initialization of 'c' was performed before the + // initialization of 'tramplec'. + for (size_t n = 0; n != sizeof(c); ++n) +assert(reinterpret_cast(tramplec)[n] == 0xab); + // Check that the initialization of 'd' was performed before the + // initialization of 'trampled'. + for (size_t n = 0; n != sizeof(d); ++n) +assert(reinterpret_cast(trampled)[n] == 0xab); + // Put a unique_ptr object back so that the global dtor is valid. + new (&a) std::unique_ptr; + new (&b) std::unique_ptr; + new (&c) std::unique_ptr>; + new (&d) std::unique_ptr>; +} Index: test/std/utilities/memory/unique.ptr/unique.ptr.runtime/constinit.pass.cpp === --- /dev/null +++ test/std/utilities/memory/unique.ptr/unique.ptr.runtime/constinit.pass.cpp @@ -0,0 +1,70 @@ +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03 + +#include +#include + +#ifndef _LIBCPP_SAFE_STATIC +#define _LIBCPP_SAFE_STATIC +#endif + +// This is basically std::default delete, except that it is not empty such that +// we test a different code path in the implementation +template struct nonempty_delete { + uint32_t sentinel; + inline constexpr nonempty_delete() noexcept : sentinel(0xDEADBEEF) {} + template + constexpr inline nonempty_delete( + const nonempty_delete &, + typename std::enable_if::value>::type * = + 0) noexcept : sentinel(0xBAADF00D) {} + inline void operator()(Tp *ptr) const noexcept { +assert(sentinel == 0xDEADBEEF || sentinel == 0xBAADF00D); +delete[] ptr; + } +}; + +extern std::unique_ptr a; +extern std::unique_ptr b; +extern std::unique_ptr> c; +extern std::unique_ptr> d; +void *tramplea = std::memset(&a, 0xab, sizeof(a)); +void *trampleb = std::memset(&b, 0xab, sizeof(b)); +void *tramplec = std::memset(&a, 0xab, sizeof(c)); +void *trampled = std::memset(&b, 0xab, sizeof(d)); +_LIBCPP_SAFE_STATIC std::unique_ptr a; +_LIBCPP_SAFE_STA
[PATCH] D24372: [libcxx] Sprinkle constexpr over compressed_pair
loladiro added a comment. Bump, please do take another close look at the latest update, particularly with respecting to marking things constexpr that are not so in C++11. Repository: rL LLVM https://reviews.llvm.org/D24372 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D24371: Add diagnostics to require_constant_initialization
loladiro created this revision. loladiro added reviewers: EricWF, aaron.ballman, rsmith. loladiro added a subscriber: cfe-commits. loladiro set the repository for this revision to rL LLVM. This hooks up the detailed diagnostics why constant initialization was not possible if require_constant_initialization reports an error. I have updated the test to account for the new notes. Everything works fine, except that in C++11 mode we get: ``` error: 'note' diagnostics expected but not seen: File /data/llvm/tools/clang/test/SemaCXX/attr-require-constant-initialization.cpp Line 229 (directive at /data/llvm/tools/clang/test/SemaCXX/attr-require-constant-initialization.cpp:231): non-constexpr constructor 'NonLit' cannot be used in a constant expression error: 'note' diagnostics seen but not expected: (frontend): non-literal type 'NonLit' cannot be used in a constant expression ``` This is because of an ImplicitValueInitExpr that gets passed into CheckLiteralType, but since ImplicitValueInitExpr doesn't have source information we get an invalid source location. I'm not really sure how to fix that (Is it possible to test for a note without source location?). Adding the proper source locations to ImplicitValueInitExpr seemed like a bigger undertaking than was warranted for this patch, so I'd appreciate guidance on how to proceed. Repository: rL LLVM https://reviews.llvm.org/D24371 Files: lib/Sema/SemaDecl.cpp test/SemaCXX/attr-require-constant-initialization.cpp Index: test/SemaCXX/attr-require-constant-initialization.cpp === --- test/SemaCXX/attr-require-constant-initialization.cpp +++ test/SemaCXX/attr-require-constant-initialization.cpp @@ -7,9 +7,9 @@ #define ATTR __attribute__((require_constant_initialization)) // expected-note 0+ {{expanded from macro}} -int ReturnInt(); +int ReturnInt(); // expected-note 0+ {{declared here}} -struct PODType { +struct PODType { // expected-note 0+ {{declared here}} int value; int value2; }; @@ -20,17 +20,17 @@ struct LitType { constexpr LitType() : value(0) {} constexpr LitType(int x) : value(x) {} - LitType(void *) : value(-1) {} + LitType(void *) : value(-1) {} // expected-note 0+ {{declared here}} int value; }; #endif -struct NonLit { +struct NonLit { // expected-note 0+ {{declared here}} #if __cplusplus >= 201402L constexpr NonLit() : value(0) {} constexpr NonLit(int x) : value(x) {} #else - NonLit() : value(0) {} + NonLit() : value(0) {} // expected-note 0+ {{declared here}} NonLit(int x) : value(x) {} #endif NonLit(void *) : value(-1) {} @@ -82,23 +82,44 @@ const int non_global = 42; ATTR static const int &local_init = non_global; // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#if __cplusplus >= 201103L + // expected-note@-3 {{reference to 'non_global' is not a constant expression}} + // expected-note@-5 {{declared here}} +#else + // expected-note@-6 {{subexpression not valid in a constant expression}} +#endif ATTR static const int &global_init = glvalue_int; ATTR static const int &temp_init = 42; } ATTR const int &temp_ref = 42; ATTR const int &temp_ref2 = ReturnInt(); // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#if __cplusplus >= 201103L +// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}} +#else +// expected-note@-5 {{subexpression not valid in a constant expression}} +#endif ATTR const NonLit &nl_temp_ref = 42; // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#if __cplusplus >= 201103L +// expected-note@-3 {{non-literal type 'const NonLit' cannot be used in a constant expression}} +#else +// expected-note@-5 {{subexpression not valid in a constant expression}} +#endif #if __cplusplus >= 201103L ATTR const LitType &lit_temp_ref = 42; ATTR const int &subobj_ref = LitType{}.value; #endif ATTR const int &nl_subobj_ref = NonLit().value; // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#if __cplusplus >= 201103L +// expected-note-re@-3 {{non-literal type '{{.*}}' cannot be used in a constant expression}} +#else +// expected-note@-5 {{subexpression not valid in a constant expression}} +#endif struct TT1 { ATTR static const int &no_init; @@ -116,6 +137,8 @@ #if __cplusplus >= 201103L thread_local const int &TT1::tl_glvalue_init = glvalue_int; thread_local const int &TT1::tl_temp_init = 42; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{reference to temporary is not a constant expression}} +// expected
[PATCH] D24372: [libcxx] Sprinkle constexpr over compressed_pair
loladiro created this revision. loladiro added reviewers: EricWF, mclow.lists. loladiro added a subscriber: cfe-commits. loladiro set the repository for this revision to rL LLVM. Without this, unique_ptr is not constant initialized. I've added a test to that extent. Unfortunately, I believe there's additional work required for C++11, since unique_ptr uses std::forward internally which is not constexpr until C++14. Doing something about that is not part of this patch. unique_ptr not being constant initialized is particularly problematic because it is in libstdc++, so there's applications that rely on this behavior. Repository: rL LLVM https://reviews.llvm.org/D24372 Files: include/memory test/std/utilities/memory/unique.ptr/unique.ptr.runtime/unique.ptr.runtime.ctor/constinit.pass.cpp Index: test/std/utilities/memory/unique.ptr/unique.ptr.runtime/unique.ptr.runtime.ctor/constinit.pass.cpp === --- /dev/null +++ test/std/utilities/memory/unique.ptr/unique.ptr.runtime/unique.ptr.runtime.ctor/constinit.pass.cpp @@ -0,0 +1,23 @@ +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11 + +#include +#include + +#ifndef _LIBCPP_SAFE_STATIC +#define _LIBCPP_SAFE_STATIC +#endif + +_LIBCPP_SAFE_STATIC static std::unique_ptr a; + +int main() { +assert(a == nullptr); +} Index: include/memory === --- include/memory +++ include/memory @@ -2096,24 +2096,28 @@ typedef const typename remove_reference<_T1>::type& _T1_const_reference; typedef const typename remove_reference<_T2>::type& _T2_const_reference; -_LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp() : __first_(), __second_() {} -_LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T1_param __t1) +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +__libcpp_compressed_pair_imp() : __first_(), __second_() {} +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +explicit __libcpp_compressed_pair_imp(_T1_param __t1) : __first_(_VSTD::forward<_T1_param>(__t1)), __second_() {} -_LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T2_param __t2) +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +explicit __libcpp_compressed_pair_imp(_T2_param __t2) : __first_(), __second_(_VSTD::forward<_T2_param>(__t2)) {} -_LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2) +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +__libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2) : __first_(_VSTD::forward<_T1_param>(__t1)), __second_(_VSTD::forward<_T2_param>(__t2)) {} #if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_T1>::value && is_nothrow_copy_constructible<_T2>::value) : __first_(__p.first()), __second_(__p.second()) {} -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __libcpp_compressed_pair_imp& operator=(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_assignable<_T1>::value && is_nothrow_copy_assignable<_T2>::value) @@ -2123,14 +2127,14 @@ return *this; } -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && is_nothrow_move_constructible<_T2>::value) : __first_(_VSTD::forward<_T1>(__p.first())), __second_(_VSTD::forward<_T2>(__p.second())) {} -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __libcpp_compressed_pair_imp& operator=(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_assignable<_T1>::value && is_nothrow_move_assignable<_T2>::value) @@ -2145,7 +2149,7 @@ #ifndef _LIBCPP_HAS_NO_VARIADICS template -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __libcpp_compressed_pair_imp(piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args, @@ -2189,23 +2193,27 @@ typedef const _T1&_T1_co
Re: [PATCH] D24371: Add diagnostics to require_constant_initialization
loladiro added inline comments. Comment at: lib/Sema/SemaDecl.cpp:10535-10538 @@ -10534,1 +10534,6 @@ << attr->getRange(); +APValue Value; +SmallVector Notes; +cast(var->ensureEvaluatedStmt()->Value)->EvaluateAsInitializer( + Value, getASTContext(), var, Notes); +for (auto &it : Notes) rsmith wrote: > Can you capture the diagnostics from `checkInitIsICE` instead of recomputing > them here? (It looks straightforward to add an overload that takes a vector > of notes.) In the non-C++11 case, you can produce a note pointing to > `CacheCulprit` instead. The problem is that the result of checking is cached internally and the diagnostics are only produced the first time. I don't think it's necessarily guaranteed that the above `checkInitIsICE` is the first such call (unless you can see such a reason). Repository: rL LLVM https://reviews.llvm.org/D24371 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24371: Add diagnostics to require_constant_initialization
loladiro updated this revision to Diff 70915. loladiro added a comment. Address review comments: - Disable C++11 test that lacks source locations - Use CacheCulprit to give diagnostics for < C++11 Repository: rL LLVM https://reviews.llvm.org/D24371 Files: lib/Sema/SemaDecl.cpp test/SemaCXX/attr-require-constant-initialization.cpp Index: test/SemaCXX/attr-require-constant-initialization.cpp === --- test/SemaCXX/attr-require-constant-initialization.cpp +++ test/SemaCXX/attr-require-constant-initialization.cpp @@ -7,9 +7,9 @@ #define ATTR __attribute__((require_constant_initialization)) // expected-note 0+ {{expanded from macro}} -int ReturnInt(); +int ReturnInt(); // expected-note 0+ {{declared here}} -struct PODType { +struct PODType { // expected-note 0+ {{declared here}} int value; int value2; }; @@ -20,20 +20,20 @@ struct LitType { constexpr LitType() : value(0) {} constexpr LitType(int x) : value(x) {} - LitType(void *) : value(-1) {} + LitType(void *) : value(-1) {} // expected-note 0+ {{declared here}} int value; }; #endif -struct NonLit { +struct NonLit { // expected-note 0+ {{declared here}} #if __cplusplus >= 201402L constexpr NonLit() : value(0) {} constexpr NonLit(int x) : value(x) {} #else - NonLit() : value(0) {} + NonLit() : value(0) {} // expected-note 0+ {{declared here}} NonLit(int x) : value(x) {} #endif - NonLit(void *) : value(-1) {} + NonLit(void *) : value(-1) {} // expected-note 0+ {{declared here}} ~NonLit() {} int value; }; @@ -82,23 +82,44 @@ const int non_global = 42; ATTR static const int &local_init = non_global; // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#if __cplusplus >= 201103L +// expected-note@-3 {{reference to 'non_global' is not a constant expression}} +// expected-note@-5 {{declared here}} +#else +// expected-note@-6 {{subexpression not valid in a constant expression}} +#endif ATTR static const int &global_init = glvalue_int; ATTR static const int &temp_init = 42; } ATTR const int &temp_ref = 42; ATTR const int &temp_ref2 = ReturnInt(); // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#if __cplusplus >= 201103L +// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}} +#else +// expected-note@-5 {{subexpression not valid in a constant expression}} +#endif ATTR const NonLit &nl_temp_ref = 42; // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#if __cplusplus >= 201103L +// expected-note@-3 {{non-literal type 'const NonLit' cannot be used in a constant expression}} +#else +// expected-note@-5 {{subexpression not valid in a constant expression}} +#endif #if __cplusplus >= 201103L ATTR const LitType &lit_temp_ref = 42; ATTR const int &subobj_ref = LitType{}.value; #endif ATTR const int &nl_subobj_ref = NonLit().value; // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#if __cplusplus >= 201103L +// expected-note-re@-3 {{non-literal type '{{.*}}' cannot be used in a constant expression}} +#else +// expected-note@-5 {{subexpression not valid in a constant expression}} +#endif struct TT1 { ATTR static const int &no_init; @@ -116,6 +137,8 @@ #if __cplusplus >= 201103L thread_local const int &TT1::tl_glvalue_init = glvalue_int; thread_local const int &TT1::tl_temp_init = 42; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{reference to temporary is not a constant expression}} +// expected-note@-2 {{temporary created here}} #endif // [basic.start.static]p2.2 @@ -129,17 +152,25 @@ #else ATTR static PODType pod; // expected-error {{variable does not have a constant initializer}} // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +// expected-note@-2 {{non-constexpr constructor 'PODType' cannot be used in a constant expression}} #endif ATTR static PODType pot2 = {ReturnInt()}; // expected-error {{variable does not have a constant initializer}} -// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#if __cplusplus >= 201103L +// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}} +#else +// expected-note@-5 {{subexpression not valid in a constant expression}} +#endif #if __cplusplus >= 201103L constexpr LitType l; ATTR static LitType static_lit = l; ATTR static LitType static_lit
Re: [PATCH] D24372: [libcxx] Sprinkle constexpr over compressed_pair
loladiro added a comment. Small bump here. Is it possible to rewrite these without std::forward, so we can have the const-initialization behavior on C++11 (or is there are different solution?). Repository: rL LLVM https://reviews.llvm.org/D24372 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24372: [libcxx] Sprinkle constexpr over compressed_pair
loladiro added inline comments. Comment at: include/memory:2137 @@ -2132,3 +2136,3 @@ -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __libcpp_compressed_pair_imp& operator=(__libcpp_compressed_pair_imp&& __p) mclow.lists wrote: > loladiro wrote: > > mclow.lists wrote: > > > Have you tested this on C++11? > > > I suspect that some of these need to be `_LIBCPP_CONSTEXPR_AFTER_CXX11` > > Well, as I mentioned there are other problems on C++11, namely forward not > > being constexpr (so even the simple constructors below can't be constant > > initialized in C++11). I would REALLY like for unique_ptr to be constant > > initialized even in C++11 mode. I feel like arguably the standard requires > > it by marking the constructor `constexpr`. > One way to deal with that is to define a call `__forward()` that is the same > as `forward()` except that it's constexpr in C++11, and have compressed_pair > call that. > I was worried that something in the definition of forward required C++14 constexpr semantics? Is that not the case. If so this sounds like a good solution, and I can update the patch accordingly. Repository: rL LLVM https://reviews.llvm.org/D24372 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D24372: [libcxx] Sprinkle constexpr over compressed_pair
loladiro updated this revision to Diff 71528. loladiro added a comment. Add private copy of forward (__forward) that is constexpr even in C++11 mode, use test suggested by @rsmith Repository: rL LLVM https://reviews.llvm.org/D24372 Files: include/memory test/std/utilities/memory/unique.ptr/unique.ptr.runtime/unique.ptr.runtime.ctor/constinit.pass.cpp Index: test/std/utilities/memory/unique.ptr/unique.ptr.runtime/unique.ptr.runtime.ctor/constinit.pass.cpp === --- /dev/null +++ test/std/utilities/memory/unique.ptr/unique.ptr.runtime/unique.ptr.runtime.ctor/constinit.pass.cpp @@ -0,0 +1,36 @@ +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03 + +#include +#include + +#ifndef _LIBCPP_SAFE_STATIC +#define _LIBCPP_SAFE_STATIC +#endif + +extern std::unique_ptr a; +extern std::unique_ptr b; +void *tramplea = std::memset(&a, 0xab, sizeof(a)); +void *trampleb = std::memset(&b, 0xab, sizeof(b)); +_LIBCPP_SAFE_STATIC std::unique_ptr a; +_LIBCPP_SAFE_STATIC std::unique_ptr b(nullptr); + +int main() { +// Check that the initialization of 'a' was performed before the initialization of 'tramplea'. +for (size_t n = 0; n != sizeof(a); ++n) + assert(reinterpret_cast(tramplea)[n] == 0xab); +// Check that the initialization of 'b' was performed before the initialization of 'trampleb'. +for (size_t n = 0; n != sizeof(b); ++n) + assert(reinterpret_cast(trampleb)[n] == 0xab); +// Put a unique_ptr object back so that the global dtor is valid. +new (&a) std::unique_ptr; +new (&b) std::unique_ptr; +} Index: include/memory === --- include/memory +++ include/memory @@ -2053,6 +2053,26 @@ typedef void element_type; }; +// Private copy of forward, for use only in this file, which is constexpr even +// in C++11 +template +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +_Tp&& +__forward(typename remove_reference<_Tp>::type& __t) _NOEXCEPT +{ +return static_cast<_Tp&&>(__t); +} + +template +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +_Tp&& +__forward(typename remove_reference<_Tp>::type&& __t) _NOEXCEPT +{ +static_assert(!is_lvalue_reference<_Tp>::value, + "Can not forward an rvalue as an lvalue."); +return static_cast<_Tp&&>(__t); +} + template ::type, typename remove_cv<_T2>::type>::value, bool = is_empty<_T1>::value @@ -2096,24 +2116,28 @@ typedef const typename remove_reference<_T1>::type& _T1_const_reference; typedef const typename remove_reference<_T2>::type& _T2_const_reference; -_LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp() : __first_(), __second_() {} -_LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T1_param __t1) -: __first_(_VSTD::forward<_T1_param>(__t1)), __second_() {} -_LIBCPP_INLINE_VISIBILITY explicit __libcpp_compressed_pair_imp(_T2_param __t2) -: __first_(), __second_(_VSTD::forward<_T2_param>(__t2)) {} -_LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2) -: __first_(_VSTD::forward<_T1_param>(__t1)), __second_(_VSTD::forward<_T2_param>(__t2)) {} +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +__libcpp_compressed_pair_imp() : __first_(), __second_() {} +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +explicit __libcpp_compressed_pair_imp(_T1_param __t1) +: __first_(__forward<_T1_param>(__t1)), __second_() {} +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +explicit __libcpp_compressed_pair_imp(_T2_param __t2) +: __first_(), __second_(__forward<_T2_param>(__t2)) {} +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +__libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2) +: __first_(__forward<_T1_param>(__t1)), __second_(__forward<_T2_param>(__t2)) {} #if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_T1>::value && is_nothrow_copy_constructible<_T2>::value) : __first_(__p.first()), __second_(__p.second()) {} -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __libcpp_compressed_pair_imp& operator=(const __libcpp_compressed_pair_imp& __p) _NOEXCEPT_(is_nothrow_copy_assignable<_T1
[PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added a comment. I came across a situation again where this would be useful to have. I know this was approved, but looking it looks like I wanted @majnemer to have another look. https://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D13419: Fix several problems at the intersection of template instantiations and visibility
loladiro added a comment. Since this was approved, I'll rebase and commit. Repository: rL LLVM https://reviews.llvm.org/D13419 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D24372: [libcxx] Sprinkle constexpr over compressed_pair
loladiro added a comment. Ok then, will commit. Repository: rL LLVM https://reviews.llvm.org/D24372 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D13419: Fix several problems at the intersection of template instantiations and visibility
loladiro updated this revision to Diff 76094. loladiro added a comment. Rebased patch Repository: rL LLVM https://reviews.llvm.org/D13419 Files: lib/AST/Decl.cpp lib/AST/DeclCXX.cpp test/CodeGenCXX/visibility.cpp Index: test/CodeGenCXX/visibility.cpp === --- test/CodeGenCXX/visibility.cpp +++ test/CodeGenCXX/visibility.cpp @@ -1317,3 +1317,59 @@ // CHECK-LABEL: define void @_ZN6test693foo1fEv // CHECK-HIDDEN-LABEL: define hidden void @_ZN6test693foo1fEv } + +namespace test70 { +template +class foo { +public: + T x; + template + HIDDEN S AddS(S); + template + class HIDDEN barS { + public: +static S AddS2(foo x, S); + }; + template + class HIDDEN barZ { + public: +template +static S AddSZ(foo x, S, Z); + }; +}; + +// CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4AddSIxEET_S3_ +// CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4AddSIxEET_S3_ +template +template +HIDDEN S foo::AddS(S y) { + return ((S)x) + y; +} + +// CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x +// CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x +template +template +HIDDEN S foo::barS::AddS2(foo x, S y) { + return ((S)x.x) + y; +} + +// CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_ +// CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_ +template +template +template +HIDDEN S foo::barZ::AddSZ(foo x, S y, Z z) { + return ((S)x.x) + y + ((S)z); +} + +extern template struct foo; +template struct foo; + +void f() { + auto var = foo{5}; + auto bar = var.AddS((long long)3); + auto bar2 = decltype(var)::barS::AddS2(var, 3); + auto bar3 = decltype(var)::barZ::AddSZ(var, 3, (char)0); +} +} Index: lib/AST/DeclCXX.cpp === --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1346,17 +1346,19 @@ if (auto *TD = dyn_cast(this)) { auto From = TD->getInstantiatedFrom(); if (auto *CTD = From.dyn_cast()) { - while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { -if (NewCTD->isMemberSpecialization()) + while (!CTD->isMemberSpecialization()) { +auto *NewCTD = CTD->getInstantiatedFromMemberTemplate(); +if (!NewCTD) break; CTD = NewCTD; } return CTD->getTemplatedDecl()->getDefinition(); } if (auto *CTPSD = From.dyn_cast()) { - while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { -if (NewCTPSD->isMemberSpecialization()) + while (!CTPSD->isMemberSpecialization()) { +auto *NewCTPSD = CTPSD->getInstantiatedFromMember(); +if (!NewCTPSD) break; CTPSD = NewCTPSD; } Index: lib/AST/Decl.cpp === --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1052,7 +1052,10 @@ // If this is a member class of a specialization of a class template // and the corresponding decl has explicit visibility, use that. if (const auto *RD = dyn_cast(ND)) { -CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); +const CXXRecordDecl *InstantiatedFrom = +RD->getTemplateInstantiationPattern(); +if (!InstantiatedFrom) + InstantiatedFrom = RD->getInstantiatedFromMemberClass(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); } @@ -1086,16 +1089,13 @@ } // Also handle function template specializations. if (const auto *fn = dyn_cast(ND)) { -// If the function is a specialization of a template with an -// explicit visibility attribute, use that. -if (FunctionTemplateSpecializationInfo *templateInfo - = fn->getTemplateSpecializationInfo()) - return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(), - kind); +// If the function is a template specialization or a member of +// a specialized class template and the corresponding decl has +// explicit visibility, use that. +FunctionDecl *InstantiatedFrom = fn->getTemplateInstantiationPattern(); +if (!InstantiatedFrom) + InstantiatedFrom = fn->getInstantiatedFromMemberFunction(); -// If the function is a member of a specialization of a class template -// and the corresponding decl has explicit visibility, use that. -FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D13419: Fix several problems at the intersection of template instantiations and visibility
loladiro added a comment. Hmm, the rebased version of this introduces new errors in `test/Modules/cxx-templates.cpp`. That test didn't exist when I wrote this code and I'm not familiar with templates. @rsmith could you take a look, error is: error: 'error' diagnostics seen but not expected: File /data/keno/llvm/tools/clang/test/Modules/cxx-templates.cpp Line 202: definition of 'nested_cls_t' must be imported from module 'cxx_templates_common.unimported' before it is required File /data/keno/llvm/tools/clang/test/Modules/cxx-templates.cpp Line 202: definition of 'nested_cls_t' must be imported from module 'cxx_templates_common.unimported' before it is required Repository: rL LLVM https://reviews.llvm.org/D13419 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro set the repository for this revision to rL LLVM. loladiro updated this revision to Diff 76102. loladiro added a comment. Rebased on current master. Repository: rL LLVM https://reviews.llvm.org/D13330 Files: include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h include/clang/Sema/Sema.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2662,6 +2662,8 @@ case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction"; +case Func | Class: + return "ExpectedFunctionOrClass"; // If not compiling for C++, the class portion does not apply. case Func | Var | Class: Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,48 @@ +// RUN: %clang -cc1 -std=c++14 -fsyntax-only -verify %s + +// Correct usage +template +struct foo {}; +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +template +T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)) float pi; +template __attribute__((unique_instantiation)) float pi; + +// Usages on non-templates +float __attribute__((unique_instantiation)) notpi(2.71828182845904523536028747135); // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +struct __attribute__((unique_instantiation)) bar {};// expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +void __attribute__((unique_instantiation)) func() {}// expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +// Usages that violate one of the conditions required conditions +template +struct foo1 {}; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +T pi1 = T(3.1415926535897932385); +template __attribute__((unique_instantiation)) float pi1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +struct foo2 {}; +extern template struct foo2;// expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo3 {}; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +template +struct foo5 {}; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo6 {}; +extern template struct __attribute__((unique_instantiation(16))) foo6; // expected-error{{'unique_instantiation' attribute takes no arguments}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,74 @@ +// RUN: %clang -std=c++14 -emit-llvm -c -S -o - %s | FileCheck %s + +// CHECK: @_Z2piIfE = global float +// CHECK-NOT: @_Z2piIfE = weak_odr global float +template +T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)) float pi; +template __attribute__((unique_instantiation)) f
[PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added a comment. I found a bug in this which I need to fix, but while I'm at it, in doing more testing on this, I came across the following corner case: template struct static_separate_template { typedef T element; static T *a_static_field; }; extern template struct __attribute__((unique_instantiation)) static_separate_template; template struct __attribute__((unique_instantiation)) static_separate_template; extern template struct __attribute__((unique_instantiation)) static_separate_template; template struct __attribute__((unique_instantiation)) static_separate_template; template typename static_separate_template::element *static_separate_template::a_static_field = nullptr; template int * __attribute__((unique_instantiation)) static_separate_template::a_static_field; template char * static_separate_template::a_static_field; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} How should this be handled? I indicated my inclination in the comment, but I'm open to alternative suggestions. Repository: rL LLVM https://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added a comment. I meant `template __attribute__((unique_instantiation)) int * static_separate_template::a_static_field;` of course, though we probably need a better diagnostic for the other spelling (which applies the attribute to the static_separate_template). I'll look into adding a diagnostic. Repository: rL LLVM https://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro updated this revision to Diff 76256. loladiro added a comment. Fix for the corner case I found and add it as a test. Repository: rL LLVM https://reviews.llvm.org/D13330 Files: include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h include/clang/Sema/Sema.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2662,6 +2662,8 @@ case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction"; +case Func | Class: + return "ExpectedFunctionOrClass"; // If not compiling for C++, the class portion does not apply. case Func | Var | Class: Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,62 @@ +// RUN: %clang -cc1 -std=c++14 -fsyntax-only -verify %s + +// Correct usage +template +struct foo {}; +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +template +T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)) float pi; +template __attribute__((unique_instantiation)) float pi; + +// Usages on non-templates +float __attribute__((unique_instantiation)) notpi(2.71828182845904523536028747135); // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +struct __attribute__((unique_instantiation)) bar {};// expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +void __attribute__((unique_instantiation)) func() {}// expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +// Usages that violate one of the conditions required conditions +template +struct foo1 {}; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +T pi1 = T(3.1415926535897932385); +template __attribute__((unique_instantiation)) float pi1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +struct foo2 {}; +extern template struct foo2;// expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo3 {}; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +template +struct foo5 {}; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo6 {}; +extern template struct __attribute__((unique_instantiation(16))) foo6; // expected-error{{'unique_instantiation' attribute takes no arguments}} + +template +struct static_separate_template { +typedef T element; +static T *a_static_field; +}; +extern template struct __attribute__((unique_instantiation)) static_separate_template; +template struct __attribute__((unique_instantiation)) static_separate_template; +extern template struct __attribute__((unique_instantiation)) static_separate_template; // expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) static_separate_template; + +template typename static_se
[PATCH] D13419: Fix several problems at the intersection of template instantiations and visibility
loladiro updated this revision to Diff 76257. loladiro added a comment. Add the expected-error annotation Repository: rL LLVM https://reviews.llvm.org/D13419 Files: lib/AST/Decl.cpp lib/AST/DeclCXX.cpp test/CodeGenCXX/visibility.cpp test/Modules/cxx-templates.cpp Index: test/Modules/cxx-templates.cpp === --- test/Modules/cxx-templates.cpp +++ test/Modules/cxx-templates.cpp @@ -199,7 +199,7 @@ cls uk4; // expected-error 1+{{partial specialization of 'cls' must be imported}} expected-error 1+{{definition of}} cls::nested_cls unk1; // expected-error 1+{{explicit specialization of 'nested_cls' must be imported}} expected-error 1+{{definition of}} cls::nested_cls_t unk2; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}} -cls::nested_cls_t unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} +cls::nested_cls_t unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}} // For enums, uses that would trigger instantiations of definitions are not // allowed. Index: test/CodeGenCXX/visibility.cpp === --- test/CodeGenCXX/visibility.cpp +++ test/CodeGenCXX/visibility.cpp @@ -1317,3 +1317,59 @@ // CHECK-LABEL: define void @_ZN6test693foo1fEv // CHECK-HIDDEN-LABEL: define hidden void @_ZN6test693foo1fEv } + +namespace test70 { +template +class foo { +public: + T x; + template + HIDDEN S AddS(S); + template + class HIDDEN barS { + public: +static S AddS2(foo x, S); + }; + template + class HIDDEN barZ { + public: +template +static S AddSZ(foo x, S, Z); + }; +}; + +// CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4AddSIxEET_S3_ +// CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4AddSIxEET_S3_ +template +template +HIDDEN S foo::AddS(S y) { + return ((S)x) + y; +} + +// CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x +// CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x +template +template +HIDDEN S foo::barS::AddS2(foo x, S y) { + return ((S)x.x) + y; +} + +// CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_ +// CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_ +template +template +template +HIDDEN S foo::barZ::AddSZ(foo x, S y, Z z) { + return ((S)x.x) + y + ((S)z); +} + +extern template struct foo; +template struct foo; + +void f() { + auto var = foo{5}; + auto bar = var.AddS((long long)3); + auto bar2 = decltype(var)::barS::AddS2(var, 3); + auto bar3 = decltype(var)::barZ::AddSZ(var, 3, (char)0); +} +} Index: lib/AST/DeclCXX.cpp === --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1346,17 +1346,19 @@ if (auto *TD = dyn_cast(this)) { auto From = TD->getInstantiatedFrom(); if (auto *CTD = From.dyn_cast()) { - while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { -if (NewCTD->isMemberSpecialization()) + while (!CTD->isMemberSpecialization()) { +auto *NewCTD = CTD->getInstantiatedFromMemberTemplate(); +if (!NewCTD) break; CTD = NewCTD; } return CTD->getTemplatedDecl()->getDefinition(); } if (auto *CTPSD = From.dyn_cast()) { - while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { -if (NewCTPSD->isMemberSpecialization()) + while (!CTPSD->isMemberSpecialization()) { +auto *NewCTPSD = CTPSD->getInstantiatedFromMember(); +if (!NewCTPSD) break; CTPSD = NewCTPSD; } Index: lib/AST/Decl.cpp === --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1052,7 +1052,10 @@ // If this is a member class of a specialization of a class template // and the corresponding decl has explicit visibility, use that. if (const auto *RD = dyn_cast(ND)) { -CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); +const CXXRecordDecl *InstantiatedFrom = +RD->getTemplateInstantiationPattern(); +if (!InstantiatedFrom) + InstantiatedFrom = RD->getInstantiatedFromMemberClass(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); } @@ -1086,16 +1089,13 @@ } // Also handle function template specializations. if (const auto *fn = dyn_cast(ND)) { -// If the function is a specialization of a template with an -// explicit visibility attribute, use that. -if (FunctionTemplateSpecializationInfo *templateInfo - = fn->getTemplateSpecializationInfo()) - return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(), -
[PATCH] D13419: Fix several problems at the intersection of template instantiations and visibility
loladiro added inline comments. Comment at: lib/AST/DeclCXX.cpp:1349-1354 + while (!CTD->isMemberSpecialization()) { +auto *NewCTD = CTD->getInstantiatedFromMemberTemplate(); +if (!NewCTD) break; CTD = NewCTD; } rsmith wrote: > The same bug exists in `VarDecl::getTemplateInstantiationPattern`; can you > fix it there too? Do you have a test case that shows a problem with the current definition of that function? Would like to include it if possible. I tried cooking one up, but wasn't particularly successful. Repository: rL LLVM https://reviews.llvm.org/D13419 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro planned changes to this revision. loladiro added a comment. Thanks for the review! Sorry, it's been a while since I wrote this code, so I'm not fluent in all the details, but I've replied below. I am not particularly partial to the name, so whatever you feel is best is ok with me. Comment at: include/clang/Basic/AttrDocs.td:2321-2323 +When the unique_instantiation attribute is specified on an explicit template +instantiation, the compiler is given license to emit strong symbols for +this specific explicit template instantiation. rsmith wrote: > The primary description of the attribute should specify what it means, not > the consequences of that meaning. In this case, the meaning is that the > programmer is guaranteeing to the compiler that an explicit instantiation > precedes all implicit instantiations, and the consequence is that we can use > strong symbols. Ok, sounds good. Comment at: include/clang/Basic/DiagnosticSemaKinds.td:2456 +def err_unique_instantiation_not_previous : Error< + "'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation">; rsmith wrote: > loladiro wrote: > > aaron.ballman wrote: > > > > They are checking for two different conditions in the spec. One > > > > requires that all explicit template instantiations with this attribute > > > > have a declaration, the other that every declaration/definition has the > > > > attribute. > > > > > > Okay, I see now what this diagnostic is attempting to convey. I think it > > > should read: > > > ``` > > > def err_unique_instantiation_no_declaration : Error< > > > "'unique_instantiation' attribute on an explicit instantiation requires > > > a previous explicit instantiation declaration">; > > > ``` > > Sounds good. > This seems like an unnecessarily-strict rule to me. I don't see a reason to > disallow: > ``` > // in header > extern template struct __attribute__((whatever_its_called)) X; > ``` > ``` > // in source file > template struct X; > ``` > There doesn't appear to be any safety or correctness concern here. In > general, it seems like the attribute is only promising that the explicit > instantiation declaration precedes any other instantiation, so the only > necessary rule would seem to be: if the attribute is present on any explicit > instantiation, the first point of instantiation must be an explicit > instantiation declaration that has the attribute. While I didn't write the rules (just implemented them from the original proposal), I like the requirement from the point of view of making sure that the explicit instantiation declaration doesn't accidentally get deleted. Those declarations are somewhat odd in that they can be deleted without any semantic loss in functionality (just larger code size/more work for the linker) in the absence of this attribute. However, with this attribute, deleting the declaration would cause a subtle, perhaps hard to track down semantic change, so I like requiring people to be explicit. Comment at: lib/Sema/SemaDecl.cpp:2398-2399 + // template declarations. In clang getDefinition() will get the + // ClassTemplateSpecializationDecl associated with the class template + // declaration, so we'd give incorrect warnings here. + if (auto *CTSD = dyn_cast(New)) { rsmith wrote: > I have no idea what you mean by this. Did you mean "associated with the > explicit instantiation declaration" or something like that? Yes, I believe that is what I meant. It's been a while since I wrote this code, but I believe that all I'm trying to say here is that explicit instantiation declarations/definitions are allowed to add attributes after a definition, even though that is not normally allowed. Comment at: lib/Sema/SemaDeclAttr.cpp:5400 + if (!CTSD->getPreviousDecl()) +S.Diag(Attr.getLoc(), diag::err_unique_instantiation_no_declaration); +} rsmith wrote: > Why is this rule only applied to explicit instantiations of class templates, > and not to function or variable templates? I don't remember precisely, but I believe (at least when I wrote the patch) that those prior explicit instantiation declarations did not leave an AST node that I could check for. Comment at: lib/Sema/SemaDeclCXX.cpp:5666-5685 +/// \brief Check if the new class needs a unique instantiation attribute +/// based on whether its containing function or class has it +void Sema::checkClassLevelUniqueInstantiation(CXXRecordDecl *Record) { + Decl *D = Record; + if (!D || D->hasAttr()) +return; + while (DeclContext *DC = D ? D->getDeclContext() : nullptr) { rsmith wrote: > I don't think this is the right way to handle this case. Note that an > explicit instantiation declaration/definition for a class is only an explicit > instantiation of those m
[PATCH] D13419: Fix several problems at the intersection of template instantiations and visibility
loladiro added a comment. I'm really out of my depth in this code, but it looks like that test case is triggering the one code path in that function that is actually correct. Could you adjust it to trigger the code path behind the first if statement? Repository: rL LLVM https://reviews.llvm.org/D13419 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D12854: [SourceManager] Support buffers that are not null-terminated
loladiro created this revision. loladiro added a reviewer: bkramer. loladiro added a subscriber: cfe-commits. loladiro set the repository for this revision to rL LLVM. I feed custom buffers to clang, and since the buffers store an explicit length, I did not think to null-terminate them. However, this causes clang to run out-of-bounds in certain situations in `ComputeLineNumbers`. Since under certain situations `ComputeLineNumbers` does look at the given bounds, I figured the proper solution was to always check the buffer for EOF. Please let me know if I missed something and this was intended. Repository: rL LLVM http://reviews.llvm.org/D12854 Files: lib/Basic/SourceManager.cpp Index: lib/Basic/SourceManager.cpp === --- lib/Basic/SourceManager.cpp +++ lib/Basic/SourceManager.cpp @@ -1227,7 +1227,7 @@ // First fix up the alignment to 16 bytes. while (((uintptr_t)NextBuf & 0xF) != 0) { - if (*NextBuf == '\n' || *NextBuf == '\r' || *NextBuf == '\0') + if (*NextBuf == '\n' || *NextBuf == '\r' || *NextBuf == '\0' || NextBuf == End) goto FoundSpecialChar; ++NextBuf; } @@ -1248,24 +1248,25 @@ } #endif -while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0') +while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0' && NextBuf == End) ++NextBuf; #ifdef __SSE2__ FoundSpecialChar: #endif Offs += NextBuf-Buf; Buf = NextBuf; +// If end of file, exit. +if (Buf == End) break; + if (Buf[0] == '\n' || Buf[0] == '\r') { // If this is \n\r or \r\n, skip both characters. if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1]) ++Offs, ++Buf; ++Offs, ++Buf; LineOffsets.push_back(Offs); } else { - // Otherwise, this is a null. If end of file, exit. - if (Buf == End) break; // Otherwise, skip the null. ++Offs, ++Buf; } Index: lib/Basic/SourceManager.cpp === --- lib/Basic/SourceManager.cpp +++ lib/Basic/SourceManager.cpp @@ -1227,7 +1227,7 @@ // First fix up the alignment to 16 bytes. while (((uintptr_t)NextBuf & 0xF) != 0) { - if (*NextBuf == '\n' || *NextBuf == '\r' || *NextBuf == '\0') + if (*NextBuf == '\n' || *NextBuf == '\r' || *NextBuf == '\0' || NextBuf == End) goto FoundSpecialChar; ++NextBuf; } @@ -1248,24 +1248,25 @@ } #endif -while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0') +while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0' && NextBuf == End) ++NextBuf; #ifdef __SSE2__ FoundSpecialChar: #endif Offs += NextBuf-Buf; Buf = NextBuf; +// If end of file, exit. +if (Buf == End) break; + if (Buf[0] == '\n' || Buf[0] == '\r') { // If this is \n\r or \r\n, skip both characters. if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1]) ++Offs, ++Buf; ++Offs, ++Buf; LineOffsets.push_back(Offs); } else { - // Otherwise, this is a null. If end of file, exit. - if (Buf == End) break; // Otherwise, skip the null. ++Offs, ++Buf; } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro created this revision. loladiro added a reviewer: doug.gregor. loladiro added a subscriber: cfe-commits. loladiro set the repository for this revision to rL LLVM. This implements a proposal by Doug Gregor on cfe-dev a couple of years ago, to allow the compiler to emit strong symbols for explicit template instantiations. Doug's spec, which I have tried to follow can be found here: http://lists.llvm.org/pipermail/cfe-dev/attachments/20111203/5e1c6c35/attachment.html. I usually work over in LLVM-land and have only contributed the occasional bug fix to clang, so please let me know how this patch can be improved. I'm also not fully done testing it yet (only did so on the toy example I included as a test case), but I wanted to get this out there to get feedback. Repository: rL LLVM http://reviews.llvm.org/D13330 Files: include/clang/Basic/Attr.td include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ASTContext.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,22 @@ +// RUN: %clang -cc1 -std=c++11 -fsyntax-only -verify %s + +template < typename T > struct foo1 { }; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{requires a previous declaration}} + +template < typename T > struct foo2 { }; +extern template struct foo2; // expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{must be specified on all declarations}} + +template < typename T > struct foo3 { }; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{must be specified on all declarations}} + +template < typename T > struct __attribute__((unique_instantiation)) foo4 { }; // expected-error{{not a explicit template declaration}} + +template < typename T > struct foo5 { }; +extern template struct foo5; // expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo5; // expected-error{{must be specified on all declarations}} + +template < typename T > struct foo6 { }; +extern template struct __attribute__((unique_instantiation)) foo6; // expected-note{{previous explicit instantiation is here}} +template struct foo6; // expected-error{{must be specified on all declarations}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,15 @@ +// RUN: %clang -std=c++11 -emit-llvm -O0 -c -S -o - %s | FileCheck %s + +template < typename T > struct foo { +T x; +T getX() { return x; } +}; +// CHECK: define i32 @_ZN3fooIiE4getXEv +// CHECK-NOT: define weak_odr i32 @_ZN3fooIiE4getXEv +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +int footest() { +auto var = foo{5}; +return var.getX(); +} Index: lib/Sema/SemaTemplate.cpp === --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7321,20 +7321,25 @@ Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); Specialization->setRBraceLoc(SourceLocation()); + Specialization->setTemplateSpecializationKind(TSK); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + if (PrevDecl && PrevDecl->hasAttr() && + !Specialization->hasAttr()) { +Diag(Specialization->getLocStart(),diag::err_unique_instantiation_not_previous); +Diag(PrevDecl->getLocStart(),diag::note_previous_explicit_instantiation); + } + // Add the explicit instantiation into its lexical context. However, // since explicit instantiations are never found by name lookup, we // just put it into the declaration context directly. Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Specialization); // Syntax is now OK, so return if it has no other effect on semantics. if (HasNoEffect) { -// Set the template specialization kind. -Specialization->setTemplateSpecializationKind(TSK); return Specialization; } @@ -7388,14 +7393,7 @@ } } -// Set the template specialization kind. Make sure it is set before -// instantiating the members which will trigger ASTConsumer callbacks. -Specialization->setTemplateSpecializationKind(TSK); InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); - } else { - -// Set the template specialization kind. -Specialization->setTemplateSpecializationKind(TSK); } return
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added a comment. Thanks for the quick review. Comment at: include/clang/Basic/Attr.td:1462 @@ +1461,3 @@ +def UniqueInstantiation : InheritableAttr { + let Spellings = [GCC<"unique_instantiation">]; + let Subjects = SubjectList<[CXXRecord]>; aaron.ballman wrote: > This is not a GCC attribute, so it should not be spelled as such. Since this > only applies to C++ code, I would recommend a C++11 spelling (in the clang > namespace). If you think this is something C++03 and earlier code would > really benefit from, then you could also add a GNU-style spelling. No, this is C++11 only. Will change the spelling. Comment at: include/clang/Basic/Attr.td:1464 @@ +1463,3 @@ + let Subjects = SubjectList<[CXXRecord]>; + let Documentation = [Undocumented]; +} aaron.ballman wrote: > Please, no undocumented attributes. Will document. Comment at: include/clang/Basic/DiagnosticSemaKinds.td:2443 @@ -2442,1 +2442,3 @@ ":must be between 1 and %2}2">; +def err_unique_instantiation_wrong_decl : Error< + "unique_instantiation attribute on something that is not a explicit template declaration or instantiation.">; aaron.ballman wrote: > Would this make more sense as an option in warn_attribute_wrong_decl_type > instead? (there's an err_ version as well if you wish to keep this an error). > > Also, please ensure that the attribute is quoted in the diagnostic -- it > makes things less confusing for the user. Ok, so should I add an "explicit template instantiations" option to that err? Comment at: lib/AST/ASTContext.cpp:8244 @@ -8242,2 +8243,3 @@ case TSK_ExplicitInstantiationDefinition: -return GVA_StrongODR; +CTSD = dyn_cast(FD->getDeclContext()); +if (!CTSD || !CTSD->hasAttr()) aaron.ballman wrote: > I think this would be easier to read (and not have to hoist a declaration out > of the switch) as: > > ``` > if (const auto *CTSD = dyn_cast<>()) { > if (CTSD->hasAttr<>()) > return GVA_StrongExternal; > } > return GVA_StrongODR; > ``` > Ok. Comment at: lib/Sema/SemaDeclAttr.cpp:4539 @@ +4538,3 @@ +// by an ExplicitInstantiationDeclaration. +if (CTSD->getSpecializationKind() == TSK_ExplicitInstantiationDefinition) { + if (!CTSD->getPreviousDecl()) aaron.ballman wrote: > Why is this required as part of the feature design? It seems restrictive. This was part of Doug's original Spec, so I implemented it: > A unique explicit instantiation definition shall follow an explicit > instantiation declaration of the same entity. [//Note//: this > requirement encourages a programming style that uses unique explicit > instantiation declarations (typically in a header) to suppress > implicit instantiations of a template or its members, so that the > unique explicit instantiation definition of that template or its members > is unique. //- end note//] I think that makes a decent amount of sense, since you really want to avoid the case where some translation units don't see the extern template declaration. Comment at: lib/Sema/SemaDeclAttr.cpp:4546 @@ +4545,3 @@ +// have performed the same check on the previous declaration here. +CXXRecordDecl *Previous = CTSD->getPreviousDecl(); +if (Previous) { aaron.ballman wrote: > Is this something that can be handled by mergeDeclAttribute()? I'm not > certain how that interplays with templates specifically, but usually we do > this sort of logic within a Sema::mergeFooAttr() function. Hmm, I'm not sure, the goal of this is to ensure that all declarations and definitions of this extern template have the attribute set. It's not really `merging` per se. Though I suppose it could be made to fit in that framework. Repository: rL LLVM http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added inline comments. Comment at: include/clang/Basic/Attr.td:1462 @@ +1461,3 @@ +def UniqueInstantiation : InheritableAttr { + let Spellings = [GCC<"unique_instantiation">]; + let Subjects = SubjectList<[CXXRecord]>; loladiro wrote: > aaron.ballman wrote: > > This is not a GCC attribute, so it should not be spelled as such. Since > > this only applies to C++ code, I would recommend a C++11 spelling (in the > > clang namespace). If you think this is something C++03 and earlier code > > would really benefit from, then you could also add a GNU-style spelling. > No, this is C++11 only. Will change the spelling. It doesn't appear like the grammar allows attributes to be specified on explicit template definitions. I'll change the spelling to GNU: ``` error: an attribute list cannot appear here template struct foo [[clang::unique_instantiation]]; ^~~ [[clang::unique_instantiation]] error: an attribute list cannot appear here template struct [[clang::unique_instantiation]] foo; ^~~ error: an attribute list cannot appear here template [[clang::unique_instantiation]] struct foo; ^~~ error: an attribute list cannot appear here [[clang::unique_instantiation]] template struct foo; ^~~ 1 error generated. FileCheck error: '-' is empty. ``` Repository: rL LLVM http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro updated this revision to Diff 36332. loladiro added a comment. Address review comments. I had to add a special case to checkNewAttributesAfterDef if we want to use attribute merging for explicit template instantiations, because the Microsoft ABI allows adding dll attributes to the explicit template definition, but not the declaration (which clang considers to be the record's definition). Repository: rL LLVM http://reviews.llvm.org/D13330 Files: include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/AST/ASTContext.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,18 @@ +// RUN: %clang -cc1 -std=c++11 -fsyntax-only -verify %s + +template < typename T > struct foo1 { }; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{requires a previous declaration}} + +template < typename T > struct foo2 { }; +extern template struct foo2; // expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{must be specified on all declarations}} + +template < typename T > struct foo3 { }; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{must be specified on all declarations}} + +template < typename T > struct __attribute__((unique_instantiation)) foo4 { }; // expected-error{{only applies to explicit template declarations or definitions}} + +template < typename T > struct foo5 { }; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{must be specified on all declarations}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,15 @@ +// RUN: %clang -std=c++11 -emit-llvm -O0 -c -S -o - %s | FileCheck %s + +template < typename T > struct foo { +T x; +T getX() { return x; } +}; +// CHECK: define i32 @_ZN3fooIiE4getXEv +// CHECK-NOT: define weak_odr i32 @_ZN3fooIiE4getXEv +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +int footest() { +auto var = foo{5}; +return var.getX(); +} Index: lib/Sema/SemaTemplate.cpp === --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7321,20 +7321,22 @@ Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); Specialization->setRBraceLoc(SourceLocation()); + Specialization->setTemplateSpecializationKind(TSK); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + if (PrevDecl) +mergeDeclAttributes(Specialization, PrevDecl); + // Add the explicit instantiation into its lexical context. However, // since explicit instantiations are never found by name lookup, we // just put it into the declaration context directly. Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Specialization); // Syntax is now OK, so return if it has no other effect on semantics. if (HasNoEffect) { -// Set the template specialization kind. -Specialization->setTemplateSpecializationKind(TSK); return Specialization; } @@ -7388,14 +7390,7 @@ } } -// Set the template specialization kind. Make sure it is set before -// instantiating the members which will trigger ASTConsumer callbacks. -Specialization->setTemplateSpecializationKind(TSK); InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); - } else { - -// Set the template specialization kind. -Specialization->setTemplateSpecializationKind(TSK); } return Specialization; Index: lib/Sema/SemaDeclAttr.cpp === --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -4529,6 +4529,29 @@ Attr.getAttributeSpellingListIndex())); } + +static void handleUniqueInstantiation(Sema &S, Decl *D, + const AttributeList &Attr) { + if (auto *CTSD = dyn_cast(D)) { +// If this is an explicit instantiation definition. Check that it was preceeded +// by an ExplicitInstantiationDeclaration. Note, this +// requirement encourages a programming style that uses unique explicit +// instantiation declarations
Re: [PATCH] D12854: [SourceManager] Support buffers that are not null-terminated
loladiro added a comment. Bump. Could somebody take a look at this? Repository: rL LLVM http://reviews.llvm.org/D12854 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D12854: [SourceManager] Support buffers that are not null-terminated
loladiro added a comment. Hmm, you're right. And I am actually constructing it in such a way that it's supposed to have it, so I wonder why it ran off the rails here. Will take another look. Repository: rL LLVM http://reviews.llvm.org/D12854 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D12854: [SourceManager] Support buffers that are not null-terminated
loladiro abandoned this revision. loladiro added a comment. Oh, I see it checks for the null terminator past the end of the given memory block on construction, but if the memory after changes later this just keeps running. Well, that's quite a trap, but I guess that's what you get for not understanding the API ;). Repository: rL LLVM http://reviews.llvm.org/D12854 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added a comment. Thoughts on allowing this attribute to be specified on the templated class itself, with the intention of never allowing any implicit instantiation? As an example, consider SymbolTableListTraits in LLVM. It can only ever be used as an explicit instantiation (because the full implementation is not available). Repository: rL LLVM http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D13419: Fix several problems at the intersection of template instantiations and visibility
loladiro created this revision. loladiro added reviewers: aaron.ballman, rsmith, rnk. loladiro added a subscriber: cfe-commits. loladiro set the repository for this revision to rL LLVM. When we were looking at a template instantiation, that itself was a template instantiation (say a templated member of a templated class), we weren't looking back far enough along the chain of instantiations to find a VisibilityAttr (which we don't copy when instantiating templates). This patch attempts to address that as well as adding a few test cases for these situations. Repository: rL LLVM http://reviews.llvm.org/D13419 Files: lib/AST/Decl.cpp lib/AST/DeclCXX.cpp test/CodeGenCXX/visibility.cpp Index: test/CodeGenCXX/visibility.cpp === --- test/CodeGenCXX/visibility.cpp +++ test/CodeGenCXX/visibility.cpp @@ -1314,3 +1314,57 @@ // CHECK-LABEL: define void @_ZN6test693foo1fEv // CHECK-HIDDEN-LABEL: define hidden void @_ZN6test693foo1fEv } + +namespace test70 { + template < typename T > class foo { + public: + T x; + template < typename S > + HIDDEN S AddS(S); + template < typename S > class HIDDEN barS { +public: + static S AddS2(foo x, S); + }; + template < typename S > class HIDDEN barZ { + public: +template < typename Z > + static S AddSZ(foo x, S, Z); + }; + }; + + // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4AddSIxEET_S3_ + // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4AddSIxEET_S3_ + template < typename T > + template < typename S > + HIDDEN S foo::AddS(S y) { + return ((S) x) + y; + } + + // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x + // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x + template < typename T > + template < typename S > + HIDDEN S foo::barS::AddS2(foo x, S y) { + return ((S) x.x) + y; + } + + // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_ + // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_ + template < typename T > + template < typename S > + template < typename Z > + HIDDEN S foo::barZ::AddSZ(foo x, S y, Z z) { + return ((S) x.x) + y + ((S) z); + } + + extern template struct foo; + template struct foo; + + void f() { + auto var = foo{5}; + auto bar = var.AddS((long long)3); + auto bar2 = decltype(var)::barS::AddS2(var,3); + auto bar3 = decltype(var)::barZ::AddSZ(var,3,(char)0); + } +} + Index: lib/AST/DeclCXX.cpp === --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1261,20 +1261,22 @@ if (auto *TD = dyn_cast(this)) { auto From = TD->getInstantiatedFrom(); if (auto *CTD = From.dyn_cast()) { - while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { + auto *NewCTD = CTD; + do { +CTD = NewCTD; if (NewCTD->isMemberSpecialization()) break; -CTD = NewCTD; - } + } while ((NewCTD = CTD->getInstantiatedFromMemberTemplate())); return CTD->getTemplatedDecl()->getDefinition(); } if (auto *CTPSD = From.dyn_cast()) { - while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { + auto *NewCTPSD = CTPSD; + do { +CTPSD = NewCTPSD; if (NewCTPSD->isMemberSpecialization()) break; -CTPSD = NewCTPSD; - } + } while ((NewCTPSD = CTPSD->getInstantiatedFromMember())); return CTPSD->getDefinition(); } } Index: lib/AST/Decl.cpp === --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1049,7 +1049,9 @@ // If this is a member class of a specialization of a class template // and the corresponding decl has explicit visibility, use that. if (const CXXRecordDecl *RD = dyn_cast(ND)) { -CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); +const CXXRecordDecl *InstantiatedFrom = RD->getTemplateInstantiationPattern(); +if (!InstantiatedFrom) + InstantiatedFrom = RD->getInstantiatedFromMemberClass(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); } @@ -1084,16 +1086,11 @@ } // Also handle function template specializations. if (const FunctionDecl *fn = dyn_cast(ND)) { -// If the function is a specialization of a template with an -// explicit visibility attribute, use that. -if (FunctionTemplateSpecializationInfo *templateInfo - = fn->getTemplateSpecializationInfo()) - return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(), - kind); - -// If the function is a member of a specialization of a class template +// If the function is a member of a specialization of a some template // and the corr
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro removed rL LLVM as the repository for this revision. loladiro updated this revision to Diff 36459. loladiro added a comment. Rebased, added support for unique_instantiation on explicit function templates and fix the case where one record is embedded in another and the outer is explicitly instantiated. Add testcases for all of these. http://reviews.llvm.org/D13330 Files: include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/AST/ASTContext.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,18 @@ +// RUN: %clang -cc1 -std=c++11 -fsyntax-only -verify %s + +template < typename T > struct foo1 { }; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{requires a previous declaration}} + +template < typename T > struct foo2 { }; +extern template struct foo2; // expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{must be specified on all declarations}} + +template < typename T > struct foo3 { }; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{must be specified on all declarations}} + +template < typename T > struct __attribute__((unique_instantiation)) foo4 { }; // expected-error{{only applies to explicit template declarations or definitions}} + +template < typename T > struct foo5 { }; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{must be specified on all declarations}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,35 @@ +// RUN: %clang -std=c++11 -emit-llvm -O0 -c -S -o - %s | FileCheck %s + +template < typename T > struct foo { +T x; +T getX() { return x; } +struct bar { +T y; +bar(T y) : y(y) {} +}; +}; +template < typename T > T bar(); + +// CHECK: define i32 @_ZN3fooIiE4getXEv +// CHECK: define void @_ZN3fooIiE3barC2Ei +// CHECK-NOT: define weak_odr i32 @_ZN3fooIiE4getXEv +// CHECK-NOT: define weak_odr void @_ZN3fooIiE3barC2Ei +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +extern template __attribute__((unique_instantiation)) int bar(); + +template < typename T > T bar() { +return (T)0; +} + +// CHECK: define i32 @_Z3barIiET_v() +// CHECK-NOT: define weak_odr i32 @_Z3barIiET_v() +template __attribute__((unique_instantiation)) int bar(); + +int footest() { +auto var = foo{5}; +auto var2 = foo::bar{5}; +auto x = bar(); +return var.getX(); +} Index: lib/Sema/SemaTemplate.cpp === --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7330,20 +7330,22 @@ Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); Specialization->setRBraceLoc(SourceLocation()); + Specialization->setTemplateSpecializationKind(TSK); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + if (PrevDecl) +mergeDeclAttributes(Specialization, PrevDecl); + // Add the explicit instantiation into its lexical context. However, // since explicit instantiations are never found by name lookup, we // just put it into the declaration context directly. Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Specialization); // Syntax is now OK, so return if it has no other effect on semantics. if (HasNoEffect) { -// Set the template specialization kind. -Specialization->setTemplateSpecializationKind(TSK); return Specialization; } @@ -7397,14 +7399,7 @@ } } -// Set the template specialization kind. Make sure it is set before -// instantiating the members which will trigger ASTConsumer callbacks. -Specialization->setTemplateSpecializationKind(TSK); InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); - } else { - -// Set the template specialization kind. -Specialization->setTemplateSpecializationKind(TSK); } return Specialization; @@ -7855,11 +7850,34 @@ return (Decl*) nullptr; } + bool HadDeclaration = Specialization->getTemplateSpecializationKind() == +TSK_ExplicitInstantiationDeclaration; + bool HadUniqueInstantiation = Specialization->
[PATCH] D13421: Fix makefile build on OSX when ARM targets are not enabled
loladiro created this revision. loladiro added a reviewer: beanz. loladiro added a subscriber: cfe-commits. loladiro set the repository for this revision to rL LLVM. Herald added subscribers: rengolin, aemerson. When LLVM/Clang is built without ARM support, the ios_kext runtime library is not built, but without this patch, the Makefile still tries to copy it. This is a recent regression, because the ios_kext library used to also be built on x86_64. Repository: rL LLVM http://reviews.llvm.org/D13421 Files: runtime/compiler-rt/Makefile Index: runtime/compiler-rt/Makefile === --- runtime/compiler-rt/Makefile +++ runtime/compiler-rt/Makefile @@ -89,8 +89,10 @@ endif ifneq ($(IOS_SDK),) +ifneq (,$(filter ARM AARCH64,$(TARGETS_TO_BUILD))) RuntimeLibrary.darwin.Configs += cc_kext_ios.a endif +endif ifneq ($(IOSSIM_SDK),) RuntimeLibrary.darwin.Configs += asan_iossim_dynamic.dylib \ Index: runtime/compiler-rt/Makefile === --- runtime/compiler-rt/Makefile +++ runtime/compiler-rt/Makefile @@ -89,8 +89,10 @@ endif ifneq ($(IOS_SDK),) +ifneq (,$(filter ARM AARCH64,$(TARGETS_TO_BUILD))) RuntimeLibrary.darwin.Configs += cc_kext_ios.a endif +endif ifneq ($(IOSSIM_SDK),) RuntimeLibrary.darwin.Configs += asan_iossim_dynamic.dylib \ ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r249281 - Fix makefile build on OSX when ARM targets are not enabled
Author: kfischer Date: Sun Oct 4 13:51:04 2015 New Revision: 249281 URL: http://llvm.org/viewvc/llvm-project?rev=249281&view=rev Log: Fix makefile build on OSX when ARM targets are not enabled Summary: When LLVM/Clang is built without ARM support, the ios_kext runtime library is not built, but without this patch, the Makefile still tries to copy it. This is a recent regression, because the ios_kext library used to also be built on x86_64. Reviewers: beanz Subscribers: aemerson, cfe-commits, rengolin Differential Revision: http://reviews.llvm.org/D13421 Modified: cfe/trunk/runtime/compiler-rt/Makefile Modified: cfe/trunk/runtime/compiler-rt/Makefile URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/runtime/compiler-rt/Makefile?rev=249281&r1=249280&r2=249281&view=diff == --- cfe/trunk/runtime/compiler-rt/Makefile (original) +++ cfe/trunk/runtime/compiler-rt/Makefile Sun Oct 4 13:51:04 2015 @@ -89,8 +89,10 @@ RuntimeLibrary.darwin.Configs += ios.a p endif ifneq ($(IOS_SDK),) +ifneq (,$(filter ARM AARCH64,$(TARGETS_TO_BUILD))) RuntimeLibrary.darwin.Configs += cc_kext_ios.a endif +endif ifneq ($(IOSSIM_SDK),) RuntimeLibrary.darwin.Configs += asan_iossim_dynamic.dylib \ ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro updated this revision to Diff 36476. loladiro added a comment. Also set the correct linkage on vtables of classes with the new attribute. http://reviews.llvm.org/D13330 Files: include/clang/AST/ASTContext.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,18 @@ +// RUN: %clang -cc1 -std=c++11 -fsyntax-only -verify %s + +template < typename T > struct foo1 { }; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{requires a previous declaration}} + +template < typename T > struct foo2 { }; +extern template struct foo2; // expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{must be specified on all declarations}} + +template < typename T > struct foo3 { }; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{must be specified on all declarations}} + +template < typename T > struct __attribute__((unique_instantiation)) foo4 { }; // expected-error{{only applies to explicit template declarations or definitions}} + +template < typename T > struct foo5 { }; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{must be specified on all declarations}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,35 @@ +// RUN: %clang -std=c++11 -emit-llvm -O0 -c -S -o - %s | FileCheck %s + +template < typename T > struct foo { +T x; +T getX() { return x; } +struct bar { +T y; +bar(T y) : y(y) {} +}; +}; +template < typename T > T bar(); + +// CHECK: define i32 @_ZN3fooIiE4getXEv +// CHECK: define void @_ZN3fooIiE3barC2Ei +// CHECK-NOT: define weak_odr i32 @_ZN3fooIiE4getXEv +// CHECK-NOT: define weak_odr void @_ZN3fooIiE3barC2Ei +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +extern template __attribute__((unique_instantiation)) int bar(); + +template < typename T > T bar() { +return (T)0; +} + +// CHECK: define i32 @_Z3barIiET_v() +// CHECK-NOT: define weak_odr i32 @_Z3barIiET_v() +template __attribute__((unique_instantiation)) int bar(); + +int footest() { +auto var = foo{5}; +auto var2 = foo::bar{5}; +auto x = bar(); +return var.getX(); +} Index: lib/Sema/SemaTemplate.cpp === --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7330,20 +7330,22 @@ Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); Specialization->setRBraceLoc(SourceLocation()); + Specialization->setTemplateSpecializationKind(TSK); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + if (PrevDecl) +mergeDeclAttributes(Specialization, PrevDecl); + // Add the explicit instantiation into its lexical context. However, // since explicit instantiations are never found by name lookup, we // just put it into the declaration context directly. Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Specialization); // Syntax is now OK, so return if it has no other effect on semantics. if (HasNoEffect) { -// Set the template specialization kind. -Specialization->setTemplateSpecializationKind(TSK); return Specialization; } @@ -7397,14 +7399,7 @@ } } -// Set the template specialization kind. Make sure it is set before -// instantiating the members which will trigger ASTConsumer callbacks. -Specialization->setTemplateSpecializationKind(TSK); InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); - } else { - -// Set the template specialization kind. -Specialization->setTemplateSpecializationKind(TSK); } return Specialization; @@ -7855,11 +7850,34 @@ return (Decl*) nullptr; } + bool HadDeclaration = Specialization->getTemplateSpecializationKind() == +TSK_ExplicitInstantiationDeclaration; + bool HadUniqueInstantiation = Specialization->hasAttr(); + SourceLocation OldUniqueInstantiationLoc; + if (HadUniqueInstantiation) { +OldUniqueInstantiationLoc = + Specializ
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added a comment. Ok, I have tested this more extensively now. I'm happy with the results. Here's a patch that applies this to LLVM for example: https://gist.github.com/Keno/79b08a4b187c4d950dd0 Before: $llvm-objdump -weak-bind libLLVM-3.8svn.dylib | wc -l 300 After: $llvm-objdump -weak-bind libLLVM-3.8svn.dylib | wc -l 15 with none of those being LLVM symbols. http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13419: Fix several problems at the intersection of template instantiations and visibility
loladiro updated this revision to Diff 36565. loladiro added a comment. Address review comment re loop structure. Reword comment that had a typo to both fix the typo and make the intent of the code more clear. Repository: rL LLVM http://reviews.llvm.org/D13419 Files: lib/AST/Decl.cpp lib/AST/DeclCXX.cpp test/CodeGenCXX/visibility.cpp Index: test/CodeGenCXX/visibility.cpp === --- test/CodeGenCXX/visibility.cpp +++ test/CodeGenCXX/visibility.cpp @@ -1314,3 +1314,57 @@ // CHECK-LABEL: define void @_ZN6test693foo1fEv // CHECK-HIDDEN-LABEL: define hidden void @_ZN6test693foo1fEv } + +namespace test70 { + template < typename T > class foo { + public: + T x; + template < typename S > + HIDDEN S AddS(S); + template < typename S > class HIDDEN barS { +public: + static S AddS2(foo x, S); + }; + template < typename S > class HIDDEN barZ { + public: +template < typename Z > + static S AddSZ(foo x, S, Z); + }; + }; + + // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4AddSIxEET_S3_ + // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4AddSIxEET_S3_ + template < typename T > + template < typename S > + HIDDEN S foo::AddS(S y) { + return ((S) x) + y; + } + + // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x + // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x + template < typename T > + template < typename S > + HIDDEN S foo::barS::AddS2(foo x, S y) { + return ((S) x.x) + y; + } + + // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_ + // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_ + template < typename T > + template < typename S > + template < typename Z > + HIDDEN S foo::barZ::AddSZ(foo x, S y, Z z) { + return ((S) x.x) + y + ((S) z); + } + + extern template struct foo; + template struct foo; + + void f() { + auto var = foo{5}; + auto bar = var.AddS((long long)3); + auto bar2 = decltype(var)::barS::AddS2(var,3); + auto bar3 = decltype(var)::barZ::AddSZ(var,3,(char)0); + } +} + Index: lib/AST/DeclCXX.cpp === --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1261,17 +1261,19 @@ if (auto *TD = dyn_cast(this)) { auto From = TD->getInstantiatedFrom(); if (auto *CTD = From.dyn_cast()) { - while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { -if (NewCTD->isMemberSpecialization()) + while (!CTD->isMemberSpecialization()) { +auto *NewCTD = CTD->getInstantiatedFromMemberTemplate(); +if (!NewCTD) break; CTD = NewCTD; } return CTD->getTemplatedDecl()->getDefinition(); } if (auto *CTPSD = From.dyn_cast()) { - while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { -if (NewCTPSD->isMemberSpecialization()) + while (!CTPSD->isMemberSpecialization()) { +auto *NewCTPSD = CTPSD->getInstantiatedFromMember(); +if (!NewCTPSD) break; CTPSD = NewCTPSD; } Index: lib/AST/Decl.cpp === --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1049,7 +1049,9 @@ // If this is a member class of a specialization of a class template // and the corresponding decl has explicit visibility, use that. if (const CXXRecordDecl *RD = dyn_cast(ND)) { -CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); +const CXXRecordDecl *InstantiatedFrom = RD->getTemplateInstantiationPattern(); +if (!InstantiatedFrom) + InstantiatedFrom = RD->getInstantiatedFromMemberClass(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); } @@ -1084,16 +1086,12 @@ } // Also handle function template specializations. if (const FunctionDecl *fn = dyn_cast(ND)) { -// If the function is a specialization of a template with an -// explicit visibility attribute, use that. -if (FunctionTemplateSpecializationInfo *templateInfo - = fn->getTemplateSpecializationInfo()) - return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(), - kind); - -// If the function is a member of a specialization of a class template -// and the corresponding decl has explicit visibility, use that. -FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction(); +// If the function is a template specialization or a member of +// a specialized class template and the corresponding decl has +// explicit visibility, use that. +FunctionDecl *InstantiatedFrom = fn->getTemplateInstantiationPattern(); +if (!InstantiatedFrom) + InstantiatedFrom = fn->getInstantiatedFromMemberFunction();
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added inline comments. Comment at: include/clang/Basic/AttrDocs.td:1638 @@ +1637,3 @@ + +Note that to ensure correct execution the user MUST make certain that no +other translation unit has an implicit instantiation of the same entity. In aaron.ballman wrote: > In the unlikely event the user gets this wrong (lol), is there a way to > diagnose this on the backend? The wording here makes it sound like it's > possible for this to cause silent miscompiles, which would be unfortunate. I don't think there is anything that can be really done here. I believe the static linker will link this just fine (there'll be one weak and one strong symbol). The difficulty of course arises with dynamic linkers that won't bother looking for any weak symbols to merge with (at least the OS X one doesn't). I suppose it's not really that different from missing a `weak` attribute on some declarations but not others. Comment at: lib/CodeGen/CGVTables.cpp:744 @@ +743,3 @@ +// UniqueInstantiationAttr), the VTable should too. +keyFunction->dump(); +if (Context.containedInUniqueInstantiation(keyFunction)) aaron.ballman wrote: > Looks like some debugging code accidentally made it in. Thanks! Comment at: lib/Sema/SemaDecl.cpp:2285 @@ +2284,3 @@ + // here. + if (auto *CTSD = dyn_cast(New)) { +TemplateSpecializationKind kind = CTSD->getSpecializationKind(); aaron.ballman wrote: > Isn't this a bit broad? I do agree that we don't want to give incorrect > warnings, but it seems like this may inadvertently silence correct warnings > as well. If my gut feeling is wrong (which it might be), it would be good to > have some test cases confirming that this doesn't silence correct > diagnostics. As far as I know, this is only called from mergeDeclAttributes, which didn't use to be called on these before this patch. I also don't think any attributes but dllexport or unique_instantiation apply to these declarations and those two both need special processing. http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro updated this revision to Diff 37555. loladiro added a comment. Address review comments and clang-format. http://reviews.llvm.org/D13330 Files: include/clang/AST/ASTContext.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2339,6 +2339,8 @@ case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction"; +case Func | Class: + return "ExpectedFunctionOrClass"; // If not compiling for C++, the class portion does not apply. case Func | Var | Class: Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,23 @@ +// RUN: %clang -cc1 -std=c++11 -fsyntax-only -verify %s + +template +struct foo1 {}; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{requires a previous declaration}} + +template +struct foo2 {}; +extern template struct foo2;// expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{must be specified on all declarations}} + +template +struct foo3 {}; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{must be specified on all declarations}} + +template +struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{only applies to explicit template declarations or definitions}} + +template +struct foo5 {}; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{must be specified on all declarations}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,38 @@ +// RUN: %clang -std=c++11 -emit-llvm -O0 -c -S -o - %s | FileCheck %s + +template +struct foo { + T x; + T getX() { return x; } + struct bar { +T y; +bar(T y) : y(y) {} + }; +}; +template +T bar(); + +// CHECK: define i32 @_ZN3fooIiE4getXEv +// CHECK: define void @_ZN3fooIiE3barC2Ei +// CHECK-NOT: define weak_odr i32 @_ZN3fooIiE4getXEv +// CHECK-NOT: define weak_odr void @_ZN3fooIiE3barC2Ei +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +extern template __attribute__((unique_instantiation)) int bar(); + +template +T bar() { + return (T)0; +} + +// CHECK: define i32 @_Z3barIiET_v() +// CHECK-NOT: define weak_odr i32 @_Z3barIiET_v() +template __attribute__((unique_instantiation)) int bar(); + +int footest() { + auto var = foo{5}; + auto var2 = foo::bar{5}; + auto x = bar(); + return var.getX(); +} Index: lib/Sema/SemaTemplate.cpp === --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7330,20 +7330,22 @@ Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); Specialization->setRBraceLoc(SourceLocation()); + Specialization->setTemplateSpecializationKind(TSK); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + if (PrevDecl) +mergeDeclAttributes(Specialization, PrevDecl); + // Add the explicit instantiation into its lexical context. However, // since explicit instantiations are never found by name lookup, we // just put it into the declaration context directly. Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Specialization); // Syntax is now OK, so return if it has no other effect on semantics. if (HasNoEffect) { -// Set the template specialization kind. -Specialization->setTemplateSpecializationKind(TSK); return Specialization; } @@ -7397,14 +7399,7 @@ } } -// Set the template specialization kind. Make sure it is set before -// instantiating the members which will trigger ASTConsumer callbacks. -Specialization->setTemplateSpecializationKind(TSK); InstantiateClassTemplateSpe
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added inline comments. Comment at: include/clang/Basic/Attr.td:1463 @@ +1462,3 @@ + let Spellings = [GNU<"unique_instantiation">]; + let Subjects = SubjectList<[Function, CXXRecord], ErrorDiag>; + let Documentation = [UniqueInstantiationDocs]; majnemer wrote: > What about variable templates? I hadn't tried before, but looking at this, I'd say they're broken in clang anyway and I'm gonna say fixing that is outside the scope of this revision: ``` $ cat test.cpp template T n; extern template int n; template int n; int main() { return n; } $ ./usr/bin/clang++ -std=c++14 -c test.cpp $ nm test.o T main U _Z1nIiE $ nm test.o.gcc6 [snip] 060098c u _Z1nIiE ``` Comment at: include/clang/Basic/DiagnosticSemaKinds.td:2456 @@ -2450,1 +2455,3 @@ +def err_unique_instantiation_not_previous : Error< + "The unique_instantiation must be specified on all declarations and definitions of a particular explicit template instantiation.">; aaron.ballman wrote: > Should say: the 'unique_instantiation' attribute. > > Also, I'm not keen on "a particular" as it's very non-specific. > > I wonder if we need err_unique_instantiation_no_declaration and > err_unique_instantiation_not_previous to be separate diagnostics? Aren't they > both effectively saying, > > "a 'unique_instantiation' attribute must be specified for all declarations > and definitions of the explicit template instantiation" They are checking for two different conditions in the spec. One requires that all explicit template instantiations with this attribute have a declaration, the other that every declaration/definition has the attribute. Comment at: test/CodeGenCXX/unique-instantiation.cpp:1 @@ +1,2 @@ +// RUN: %clang -std=c++11 -emit-llvm -O0 -c -S -o - %s | FileCheck %s + majnemer wrote: > Is -O0 needed here? No, removing. http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro set the repository for this revision to rL LLVM. loladiro updated this revision to Diff 38039. loladiro added a comment. Address review comments. Repository: rL LLVM http://reviews.llvm.org/D13330 Files: include/clang/AST/ASTContext.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2339,6 +2339,8 @@ case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction"; +case Func | Class: + return "ExpectedFunctionOrClass"; // If not compiling for C++, the class portion does not apply. case Func | Var | Class: Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,23 @@ +// RUN: %clang -cc1 -std=c++11 -fsyntax-only -verify %s + +template +struct foo1 {}; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{requires a previous declaration}} + +template +struct foo2 {}; +extern template struct foo2;// expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{must be specified for all declarations}} + +template +struct foo3 {}; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{must be specified for all declarations}} + +template +struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{only applies to explicit template declarations or definitions}} + +template +struct foo5 {}; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{must be specified for all declarations}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,38 @@ +// RUN: %clang -std=c++11 -emit-llvm -c -S -o - %s | FileCheck %s + +template +struct foo { + T x; + T getX() { return x; } + struct bar { +T y; +bar(T y) : y(y) {} + }; +}; +template +T bar(); + +// CHECK: define i32 @_ZN3fooIiE4getXEv +// CHECK: define void @_ZN3fooIiE3barC2Ei +// CHECK-NOT: define weak_odr i32 @_ZN3fooIiE4getXEv +// CHECK-NOT: define weak_odr void @_ZN3fooIiE3barC2Ei +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +extern template __attribute__((unique_instantiation)) int bar(); + +template +T bar() { + return (T)0; +} + +// CHECK: define i32 @_Z3barIiET_v() +// CHECK-NOT: define weak_odr i32 @_Z3barIiET_v() +template __attribute__((unique_instantiation)) int bar(); + +int footest() { + auto var = foo{5}; + auto var2 = foo::bar{5}; + auto x = bar(); + return var.getX(); +} Index: lib/Sema/SemaTemplate.cpp === --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7330,20 +7330,22 @@ Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); Specialization->setRBraceLoc(SourceLocation()); + Specialization->setTemplateSpecializationKind(TSK); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + if (PrevDecl) +mergeDeclAttributes(Specialization, PrevDecl); + // Add the explicit instantiation into its lexical context. However, // since explicit instantiations are never found by name lookup, we // just put it into the declaration context directly. Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Specialization); // Syntax is now OK, so return if it has no other effect on semantics. if (HasNoEffect) { -// Set the template specialization kind. -Specialization->setTemplateSpecializationKind(TSK); return Specialization; } @@ -7397,14 +7399,7 @@ } } -// Set the template specialization kind. Make sure it is set before -// instantiating the members which will trigger ASTConsumer callbacks. -Specialization->setTe
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added inline comments. Comment at: include/clang/Basic/Attr.td:1463 @@ +1462,3 @@ + let Spellings = [GNU<"unique_instantiation">]; + let Subjects = SubjectList<[Function, CXXRecord], ErrorDiag>; + let Documentation = [UniqueInstantiationDocs]; majnemer wrote: > They work ok, clang just thinks that it's a declaration of a variable > template. Try this: > template T n = T(); > extern template int n; > template int n; I see. I'll look into adding support for it. Can you explain why my example doesn't work? GCC seems to allow this. Repository: rL LLVM http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D13959: Fix crash in EmitDeclMetadata mode
loladiro created this revision. loladiro added reviewers: rjmccall, labath. loladiro added a subscriber: cfe-commits. loladiro set the repository for this revision to rL LLVM. This fixes a bug that's easily encountered in LLDB (https://llvm.org/bugs/show_bug.cgi?id=22875). The problem here is that we mangle a name during debug info emission, but never actually emit the actual Decl, so we run into problems here. I am not entirely sure this is the right fix. The comment says something about StaticLocalDeclMap, which may be better here, but I checked and that already existed when this functionality was added, which makes me think that there is some reason it wasn't used. Repository: rL LLVM http://reviews.llvm.org/D13959 Files: lib/CodeGen/CodeGenModule.cpp Index: lib/CodeGen/CodeGenModule.cpp === --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -3710,7 +3710,10 @@ // StaticLocalDeclMap for (auto &I : MangledDeclNames) { llvm::GlobalValue *Addr = getModule().getNamedValue(I.second); -EmitGlobalDeclMetadata(*this, GlobalMetadata, I.first, Addr); +// Some mangled names don't necessarily have an associated GlobalValue +// in this module, e.g. if we mangled it for DebugInfo. +if (Addr) + EmitGlobalDeclMetadata(*this, GlobalMetadata, I.first, Addr); } } Index: lib/CodeGen/CodeGenModule.cpp === --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -3710,7 +3710,10 @@ // StaticLocalDeclMap for (auto &I : MangledDeclNames) { llvm::GlobalValue *Addr = getModule().getNamedValue(I.second); -EmitGlobalDeclMetadata(*this, GlobalMetadata, I.first, Addr); +// Some mangled names don't necessarily have an associated GlobalValue +// in this module, e.g. if we mangled it for DebugInfo. +if (Addr) + EmitGlobalDeclMetadata(*this, GlobalMetadata, I.first, Addr); } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13959: Fix crash in EmitDeclMetadata mode
loladiro added a comment. Can you provide insight as to why this is looking at MangledDeclNames rather than the StaticLocalDeclMap? I'd like to extend the comment with an explanation. Repository: rL LLVM http://reviews.llvm.org/D13959 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r252229 - Fix crash in EmitDeclMetadata mode
Author: kfischer Date: Thu Nov 5 17:18:44 2015 New Revision: 252229 URL: http://llvm.org/viewvc/llvm-project?rev=252229&view=rev Log: Fix crash in EmitDeclMetadata mode Summary: This fixes a bug that's easily encountered in LLDB (https://llvm.org/bugs/show_bug.cgi?id=22875). The problem here is that we mangle a name during debug info emission, but never actually emit the actual Decl, so we run into problems in EmitDeclMetadata (which assumes such a Decl exists). Fix that by just skipping metadata emissions for mangled names that don't have associated Decls. Reviewers: rjmccall Subscribers: labath, cfe-commits Differential Revision: http://reviews.llvm.org/D13959 Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=252229&r1=252228&r2=252229&view=diff == --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Thu Nov 5 17:18:44 2015 @@ -3707,10 +3707,12 @@ bool CodeGenModule::lookupRepresentative void CodeGenModule::EmitDeclMetadata() { llvm::NamedMDNode *GlobalMetadata = nullptr; - // StaticLocalDeclMap for (auto &I : MangledDeclNames) { llvm::GlobalValue *Addr = getModule().getNamedValue(I.second); -EmitGlobalDeclMetadata(*this, GlobalMetadata, I.first, Addr); +// Some mangled names don't necessarily have an associated GlobalValue +// in this module, e.g. if we mangled it for DebugInfo. +if (Addr) + EmitGlobalDeclMetadata(*this, GlobalMetadata, I.first, Addr); } } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added inline comments. Comment at: include/clang/Basic/Attr.td:1463 @@ +1462,3 @@ + let Spellings = [GNU<"unique_instantiation">]; + let Subjects = SubjectList<[Function, CXXRecord], ErrorDiag>; + let Documentation = [UniqueInstantiationDocs]; loladiro wrote: > majnemer wrote: > > They work ok, clang just thinks that it's a declaration of a variable > > template. Try this: > > template T n = T(); > > extern template int n; > > template int n; > I see. I'll look into adding support for it. Can you explain why my example > doesn't work? GCC seems to allow this. Bump on the question of differences to GCC here. Comment at: include/clang/Basic/DiagnosticSemaKinds.td:2456 @@ -2450,1 +2455,3 @@ +def err_unique_instantiation_not_previous : Error< + "'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation">; aaron.ballman wrote: > > They are checking for two different conditions in the spec. One requires > > that all explicit template instantiations with this attribute have a > > declaration, the other that every declaration/definition has the attribute. > > Okay, I see now what this diagnostic is attempting to convey. I think it > should read: > ``` > def err_unique_instantiation_no_declaration : Error< > "'unique_instantiation' attribute on an explicit instantiation requires a > previous explicit instantiation declaration">; > ``` Sounds good. Comment at: test/SemaCXX/unique-instantiations.cpp:23 @@ +22,2 @@ +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{must be specified for all declarations}} aaron.ballman wrote: > Missing tests for correct usage of the attribute. Missing tests of the > attribute diagnosing when given arguments. Isn't the correct usage checked for in the CodeGen tests above? Repository: rL LLVM http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro updated this revision to Diff 39627. loladiro updated the summary for this revision. loladiro added a comment. Address review feedback regarding diagnostic wording/expand tests to full text of diagnostic. http://reviews.llvm.org/D13330 Files: include/clang/AST/ASTContext.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2371,6 +2371,8 @@ case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction"; +case Func | Class: + return "ExpectedFunctionOrClass"; // If not compiling for C++, the class portion does not apply. case Func | Var | Class: Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,28 @@ +// RUN: %clang -cc1 -std=c++11 -fsyntax-only -verify %s + +template +struct foo1 {}; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +struct foo2 {}; +extern template struct foo2;// expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo3 {}; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +template +struct foo5 {}; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo6 {}; +extern template struct __attribute__((unique_instantiation(16))) foo6;// expected-error{{'unique_instantiation' attribute takes no arguments}} +template struct __attribute__((unique_instantiation("Hello World"))) foo6; // expected-error{{'unique_instantiation' attribute takes no arguments}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,38 @@ +// RUN: %clang -std=c++11 -emit-llvm -c -S -o - %s | FileCheck %s + +template +struct foo { + T x; + T getX() { return x; } + struct bar { +T y; +bar(T y) : y(y) {} + }; +}; +template +T bar(); + +// CHECK: define i32 @_ZN3fooIiE4getXEv +// CHECK: define void @_ZN3fooIiE3barC2Ei +// CHECK-NOT: define weak_odr i32 @_ZN3fooIiE4getXEv +// CHECK-NOT: define weak_odr void @_ZN3fooIiE3barC2Ei +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +extern template __attribute__((unique_instantiation)) int bar(); + +template +T bar() { + return (T)0; +} + +// CHECK: define i32 @_Z3barIiET_v() +// CHECK-NOT: define weak_odr i32 @_Z3barIiET_v() +template __attribute__((unique_instantiation)) int bar(); + +int footest() { + auto var = foo{5}; + auto var2 = foo::bar{5}; + auto x = bar(); + return var.getX(); +} Index: lib/Sema/SemaTemplate.cpp === --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7330,20 +7330,22 @@ Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); Specialization->setRBraceLoc(SourceLocation()); + Specialization->setTemplateSpecializationKind(TSK); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + if (PrevDecl) +mergeDeclAttributes(Specialization, PrevDecl)
Re: [PATCH] D13610: [CodeGen] Fix CodeGenModule::CreateGlobalInitOrDestructFunction
loladiro added a subscriber: loladiro. loladiro added a comment. Thanks for this. I was about to create the same patch (after seeing this broken on 3.7) only to see it had already been done! Repository: rL LLVM http://reviews.llvm.org/D13610 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added a comment. Bumping this again. http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r253190 - [CGDebugInfo] Set the size and align for reference types
Author: kfischer Date: Mon Nov 16 03:04:13 2015 New Revision: 253190 URL: http://llvm.org/viewvc/llvm-project?rev=253190&view=rev Log: [CGDebugInfo] Set the size and align for reference types In r253186, I changed the DIBuilder API to now take size and align for reference types as well. This was done in preparation for upcoming changes to the Verifier that will validate that sizes match between DI types and IR values that are declared as having those types. This updates clang to actually pass the information through. Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp cfe/trunk/test/CodeGenCXX/debug-info-rvalue-ref.cpp Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=253190&r1=253189&r2=253190&view=diff == --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Mon Nov 16 03:04:13 2015 @@ -712,10 +712,6 @@ llvm::DIType *CGDebugInfo::CreatePointer const Type *Ty, QualType PointeeTy, llvm::DIFile *Unit) { - if (Tag == llvm::dwarf::DW_TAG_reference_type || - Tag == llvm::dwarf::DW_TAG_rvalue_reference_type) -return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit)); - // Bit size, align and offset of the type. // Size is always the size of a pointer. We can't use getTypeSize here // because that does not return the correct value for references. @@ -723,8 +719,13 @@ llvm::DIType *CGDebugInfo::CreatePointer uint64_t Size = CGM.getTarget().getPointerWidth(AS); uint64_t Align = CGM.getContext().getTypeAlign(Ty); - return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size, -Align); + if (Tag == llvm::dwarf::DW_TAG_reference_type || + Tag == llvm::dwarf::DW_TAG_rvalue_reference_type) +return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit), +Size, Align); + else +return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size, + Align); } llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name, Modified: cfe/trunk/test/CodeGenCXX/debug-info-rvalue-ref.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/debug-info-rvalue-ref.cpp?rev=253190&r1=253189&r2=253190&view=diff == --- cfe/trunk/test/CodeGenCXX/debug-info-rvalue-ref.cpp (original) +++ cfe/trunk/test/CodeGenCXX/debug-info-rvalue-ref.cpp Mon Nov 16 03:04:13 2015 @@ -8,5 +8,5 @@ void foo (int &&i) printf("%d\n", i); } -// CHECK: !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: ![[INT:[0-9]+]]) +// CHECK: !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: ![[INT:[0-9]+]], size: 64, align: 64) // CHECK: ![[INT]] = !DIBasicType(name: "int" ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro updated this revision to Diff 41261. loladiro added a comment. Rebased and made the small suggested changes to the test cases. http://reviews.llvm.org/D13330 Files: include/clang/AST/ASTContext.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2371,6 +2371,8 @@ case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction"; +case Func | Class: + return "ExpectedFunctionOrClass"; // If not compiling for C++, the class portion does not apply. case Func | Var | Class: Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,34 @@ +// RUN: %clang -cc1 -std=c++11 -fsyntax-only -verify %s + +// Correct usage +template +struct foo {}; +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +// Various examples of incorrect usage +template +struct foo1 {}; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +struct foo2 {}; +extern template struct foo2;// expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo3 {}; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +template +struct foo5 {}; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo6 {}; +extern template struct __attribute__((unique_instantiation(16))) foo6;// expected-error{{'unique_instantiation' attribute takes no arguments}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,38 @@ +// RUN: %clang -std=c++11 -emit-llvm -c -S -o - %s | FileCheck %s + +template +struct foo { + T x; + T getX() { return x; } + struct bar { +T y; +bar(T y) : y(y) {} + }; +}; +template +T bar(); + +// CHECK: define i32 @_ZN3fooIiE4getXEv +// CHECK: define void @_ZN3fooIiE3barC2Ei +// CHECK-NOT: define weak_odr i32 @_ZN3fooIiE4getXEv +// CHECK-NOT: define weak_odr void @_ZN3fooIiE3barC2Ei +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +extern template __attribute__((unique_instantiation)) int bar(); + +template +T bar() { + return (T)0; +} + +// CHECK: define i32 @_Z3barIiET_v() +// CHECK-NOT: define weak_odr i32 @_Z3barIiET_v() +template __attribute__((unique_instantiation)) int bar(); + +int footest() { + auto var = foo{5}; + auto var2 = foo::bar{5}; + auto x = bar(); + return var.getX(); +} Index: lib/Sema/SemaTemplate.cpp === --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7398,20 +7398,22 @@ Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); Specialization->setRBraceLoc(SourceLocation()); + Specialization->setTemplateSpecializationKind(TSK); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + if (PrevDecl) +mergeDeclAttributes(Specialization, PrevDecl); + // Add
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro updated this revision to Diff 41265. loladiro added a comment. Add support for variable templates http://reviews.llvm.org/D13330 Files: include/clang/AST/ASTContext.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2371,6 +2371,8 @@ case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction"; +case Func | Class: + return "ExpectedFunctionOrClass"; // If not compiling for C++, the class portion does not apply. case Func | Var | Class: Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,48 @@ +// RUN: %clang -cc1 -std=c++14 -fsyntax-only -verify %s + +// Correct usage +template +struct foo {}; +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +template +T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)) float pi; +template __attribute__((unique_instantiation)) float pi; + +// Usages on non-templates +float __attribute__((unique_instantiation)) notpi(2.71828182845904523536028747135); // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +struct __attribute__((unique_instantiation)) bar {};// expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +void __attribute__((unique_instantiation)) func() {}// expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +// Usages that violate one of the conditions required conditions +template +struct foo1 {}; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +T pi1 = T(3.1415926535897932385); +template __attribute__((unique_instantiation)) float pi1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +struct foo2 {}; +extern template struct foo2;// expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo3 {}; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +template +struct foo5 {}; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo6 {}; +extern template struct __attribute__((unique_instantiation(16))) foo6; // expected-error{{'unique_instantiation' attribute takes no arguments}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,45 @@ +// RUN: %clang -std=c++14 -emit-llvm -c -S -o - %s | FileCheck %s + +// CHECK: @_Z2piIfE = global float +// CHECK-NOT: @_Z2piIfE = weak_odr global float +template +T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)) float pi; +template __attribute__((unique_instantiation)) float pi; + +template +struct foo { + T x; + T getX() { return x; } + struct bar { +T y;
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added a comment. Bump, is there anything else that's needed here? http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13419: Fix several problems at the intersection of template instantiations and visibility
loladiro added a comment. Bumping this again. Repository: rL LLVM http://reviews.llvm.org/D13419 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added inline comments. Comment at: include/clang/Basic/AttrDocs.td:1736-1755 @@ -1722,2 +1735,22 @@ + +// Explicit template definition (in exactly ONE .cpp file) +template struct __attribute__((unique_instantiation)) my_template; + + +When the unique_instantiation attribute is specified on an explicit template +instantiation, the compiler is given license to emit strong symbols for +this specific explicit template instantiation. + +If the attribute is present on one such definition or declaration for a given +entity, it must be present on all. + +Note that to ensure correct execution the user MUST make certain that no +other translation unit has an implicit instantiation of the same entity. In +particular this means that any usage of the entity has to be preceeded by an +appropriate explicit template declaration or definition. +It is thus recommended that explicit template declarations are placed in headers +to suppress any potential implicit instantiation of the entity. In order to +encourage this programming style, any explicit template definition with this +attribute MUST be preceeded by an appropriate declaration. }]; majnemer wrote: > Instead of using all-caps for emphasis in "ONE" and "MUST", why not bold the > text instead? It would catch the eye a little faster. Sure! I assume, this follows standard RST conventions where ** is bold? Comment at: include/clang/Basic/DiagnosticSemaKinds.td:2533-2534 @@ -2531,1 +2532,4 @@ ":must be between 1 and %2}2">; +def err_unique_instantiation_wrong_decl : Error< + "'unique_instantiation' attribute only applies to an explicit template declaration or instantiation">; +def err_unique_instantiation_no_declaration : Error< majnemer wrote: > I can't seem to see any users of `err_unique_instantiation_wrong_decl`. Yes, it was replaced by adding a case to err_attribute_wrong_decl_type above. Will remove. Comment at: lib/AST/ASTContext.cpp:8283-8286 @@ +8282,6 @@ +Context.containedInUniqueInstantiation(FD)) { + // We return GVA_StrongExternal here, instead of going through the logic + // below, because even if the definition is available inline, since the + // source specified an explicit template instantiation, we want to make + // the symbol available. + return GVA_StrongExternal; majnemer wrote: > There are a lot of commas here, making it a little hard to read the > justification. > > Perhaps something along the lines of: > > > This translation unit is responsible for emitting a unique instantiation of > > this function regardless of whether or not the function is marked inline. Sounds good. Comment at: lib/CodeGen/CGVTables.cpp:744-747 @@ -743,2 +743,6 @@ case TSK_ExplicitInstantiationDefinition: +// If the key function has strong linkage (say due to +// UniqueInstantiationAttr), the VTable should too. +if (Context.containedInUniqueInstantiation(keyFunction)) + return llvm::GlobalVariable::ExternalLinkage; return !Context.getLangOpts().AppleKext ? majnemer wrote: > What if the key function is not contained within a record which is marked as > `UniqueInstantiationAttr` but the key function itself is marked > `UniqueInstantiationAttr`? I don't know, I'd be inclined to say the unique instantiation does not apply to the vtable unless it's explicit on the class, but I'd be open to differing opinions. http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro updated this revision to Diff 42100. loladiro added a comment. Address stylistic concerns brought up by David http://reviews.llvm.org/D13330 Files: include/clang/AST/ASTContext.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2373,6 +2373,8 @@ case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction"; +case Func | Class: + return "ExpectedFunctionOrClass"; // If not compiling for C++, the class portion does not apply. case Func | Var | Class: Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,46 @@ +// RUN: %clang -cc1 -std=c++14 -fsyntax-only -verify %s + +// Correct usage +template +struct foo {}; +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +template T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)) float pi; +template __attribute__((unique_instantiation)) float pi; + +// Usages on non-templates +float __attribute__((unique_instantiation)) notpi(2.71828182845904523536028747135); // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +struct __attribute__((unique_instantiation)) bar{}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +void __attribute__((unique_instantiation)) func() {} // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +// Usages that violate one of the conditions required conditions +template +struct foo1 {}; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template T pi1 = T(3.1415926535897932385); +template __attribute__((unique_instantiation)) float pi1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +struct foo2 {}; +extern template struct foo2;// expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo3 {}; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +template +struct foo5 {}; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo6 {}; +extern template struct __attribute__((unique_instantiation(16))) foo6;// expected-error{{'unique_instantiation' attribute takes no arguments}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,44 @@ +// RUN: %clang -std=c++14 -emit-llvm -c -S -o - %s | FileCheck %s + +// CHECK: @_Z2piIfE = global float +// CHECK-NOT: @_Z2piIfE = weak_odr global float +template T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)) float pi; +template __attribute__((unique_instantiation)) float pi; + +template +struct foo { + T x; + T getX() { return x; } + struct bar { +T y; +bar(T y) : y(y) {} + }; +}; +template +T b
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added inline comments. Comment at: lib/AST/ASTContext.cpp:8257-8266 @@ -8256,1 +8256,12 @@ +bool ASTContext::containedInUniqueInstantiation(const Decl *D) { + const RecordDecl *RD; + while ((RD = dyn_cast(D->getDeclContext( { +auto *CTSD = dyn_cast(RD); +if (CTSD && CTSD->hasAttr()) + return true; +D = RD; + } + return false; +} + majnemer wrote: > Function templates can contain class templates which contain functions. I > think this code will return false if the outermost function template is the > only one annotated with UniqueInstantiationAttr. So you're concerned about this case: ``` template < typename T > auto foo( T x ) { class inner { T y; public: virtual ~inner() {} inner(T y) : y(y) {} T getY() { return y; } }; return inner{x}.getY(); } extern template __attribute__((unique_instantiation)) auto foo(int); template __attribute__((unique_instantiation)) auto foo(int); ``` Right now the inner class's vtable and method is linkonce_odr. If you think it should be strong I'll look into it. http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro updated this revision to Diff 42132. loladiro added a comment. Address David's concern about inner classes. David also suggested on IRC to propagate the unique instantiation attribute down rather than walking the context chain to check for the attribute. I'll try that out, but wanted to put up a known-good version with all fixed first. http://reviews.llvm.org/D13330 Files: include/clang/AST/ASTContext.h include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2373,6 +2373,8 @@ case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction"; +case Func | Class: + return "ExpectedFunctionOrClass"; // If not compiling for C++, the class portion does not apply. case Func | Var | Class: Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,46 @@ +// RUN: %clang -cc1 -std=c++14 -fsyntax-only -verify %s + +// Correct usage +template +struct foo {}; +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +template T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)) float pi; +template __attribute__((unique_instantiation)) float pi; + +// Usages on non-templates +float __attribute__((unique_instantiation)) notpi(2.71828182845904523536028747135); // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +struct __attribute__((unique_instantiation)) bar{}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +void __attribute__((unique_instantiation)) func() {} // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +// Usages that violate one of the conditions required conditions +template +struct foo1 {}; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template T pi1 = T(3.1415926535897932385); +template __attribute__((unique_instantiation)) float pi1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +struct foo2 {}; +extern template struct foo2;// expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo3 {}; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +template +struct foo5 {}; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo6 {}; +extern template struct __attribute__((unique_instantiation(16))) foo6;// expected-error{{'unique_instantiation' attribute takes no arguments}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,69 @@ +// RUN: %clang -std=c++14 -emit-llvm -c -S -o - %s | FileCheck %s + +// CHECK: @_Z2piIfE = global float +// CHECK-NOT: @_Z2piIfE = weak_odr global float +template T pi = T(3.1415926535897932385); +extern template __attribute_
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro updated this revision to Diff 42137. loladiro added a comment. Propagate unique instantiation attribute to children rather than later trying to look through the DeclContexts to see if we're contained in one that has the attribute. http://reviews.llvm.org/D13330 Files: include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h include/clang/Sema/Sema.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2373,6 +2373,8 @@ case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction"; +case Func | Class: + return "ExpectedFunctionOrClass"; // If not compiling for C++, the class portion does not apply. case Func | Var | Class: Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,48 @@ +// RUN: %clang -cc1 -std=c++14 -fsyntax-only -verify %s + +// Correct usage +template +struct foo {}; +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +template +T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)) float pi; +template __attribute__((unique_instantiation)) float pi; + +// Usages on non-templates +float __attribute__((unique_instantiation)) notpi(2.71828182845904523536028747135); // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +struct __attribute__((unique_instantiation)) bar {};// expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +void __attribute__((unique_instantiation)) func() {}// expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +// Usages that violate one of the conditions required conditions +template +struct foo1 {}; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +T pi1 = T(3.1415926535897932385); +template __attribute__((unique_instantiation)) float pi1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +struct foo2 {}; +extern template struct foo2;// expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo3 {}; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +template +struct foo5 {}; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo6 {}; +extern template struct __attribute__((unique_instantiation(16))) foo6; // expected-error{{'unique_instantiation' attribute takes no arguments}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,74 @@ +// RUN: %clang -std=c++14 -emit-llvm -c -S -o - %s | FileCheck %s + +// CHECK: @_Z2piIfE = global float +// CHECK-NOT: @_Z2piIfE = weak_odr global float +template +T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro added a comment. @majnemer Do you like the new approach? Is there anything else to be done here? http://reviews.llvm.org/D13330 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D13330: Implement __attribute__((unique_instantiation))
loladiro updated this revision to Diff 43218. loladiro added a comment. Rebased http://reviews.llvm.org/D13330 Files: include/clang/Basic/Attr.td include/clang/Basic/AttrDocs.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h include/clang/Sema/Sema.h lib/AST/ASTContext.cpp lib/CodeGen/CGVTables.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp test/CodeGenCXX/unique-instantiation.cpp test/SemaCXX/unique-instantiations.cpp utils/TableGen/ClangAttrEmitter.cpp Index: utils/TableGen/ClangAttrEmitter.cpp === --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2369,6 +2369,8 @@ case Func | ObjCMethod | Param: return "ExpectedFunctionMethodOrParameter"; case Func | ObjCMethod: return "ExpectedFunctionOrMethod"; case Func | Var: return "ExpectedVariableOrFunction"; +case Func | Class: + return "ExpectedFunctionOrClass"; // If not compiling for C++, the class portion does not apply. case Func | Var | Class: Index: test/SemaCXX/unique-instantiations.cpp === --- /dev/null +++ test/SemaCXX/unique-instantiations.cpp @@ -0,0 +1,48 @@ +// RUN: %clang -cc1 -std=c++14 -fsyntax-only -verify %s + +// Correct usage +template +struct foo {}; +extern template struct __attribute__((unique_instantiation)) foo; +template struct __attribute__((unique_instantiation)) foo; + +template +T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)) float pi; +template __attribute__((unique_instantiation)) float pi; + +// Usages on non-templates +float __attribute__((unique_instantiation)) notpi(2.71828182845904523536028747135); // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +struct __attribute__((unique_instantiation)) bar {};// expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} +void __attribute__((unique_instantiation)) func() {}// expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +// Usages that violate one of the conditions required conditions +template +struct foo1 {}; +template struct __attribute__((unique_instantiation)) foo1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +T pi1 = T(3.1415926535897932385); +template __attribute__((unique_instantiation)) float pi1; // expected-error{{'unique_instantiation' attribute on an explicit instantiation requires a previous explicit instantiation declaration}} + +template +struct foo2 {}; +extern template struct foo2;// expected-note{{previous explicit instantiation is here}} +template struct __attribute__((unique_instantiation)) foo2; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo3 {}; +extern template struct __attribute__((unique_instantiation)) foo3; // expected-note{{previous explicit instantiation is here}} +extern template struct foo3; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct __attribute__((unique_instantiation)) foo4 {}; // expected-error{{'unique_instantiation' attribute only applies to explicit template declarations or definitions}} + +template +struct foo5 {}; +extern template struct __attribute__((unique_instantiation)) foo5; // expected-note{{previous explicit instantiation is here}} +template struct foo5; // expected-error{{'unique_instantiation' attribute must be specified for all declarations and definitions of this explicit template instantiation}} + +template +struct foo6 {}; +extern template struct __attribute__((unique_instantiation(16))) foo6; // expected-error{{'unique_instantiation' attribute takes no arguments}} Index: test/CodeGenCXX/unique-instantiation.cpp === --- /dev/null +++ test/CodeGenCXX/unique-instantiation.cpp @@ -0,0 +1,74 @@ +// RUN: %clang -std=c++14 -emit-llvm -c -S -o - %s | FileCheck %s + +// CHECK: @_Z2piIfE = global float +// CHECK-NOT: @_Z2piIfE = weak_odr global float +template +T pi = T(3.1415926535897932385); +extern template __attribute__((unique_instantiation)) float pi; +template __attribute__((unique_instantiation)) float pi; + +template +struct foo { + T x; + T getX() { return x; } + struct bar { +T y; +
Re: [PATCH] D13419: Fix several problems at the intersection of template instantiations and visibility
loladiro added a comment. bump again Repository: rL LLVM http://reviews.llvm.org/D13419 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][MinGW] Implement -mcrtdll option to switch crt choice (PR #149469)
https://github.com/Keno created https://github.com/llvm/llvm-project/pull/149469 This implements the mingw `-mcrtdll` option recently added to gcc. This option is useful for having the compiler be in charge of crt version selection while only shipping a single copy of mingw for a multi-ABI toolchain. That said, there are various ABI dependent compiler libraries (e.g. libstdc++), so a certain degree of ABI awareness is nevertheless required in order to use this option correctly. See also #149434 (which this branch includes, since it touches the same code). >From e3dd50c14f79dca0d28e482f707849c92ec0df76 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 18 Jul 2025 01:02:00 + Subject: [PATCH 1/2] [Driver][MinGW] Always put libc argument last, even if non-standard I was attempting to build openblas with clang in msys2's `ucrt64` environment (I'm aware of the `clang64` environment, but I wanted libstdc++). The openblas link failed with the following: ``` clang -march=native -mtune=native -m64 -O2 -fno-asynchronous-unwind-tables -O2 -DSMALL_MATRIX_OPT -DMS_ABI -DMAX_STACK_ALLOC=2048 -Wall -m64 -DF_INTERFACE_GFORT -DDYNAMIC_ARCH -DSMP_SERVER -DNO_WARMUP -DMAX_CPU_NUMBER=512 -DMAX_PARALLEL_NUMBER=1 -DBUILD_SINGLE=1 -DBUILD_DOUBLE=1 -DBUILD_COMPLEX=1 -DBUILD_COMPLEX16=1 -DVERSION=\"0.3.29\" -UASMNAME -UASMFNAME -UNAME -UCNAME -UCHAR_NAME -UCHAR_CNAME -DASMNAME= -DASMFNAME=_ -DNAME=_ -DCNAME= -DCHAR_NAME=\"_\" -DCHAR_CNAME=\"\" -DNO_AFFINITY -I.. libopenblas64_.def dllinit.obj \ -shared -o ../libopenblas64_.dll -Wl,--out-implib,../libopenblas64_.dll.a \ -Wl,--whole-archive ../libopenblas64_p-r0.3.29.a -Wl,--no-whole-archive -LC:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/15.1.0 -LC:/msys64/ucrt64/bin/../lib/gcc -LC:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/15.1.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/15.1.0/../../../../lib -LC:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/15.1.0/../../../../x86_64-w64-mingw32/lib -LC:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/15.1.0/../../.. -lgfortran -lmingwex -lmsvcrt -lquadmath -lm -lpthread -lmingwex -lmsvcrt -defaultlib:advapi32 -lgfortran -defaultlib:advapi32 -lgfortran C:/msys64/ucrt64/bin/ld: C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/15.1.0/../../../../lib/libmingw32.a(lib64_libmingw32_a-pseudo-reloc.o): in function `__report_error': D:/W/B/src/mingw-w64/mingw-w64-crt/crt/pseudo-reloc.c:157:(.text+0x59): undefined reference to `abort' C:/msys64/ucrt64/bin/ld: C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/15.1.0/../../../../lib/libmingw32.a(lib64_libmingw32_a-tlsthrd.o): in function `___w64_mingwthr_add_key_dtor': D:/W/B/src/mingw-w64/mingw-w64-crt/crt/tlsthrd.c:48:(.text+0xa5): undefined reference to `calloc' C:/msys64/ucrt64/bin/ld: C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/15.1.0/../../../../lib/libmingw32.a(lib64_libmingw32_a-pesect.o): in function `_FindPESectionByName': D:/W/B/src/mingw-w64/mingw-w64-crt/crt/pesect.c:79:(.text+0xfd): undefined reference to `strncmp' ``` These symbols come from the `-lmingw32` dep that the driver added and are ordinarily found in `-lmsvcrt`, which got skipped here, because openblas passed `-lmsvcrt` explicitly. Since we always add these libraries at the end here, I think that clang is "at fault" (as opposed to a user or packaging mistake) and should have added some crt here. To preserve the intent of letting the user override which crt is chosen, duplicate the (first) user chosen crt `-l` into this position, although we should perhaps consider an explicit `-mcrtdll` like gcc has as well. --- clang/lib/Driver/ToolChains/MinGW.cpp | 11 +-- clang/test/Driver/mingw-msvcrt.c | 8 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 7d093d20b3dd9..58c59aa7f2237 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -85,11 +85,18 @@ void tools::MinGW::Linker::AddLibGCC(const ArgList &Args, CmdArgs.push_back("-lmoldname"); CmdArgs.push_back("-lmingwex"); - for (auto Lib : Args.getAllArgValues(options::OPT_l)) + for (auto Lib : Args.getAllArgValues(options::OPT_l)) { if (StringRef(Lib).starts_with("msvcr") || StringRef(Lib).starts_with("ucrt") || -StringRef(Lib).starts_with("crtdll")) +StringRef(Lib).starts_with("crtdll")) { + Lib = (llvm::Twine("-l") + Lib).str(); + // Respect the user's chosen crt variant, but still provide it + // again as the last linker argument, because some of the libraries + // we added above may depend on it. + CmdArgs.push_back(Args.MakeArgStringRef(Lib)); return; +} + } CmdArgs.push_back("-lmsvcrt"); } diff --git a/clang/test/Driver/mingw-msvcrt.c b/clang/test/Driver/mingw-msvcrt.c index 340ce1f57b0f8..e1648630476a0 100644 --- a/
[clang] [Driver][MinGW] Always put libc argument last, even if non-standard (PR #149434)
Keno wrote: > why not use lld? It's how the toolchain happens to be configured, and we can't tell users of clang that they need to use lld if they want their builds to work, especially if they work fine with gcc. https://github.com/llvm/llvm-project/pull/149434 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Driver][MinGW] Always put libc argument last, even if non-standard (PR #149434)
https://github.com/Keno closed https://github.com/llvm/llvm-project/pull/149434 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits