]> granicus.if.org Git - clang/commitdiff
Implement name mangling for lambda expressions that occur within the
authorDouglas Gregor <dgregor@apple.com>
Tue, 21 Feb 2012 02:22:07 +0000 (02:22 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 21 Feb 2012 02:22:07 +0000 (02:22 +0000)
initializers of data members (both static and non-static).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151017 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Parse/Parser.h
lib/AST/ItaniumMangle.cpp
lib/Parse/ParseCXXInlineMethods.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaLambda.cpp
test/CodeGenCXX/mangle-lambdas.cpp

index a13b48a420ac13f567e209a717a120194468b8c8..242ef3857c7c50abbdd3000c25080a757b9ec7ab 100644 (file)
@@ -2063,7 +2063,7 @@ private:
                            bool SuppressDeclarations = false);
   void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
                                    Decl *TagDecl);
-  ExprResult ParseCXXMemberInitializer(bool IsFunction,
+  ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction,
                                        SourceLocation &EqualLoc);
   void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr,
                 const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
index 93ebcc50cf2157dc20cee911c6132373b0103a25..47f50cf078e54e3532391f37ec1310dde3fa53b5 100644 (file)
@@ -1313,9 +1313,26 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
 }
 
 void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
-  // FIXME: Figure out if we're in a function body, default argument,
-  // or initializer for a class member.
-  
+  // If the context of a closure type is an initializer for a class member 
+  // (static or nonstatic), it is encoded in a qualified name with a final 
+  // <prefix> of the form:
+  //
+  //   <data-member-prefix> := <member source-name> M
+  //
+  // Technically, the data-member-prefix is part of the <prefix>. However,
+  // since a closure type will always be mangled with a prefix, it's easier
+  // to emit that last part of the prefix here.
+  if (Decl *Context = Lambda->getLambdaContextDecl()) {
+    if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
+        Context->getDeclContext()->isRecord()) {
+      if (const IdentifierInfo *Name
+            = cast<NamedDecl>(Context)->getIdentifier()) {
+        mangleSourceName(Name);
+        Out << 'M';            
+      }
+    }
+  }
+
   Out << "Ul";
   DeclarationName Name
     = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
@@ -1392,26 +1409,27 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
     return;
   }
   
-  if (mangleSubstitution(cast<NamedDecl>(DC)))
+  const NamedDecl *ND = cast<NamedDecl>(DC);  
+  if (mangleSubstitution(ND))
     return;
-
+  
   // Check if we have a template.
   const TemplateArgumentList *TemplateArgs = 0;
-  if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
+  if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
     mangleTemplatePrefix(TD);
     TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
     mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
   }
-  else if(NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)))
+  else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND)))
     return;
-  else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC))
+  else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
     mangleObjCMethodName(Method);
   else {
-    manglePrefix(getEffectiveParentContext(DC), NoFunction);
-    mangleUnqualifiedName(cast<NamedDecl>(DC));
+    manglePrefix(getEffectiveDeclContext(ND), NoFunction);
+    mangleUnqualifiedName(ND);
   }
 
-  addSubstitution(cast<NamedDecl>(DC));
+  addSubstitution(ND);
 }
 
 void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
index 8ed058787e469a20f61636edce280cccddc805bd..1294a4c79aab5ccb55f88a38c2ba1a3d8b84b6df 100644 (file)
@@ -478,7 +478,8 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
   ConsumeAnyToken();
 
   SourceLocation EqualLoc;
-  ExprResult Init = ParseCXXMemberInitializer(/*IsFunction=*/false, EqualLoc);
+  ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false, 
+                                              EqualLoc);
 
   Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release());
 
