aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/Decl.cpp26
-rw-r--r--lib/AST/ExprCXX.cpp5
-rw-r--r--lib/AST/ItaniumMangle.cpp12
-rw-r--r--lib/Sema/SemaLambda.cpp39
-rw-r--r--test/CodeGenCXX/lambda-expressions.cpp32
-rw-r--r--test/CodeGenCXX/mangle-lambdas.cpp68
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