[cfe-commits] r151029 - in /cfe/trunk: lib/AST/Decl.cpp lib/AST/ExprCXX.cpp lib/AST/ItaniumMangle.cpp lib/Sema/SemaLambda.cpp test/CodeGenCXX/lambda-expressions.cpp test/CodeGenCXX/mangle-lambdas.cpp

Douglas Gregor dgregor at apple.com
Mon Feb 20 20:17:39 PST 2012


Author: dgregor
Date: Mon Feb 20 22:17:39 2012
New Revision: 151029

URL: http://llvm.org/viewvc/llvm-project?rev=151029&view=rev
Log:
Implement non-internal linkage for lambda closure types that need a
stable mangling, since these lambdas can end up in multiple
translation units. Sema is responsible for deciding when this is the
case, because it's already responsible for choosing the mangling
number.


Modified:
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp
    cfe/trunk/test/CodeGenCXX/mangle-lambdas.cpp

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=151029&r1=151028&r2=151029&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Mon Feb 20 22:17:39 2012
@@ -734,6 +734,32 @@
     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.

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=151029&r1=151028&r2=151029&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Mon Feb 20 22:17:39 2012
@@ -815,7 +815,10 @@
     memcpy(getArrayIndexStarts(), ArrayIndexStarts.data(), 
            sizeof(unsigned) * Captures.size());
     getArrayIndexStarts()[Captures.size()] = ArrayIndexVars.size();
-  }  
+  }
+  
+  if (ManglingNumber)
+    Class->ClearLinkageCache();
 }
 
 LambdaExpr *LambdaExpr::Create(ASTContext &Context, 

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=151029&r1=151028&r2=151029&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Mon Feb 20 22:17:39 2012
@@ -52,7 +52,7 @@
   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 @@
     // <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 @@
   // (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 << '_';  
 }
 

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=151029&r1=151028&r2=151029&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Mon Feb 20 22:17:39 2012
@@ -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 @@
   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 @@
     enum ContextKind {
       Normal,
       DefaultArgument,
-      DataMember
+      DataMember,
+      StaticDataMember,
     } Kind = Normal;
 
     // Default arguments of member function parameters that appear in a class
@@ -658,7 +674,7 @@
             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 @@
     
     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;

Modified: cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp?rev=151029&r1=151028&r2=151029&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp Mon Feb 20 22:17:39 2012
@@ -8,8 +8,8 @@
 
 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 @@
 // 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 @@
 // 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 @@
 // 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 @@
 // 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"

Modified: cfe/trunk/test/CodeGenCXX/mangle-lambdas.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-lambdas.cpp?rev=151029&r1=151028&r2=151029&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mangle-lambdas.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/mangle-lambdas.cpp Mon Feb 20 22:17:39 2012
@@ -14,7 +14,7 @@
   // 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 @@
   // 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 @@
   // 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 @@
 // 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 @@
   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





More information about the cfe-commits mailing list