index 6213824cae3aa2dd2ecb281685dfb4b64e51c60c..5edc30be92b4fa36b572de11ee4831a4aafa5e1b 100644 (file)
@@ -2000,7 +2000,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
     } else if (HasInitializer) {
       // Normal initializer.
       if (!Init.isUsable())
-        Init = ParseCXXMemberInitializer(
+        Init = ParseCXXMemberInitializer(ThisDecl,
                  DeclaratorInfo.isDeclarationOfFunction(), EqualLoc);
       
       if (Init.isInvalid())
@@ -2096,11 +2096,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
 ///
 /// Prior to C++0x, the assignment-expression in an initializer-clause must
 /// be a constant-expression.
-ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction,
+ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
                                              SourceLocation &EqualLoc) {
   assert((Tok.is(tok::equal) || Tok.is(tok::l_brace))
          && "Data member initializer not starting with '=' or '{'");
 
+  EnterExpressionEvaluationContext Context(Actions, 
+                                           Sema::PotentiallyEvaluated,
+                                           D);
   if (Tok.is(tok::equal)) {
     EqualLoc = ConsumeToken();
     if (Tok.is(tok::kw_delete)) {
index faf2c41853b9ebbaf8553792ad33bb134c12f8d7..a1a952b833f01b3291bc7e912b572fc60882cef4 100644 (file)
@@ -10394,6 +10394,14 @@ bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) {
   return true;
 }
 
+/// \brief Determine whether the given declaration is a static data member.
+static bool isStaticDataMember(Decl *D) {
+  VarDecl *Var = dyn_cast_or_null<VarDecl>(D);
+  if (!Var)
+    return false;
+  
+  return Var->isStaticDataMember();
+}
 /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse
 /// an initializer for the out-of-line declaration 'Dcl'.  The scope
 /// is a fresh scope pushed for just this purpose.
@@ -10409,6 +10417,12 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
   //   int foo::bar;
   assert(D->isOutOfLine());
   EnterDeclaratorContext(S, D->getDeclContext());
+  
+  // If we are parsing the initializer for a static data member, push a
+  // new expression evaluation context that is associated with this static
+  // data member.
+  if (isStaticDataMember(D))
+    PushExpressionEvaluationContext(PotentiallyEvaluated, D);
 }
 
 /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an
@@ -10417,6 +10431,9 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
   // If there is no declaration, there was an error parsing it.
   if (D == 0 || D->isInvalidDecl()) return;
 
+  if (isStaticDataMember(D))
+    PopExpressionEvaluationContext();  
+
   assert(D->isOutOfLine());
   ExitDeclaratorContext(S);
 }
index 047a28436f6f27d5d858ad68cc381d4d27f75d50..7b729e70181eabfc1b62c2e354162f6b718004a8 100644 (file)
@@ -641,20 +641,28 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
   if (!ManglingNumber) {
     ContextDecl = ExprEvalContexts.back().LambdaContextDecl;
     
-    // FIXME: Data member initializers.
     enum ContextKind {
       Normal,
-      DefaultArgument
+      DefaultArgument,
+      DataMember
     } Kind = Normal;
 
     // Default arguments of member function parameters that appear in a class
-    // definition receive special treatment. Identify them.
-    if (ParmVarDecl *Param = dyn_cast_or_null<ParmVarDecl>(ContextDecl)) {
-      if (const DeclContext *LexicalDC
-            = Param->getDeclContext()->getLexicalParent())
-        if (LexicalDC->isRecord())
-          Kind = DefaultArgument;
-    }
+    // definition, as well as the initializers of data members, receive special
+    // treatment. Identify them.
+    if (ContextDecl) {
+      if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ContextDecl)) {
+        if (const DeclContext *LexicalDC
+              = Param->getDeclContext()->getLexicalParent())
+          if (LexicalDC->isRecord())
+            Kind = DefaultArgument;
+      } else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) {
+        if (Var->getDeclContext()->isRecord())
+          Kind = DataMember;
+      } else if (isa<FieldDecl>(ContextDecl)) {
+        Kind = DataMember;
+      }
+    }        
     
     switch (Kind) {
     case Normal:
@@ -663,6 +671,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
       break;
       
     case DefaultArgument:
+    case DataMember:
       ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
                          .getManglingNumber(CallOperator);
       break;
index de8360d730e9045b0818044fb1356ff809bc8dd3..a4fb7cdc846e47d3893c2d6b988237f126de8091 100644 (file)
@@ -75,3 +75,50 @@ void test_ST(ST<double> st) {
 
   // CHECK-NEXT: ret void
 }
+
+template<typename T> 
+struct StaticMembers {
+  static T x;
+  static T y;
+  static T z;
+};
+
+template<typename T> int accept_lambda(T);
+
+template<typename T>
+T StaticMembers<T>::x = []{return 1;}() + []{return 2;}();
+
+template<typename T>
+T StaticMembers<T>::y = []{return 3;}();
+
+template<typename T>
+T StaticMembers<T>::z = accept_lambda([]{return 4;});
+
+// CHECK: define internal void @__cxx_global_var_init()
+// CHECK: call i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv
+// CHECK-NEXT: call i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv
+// CHECK-NEXT: add nsw
+template float StaticMembers<float>::x;
+
+// CHECK: define internal void @__cxx_global_var_init1()
+// CHECK: call i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv
+template float StaticMembers<float>::y;
+
+// CHECK: define internal void @__cxx_global_var_init2()
+// CHECK: call i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_
+template float StaticMembers<float>::z;
+
+struct Members {
+  int x = [] { return 1; }() + [] { return 2; }();
+  int y = [] { return 3; }();
+};
+
+void test_Members() {
+  // CHECK: define linkonce_odr void @_ZN7MembersC2Ev
+  // CHECK: call i32 @_ZNK7Members1xMUlvE_clEv
+  // CHECK-NEXT: call i32 @_ZNK7Members1xMUlvE0_clE
+  // CHECK-NEXT: add nsw i32
+  // CHECK: call i32 @_ZNK7Members1yMUlvE_clEv
+  Members members;
+  // CHECK: ret void
+}