diff options
-rw-r--r-- | lib/AST/Decl.cpp | 26 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 5 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 39 | ||||
-rw-r--r-- | test/CodeGenCXX/lambda-expressions.cpp | 32 | ||||
-rw-r--r-- | test/CodeGenCXX/mangle-lambdas.cpp | 68 |
6 files changed, 151 insertions, 31 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d80e06b322..4d1b562c59 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -734,6 +734,32 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { case Decl::ObjCPropertyImpl: case Decl::ObjCProtocol: return LinkageInfo::external(); + + case Decl::CXXRecord: { + const CXXRecordDecl *Record = cast<CXXRecordDecl>(D); + if (Record->isLambda()) { + if (!Record->getLambdaManglingNumber()) { + // This lambda has no mangling number, so it's internal. + return LinkageInfo::internal(); + } + + // This lambda has its linkage/visibility determined by its owner. + const DeclContext *DC = D->getDeclContext()->getRedeclContext(); + if (Decl *ContextDecl = Record->getLambdaContextDecl()) { + if (isa<ParmVarDecl>(ContextDecl)) + DC = ContextDecl->getDeclContext()->getRedeclContext(); + else + return getLVForDecl(cast<NamedDecl>(ContextDecl), Flags); + } + + if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC)) + return getLVForDecl(ND, Flags); + + return LinkageInfo::external(); + } + + break; + } } // Handle linkage for namespace-scope names. diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 98664b2a7c..7ef3417e6d 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -815,7 +815,10 @@ LambdaExpr::LambdaExpr(QualType T, memcpy(getArrayIndexStarts(), ArrayIndexStarts.data(), sizeof(unsigned) * Captures.size()); getArrayIndexStarts()[Captures.size()] = ArrayIndexVars.size(); - } + } + + if (ManglingNumber) + Class->ClearLinkageCache(); } LambdaExpr *LambdaExpr::Create(ASTContext &Context, diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 47f50cf078..5e167f58dc 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -52,7 +52,7 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { if (RD->isLambda()) if (ParmVarDecl *ContextParam - = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) + = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) return ContextParam->getDeclContext(); } @@ -1114,7 +1114,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'. if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) { - if (Record->isLambda()) { + if (Record->isLambda() && Record->getLambdaManglingNumber()) { mangleLambda(Record); break; } @@ -1347,10 +1347,10 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { // (in lexical order) with that same <lambda-sig> and context. // // The AST keeps track of the number for us. - if (unsigned Number = Lambda->getLambdaManglingNumber()) { - if (Number > 1) - mangleNumber(Number - 2); - } + unsigned Number = Lambda->getLambdaManglingNumber(); + assert(Number > 0 && "Lambda should be mangled as an unnamed class"); + if (Number > 1) + mangleNumber(Number - 2); Out << '_'; } diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 7b729e7018..867049d456 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -13,6 +13,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Lex/Preprocessor.h" @@ -482,6 +483,20 @@ static void addBlockPointerConversion(Sema &S, Class->addDecl(Conversion); } +/// \brief Determine whether the given context is or is enclosed in an inline +/// function. +static bool isInInlineFunction(const DeclContext *DC) { + while (!DC->isFileContext()) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) + if (FD->isInlined()) + return true; + + DC = DC->getLexicalParent(); + } + + return false; +} + ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope, llvm::Optional<unsigned> ManglingNumber, @@ -644,7 +659,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, enum ContextKind { Normal, DefaultArgument, - DataMember + DataMember, + StaticDataMember, } Kind = Normal; // Default arguments of member function parameters that appear in a class @@ -658,7 +674,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Kind = DefaultArgument; } else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) { if (Var->getDeclContext()->isRecord()) - Kind = DataMember; + Kind = StaticDataMember; } else if (isa<FieldDecl>(ContextDecl)) { Kind = DataMember; } @@ -666,12 +682,25 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, switch (Kind) { case Normal: - ManglingNumber = Context.getLambdaManglingNumber(CallOperator); - ContextDecl = 0; + if (CurContext->isDependentContext() || isInInlineFunction(CurContext)) + ManglingNumber = Context.getLambdaManglingNumber(CallOperator); + else + ManglingNumber = 0; + + // There is no special context for this lambda. + ContextDecl = 0; break; - case DefaultArgument: + case StaticDataMember: + if (!CurContext->isDependentContext()) { + ManglingNumber = 0; + ContextDecl = 0; + break; + } + // Fall through to assign a mangling number. + case DataMember: + case DefaultArgument: ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext() .getManglingNumber(CallOperator); break; diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp index 5a68e893d7..797cbf43a7 100644 --- a/test/CodeGenCXX/lambda-expressions.cpp +++ b/test/CodeGenCXX/lambda-expressions.cpp @@ -8,8 +8,8 @@ extern "C" auto cvar = []{}; int a() { return []{ return 1; }(); } // CHECK: define i32 @_Z1av -// CHECK: call i32 @_ZZ1avENKUlvE_clEv -// CHECK: define internal i32 @_ZZ1avENKUlvE_clEv +// CHECK: call i32 @"_ZZ1avENK3$_0clEv" +// CHECK: define internal i32 @"_ZZ1avENK3$_0clEv" // CHECK: ret i32 1 int b(int x) { return [x]{return x;}(); } @@ -17,8 +17,8 @@ int b(int x) { return [x]{return x;}(); } // CHECK: store i32 // CHECK: load i32* // CHECK: store i32 -// CHECK: call i32 @_ZZ1biENKUlvE_clEv -// CHECK: define internal i32 @_ZZ1biENKUlvE_clEv +// CHECK: call i32 @"_ZZ1biENK3$_1clEv" +// CHECK: define internal i32 @"_ZZ1biENK3$_1clEv" // CHECK: load i32* // CHECK: ret i32 @@ -26,8 +26,8 @@ int c(int x) { return [&x]{return x;}(); } // CHECK: define i32 @_Z1ci // CHECK: store i32 // CHECK: store i32* -// CHECK: call i32 @_ZZ1ciENKUlvE_clEv -// CHECK: define internal i32 @_ZZ1ciENKUlvE_clEv +// CHECK: call i32 @"_ZZ1ciENK3$_2clEv" +// CHECK: define internal i32 @"_ZZ1ciENK3$_2clEv" // CHECK: load i32** // CHECK: load i32* // CHECK: ret i32 @@ -39,8 +39,8 @@ int d(int x) { D y[10]; [x,y] { return y[x].x; }(); } // CHECK: call void @_ZN1DC1Ev // CHECK: icmp ult i64 %{{.*}}, 10 // CHECK: call void @_ZN1DC1ERKS_ -// CHECK: call i32 @_ZZ1diENKUlvE_clEv -// CHECK: define internal i32 @_ZZ1diENKUlvE_clEv +// CHECK: call i32 @"_ZZ1diENK3$_3clEv" +// CHECK: define internal i32 @"_ZZ1diENK3$_3clEv" // CHECK: load i32* // CHECK: load i32* // CHECK: ret i32 @@ -50,29 +50,29 @@ int e(E a, E b, bool cond) { [a,b,cond](){ return (cond ? a : b).x; }(); } // CHECK: define i32 @_Z1e1ES_b // CHECK: call void @_ZN1EC1ERKS_ // CHECK: invoke void @_ZN1EC1ERKS_ -// CHECK: invoke i32 @_ZZ1e1ES_bENKUlvE_clEv -// CHECK: call void @_ZZ1e1ES_bENUlvE_D1Ev -// CHECK: call void @_ZZ1e1ES_bENUlvE_D1Ev +// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_4clEv" +// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev" +// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev" -// CHECK: define internal i32 @_ZZ1e1ES_bENKUlvE_clEv +// CHECK: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv" // CHECK: trunc i8 // CHECK: load i32* // CHECK: ret i32 void f() { // CHECK: define void @_Z1fv() - // CHECK: {{call.*@_ZZ1fvENKUliiE_cvPFiiiEEv}} + // CHECK: @"_ZZ1fvENK3$_5cvPFiiiEEv" // CHECK-NEXT: store i32 (i32, i32)* // CHECK-NEXT: ret void int (*fp)(int, int) = [](int x, int y){ return x + y; }; } -// CHECK: define internal i32 @_ZZ1fvENUliiE_8__invokeEii +// CHECK: define internal i32 @"_ZZ1fvEN3$_58__invokeEii" // CHECK: store i32 // CHECK-NEXT: store i32 // CHECK-NEXT: load i32* // CHECK-NEXT: load i32* -// CHECK-NEXT: call i32 @_ZZ1fvENKUliiE_clEii +// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_5clEii" // CHECK-NEXT: ret i32 -// CHECK: define internal void @_ZZ1e1ES_bENUlvE_D2Ev +// CHECK: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev" diff --git a/test/CodeGenCXX/mangle-lambdas.cpp b/test/CodeGenCXX/mangle-lambdas.cpp index a4fb7cdc84..e8bd6ec47b 100644 --- a/test/CodeGenCXX/mangle-lambdas.cpp +++ b/test/CodeGenCXX/mangle-lambdas.cpp @@ -14,7 +14,7 @@ inline void inline_func(int n) { // CHECK: call i32 @_ZZ11inline_funciENKUliE_clEi int l = [=] (int x) -> int { return x + i; }(n); - int inner(int i = []{ return 1; }()); + int inner(int i = []{ return 17; }()); // CHECK: call i32 @_ZZ11inline_funciENKUlvE2_clEv // CHECK-NEXT: call i32 @_Z5inneri inner(); @@ -49,14 +49,26 @@ void test_S(S s) { // the lambdas in the default arguments of g() won't be seen by // multiple translation units. We check them mainly to ensure that they don't // get the special mangling for lambdas in in-class default arguments. - // CHECK: call i32 @_ZNK1SUlvE_clEv - // CHECK-NEXT: call i32 @_ZNK1SUlvE0_clEv + // CHECK: call i32 @"_ZNK1S3$_0clEv" + // CHECK-NEXT: call i32 @"_ZNK1S3$_1clEv" // CHECK-NEXT: call void @_ZN1S1gEi s.g(); // CHECK-NEXT: ret void } +// Check the linkage of the lambda call operators used in test_S. +// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv +// CHECK: ret i32 1 +// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv +// CHECK: ret i32 2 +// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd_NKUlvE_clEv +// CHECK: ret i32 3 +// CHECK: define internal i32 @"_ZNK1S3$_0clEv" +// CHECK: ret i32 1 +// CHECK: define internal i32 @"_ZNK1S3$_1clEv" +// CHECK: ret i32 2 + template<typename T> struct ST { void f(T = []{return T() + 1;}() @@ -76,6 +88,14 @@ void test_ST(ST<double> st) { // CHECK-NEXT: ret void } +// Check the linkage of the lambda call operators used in test_ST. +// CHECK: define linkonce_odr double @_ZZN2ST1fET_S0_Ed0_NKUlvE_clEv +// CHECK: ret double 1 +// CHECK: define linkonce_odr double @_ZZN2ST1fET_S0_Ed0_NKUlvE0_clEv +// CHECK: ret double 2 +// CHECK: define linkonce_odr double @_ZZN2ST1fET_S0_Ed_NKUlvE_clEv +// CHECK: ret double 3 + template<typename T> struct StaticMembers { static T x; @@ -98,16 +118,38 @@ T StaticMembers<T>::z = accept_lambda([]{return 4;}); // CHECK: call i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv // CHECK-NEXT: call i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv // CHECK-NEXT: add nsw +// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv +// CHECK: ret i32 1 +// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv +// CHECK: ret i32 2 template float StaticMembers<float>::x; // CHECK: define internal void @__cxx_global_var_init1() // CHECK: call i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv +// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv +// CHECK: ret i32 3 template float StaticMembers<float>::y; // CHECK: define internal void @__cxx_global_var_init2() // CHECK: call i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_ +// CHECK: declare i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_() template float StaticMembers<float>::z; +// CHECK: define internal void @__cxx_global_var_init3 +// CHECK: call i32 @"_ZNK13StaticMembersIdE3$_2clEv" +// CHECK: define internal i32 @"_ZNK13StaticMembersIdE3$_2clEv" +// CHECK: ret i32 42 +template<> double StaticMembers<double>::z = []{return 42; }(); + +template<typename T> +void func_template(T = []{ return T(); }()); + +// CHECK: define void @_Z17use_func_templatev() +void use_func_template() { + // CHECK: call i32 @"_ZZ13func_templateIiEvT_ENKS_IiE3$_3clEv" + func_template<int>(); +} + struct Members { int x = [] { return 1; }() + [] { return 2; }(); int y = [] { return 3; }(); @@ -122,3 +164,23 @@ void test_Members() { Members members; // CHECK: ret void } + +// Check the linkage of the lambdas used in test_Members. +// CHECK: define linkonce_odr i32 @_ZNK7Members1xMUlvE_clEv +// CHECK: ret i32 1 +// CHECK: define linkonce_odr i32 @_ZNK7Members1xMUlvE0_clEv +// CHECK: ret i32 2 +// CHECK: define linkonce_odr i32 @_ZNK7Members1yMUlvE_clEv +// CHECK: ret i32 3 + +// Check linkage of the various lambdas. +// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE_clEv +// CHECK: ret i32 1 +// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE0_clEv +// CHECK: ret i32 +// CHECK: define linkonce_odr double @_ZZ11inline_funciENKUlvE1_clEv +// CHECK: ret double +// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUliE_clEi +// CHECK: ret i32 +// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE2_clEv +// CHECK: ret i32 17 |