WIP Patch: Introduce a proper mangling scheme for block literals

Eli Friedman eli.friedman at gmail.com
Fri Jun 21 18:19:55 PDT 2013


On Tue, Jun 18, 2013 at 6:41 PM, John McCall <rjmccall at apple.com> wrote:

> On Jun 12, 2013, at 4:42 PM, Eli Friedman <eli.friedman at gmail.com> wrote:
>
> Take a C++ function like the following:
>
> inline void f() {
>   ^{
>     static int i = 0;
>     printf("%d\n", ++i);
>   }();
> }
>
> Looks pretty simple, right?  Unfortunately, trunk clang doesn't handle
> this correctly.  The primary issue here is we haven't defined the correct
> way to mangle the name of "i", and clang's current scheme is unusable
> because it depends on the details of IRGen.  (There's also the matter that
> we don't compute the linkage correctly, but that's a simple IRGen bug.)
>
> I'm attaching a patch which expands the scheme we use for mangling lambda
> expressions in this sort of context to also work for block literals.  The
> patch is still a bit of a mess: there's a bunch of copy-paste code I still
> need to clean up, I haven't included tests, and it would probably be nice
> to include the parameter types of the block in the mangling.  That said, it
> essentially implements everything necessary.
>
>
> Unlike lambdas, we never actually need to mangle a block declaration;  we
> just encounter it as a context for local statics and types.  And much like
> we do with lambdas, we should just ignore the block as a context and mangle
> the static/type as a local declaration within the actual enclosing
> declaration.
>

We discussed this in person; basically, we do in fact mangle lambdas into
the context.


> Note that this doesn't touch the mangling scheme for the actual function
> definitions for blocks; they don't need to be externally visible, so we
> don't need to change the current mangling.
>
> I'd like some feedback to make sure my patch is actually implementing
> something sane.
>
>
> Other than the mangling scheme, this seems reasonable.
>
> Any suggestions for a better name than LambdaBlockMangleContext are also
> welcome.
>
>
> How about ClosureOwningContext?
>

I ended up choosing MangleNumberingContext, given that we might need to add
more to it in the future (e.g. static local variables).

Attaching updated patch; this fixes some details like avoiding some of the
code duplication, fixing the mangling so it makes a bit more sense, and
includes some fixes to make our linkage computations for static local
variables a bit more accurate.

-Eli
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130621/57891b1b/attachment.html>
-------------- next part --------------
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h	(revision 184607)
+++ include/clang/AST/ASTContext.h	(working copy)
@@ -19,7 +19,7 @@
 #include "clang/AST/CanonicalType.h"
 #include "clang/AST/CommentCommandTraits.h"
 #include "clang/AST/Decl.h"
-#include "clang/AST/LambdaMangleContext.h"
+#include "clang/AST/MangleNumberingContext.h"
 #include "clang/AST/NestedNameSpecifier.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/RawCommentList.h"
@@ -337,9 +337,11 @@
   typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector;
   llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
 
-  /// \brief Mapping from each declaration context to its corresponding lambda 
-  /// mangling context.
-  llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
+  /// \brief Mapping from each declaration context to its corresponding
+  /// mangling numbering context (used for constructs like lambdas which
+  /// need to be consistently numbered for the mangler).
+  llvm::DenseMap<const DeclContext *, MangleNumberingContext>
+      MangleNumberingContexts;
 
   llvm::DenseMap<const DeclContext *, unsigned> UnnamedMangleContexts;
   llvm::DenseMap<const TagDecl *, unsigned> UnnamedMangleNumbers;
@@ -2104,9 +2106,10 @@
   void addUnnamedTag(const TagDecl *Tag);
   int getUnnamedTagManglingNumber(const TagDecl *Tag) const;
 
-  /// \brief Retrieve the lambda mangling number for a lambda expression.
-  unsigned getLambdaManglingNumber(CXXMethodDecl *CallOperator);
-  
+  /// \brief Retrieve the context for computing mangling numbers in the given
+  /// DeclContext.
+  MangleNumberingContext &getManglingNumberContext(DeclContext *DC);
+
   /// \brief Used by ParmVarDecl to store on the side the
   /// index of the parameter when it exceeds the size of the normal bitfield.
   void setParameterIndex(const ParmVarDecl *D, unsigned index);
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h	(revision 184607)
+++ include/clang/AST/Decl.h	(working copy)
@@ -3137,13 +3137,17 @@
   Capture *Captures;
   unsigned NumCaptures;
 
+  unsigned ManglingNumber;
+  Decl *ManglingContextDecl;
+
 protected:
   BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
     : Decl(Block, DC, CaretLoc), DeclContext(Block),
       IsVariadic(false), CapturesCXXThis(false),
       BlockMissingReturnType(true), IsConversionFromLambda(false),
       ParamInfo(0), NumParams(0), Body(0),
-      SignatureAsWritten(0), Captures(0), NumCaptures(0) {}
+      SignatureAsWritten(0), Captures(0), NumCaptures(0),
+      ManglingNumber(0), ManglingContextDecl(0) {}
 
 public:
   static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); 
@@ -3213,6 +3217,18 @@
                    const Capture *end,
                    bool capturesCXXThis);
 
+   unsigned getBlockManglingNumber() const {
+     return ManglingNumber;
+   }
+   Decl *getBlockManglingContextDecl() const {
+     return ManglingContextDecl;    
+   }
+
+  void setBlockMangling(unsigned Number, Decl *Ctx) {
+    ManglingNumber = Number;
+    ManglingContextDecl = Ctx;
+  }
+
   virtual SourceRange getSourceRange() const LLVM_READONLY;
 
   // Implement isa/cast/dyncast/etc.
Index: include/clang/AST/LambdaMangleContext.h
===================================================================
--- include/clang/AST/LambdaMangleContext.h	(revision 184607)
+++ include/clang/AST/LambdaMangleContext.h	(working copy)
@@ -1,38 +0,0 @@
-//===--- LambdaMangleContext.h - Context for mangling lambdas ---*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-//  This file defines the LambdaMangleContext interface, which keeps track of
-//  the Itanium C++ ABI mangling numbers for lambda expressions.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LAMBDAMANGLECONTEXT_H
-#define LLVM_CLANG_LAMBDAMANGLECONTEXT_H
-
-#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
-
-namespace clang {
-
-class CXXMethodDecl;
-class FunctionProtoType;
-
-/// \brief Keeps track of the mangled names of lambda expressions within a
-/// particular context.
-class LambdaMangleContext : public RefCountedBase<LambdaMangleContext> {
-  llvm::DenseMap<const FunctionProtoType *, unsigned> ManglingNumbers;
-  
-public:
-  /// \brief Retrieve the mangling number of a new lambda expression with the
-  /// given call operator within this lambda context.
-  unsigned getManglingNumber(CXXMethodDecl *CallOperator);
-};
-  
-} // end namespace clang
-#endif
Index: include/clang/AST/MangleNumberingContext.h
===================================================================
--- include/clang/AST/MangleNumberingContext.h	(working copy)
+++ include/clang/AST/MangleNumberingContext.h	(working copy)
@@ -1,4 +1,4 @@
-//===--- LambdaMangleContext.h - Context for mangling lambdas ---*- C++ -*-===//
+//=== MangleNumberingContext.h - Context for mangling numbers ---*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -7,12 +7,13 @@
 //
 //===----------------------------------------------------------------------===//
 //
-//  This file defines the LambdaMangleContext interface, which keeps track of
-//  the Itanium C++ ABI mangling numbers for lambda expressions.
+//  This file defines the LambdaBlockMangleContext interface, which keeps track
+//  of the Itanium C++ ABI mangling numbers for lambda expressions and block
+//  literals.
 //
 //===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LAMBDAMANGLECONTEXT_H
-#define LLVM_CLANG_LAMBDAMANGLECONTEXT_H
+#ifndef LLVM_CLANG_MANGLENUMBERINGCONTEXT_H
+#define LLVM_CLANG_MANGLENUMBERINGCONTEXT_H
 
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/DenseMap.h"
@@ -20,18 +21,24 @@
 
 namespace clang {
 
+class BlockDecl;
 class CXXMethodDecl;
-class FunctionProtoType;
+class Type;
 
-/// \brief Keeps track of the mangled names of lambda expressions within a
-/// particular context.
-class LambdaMangleContext : public RefCountedBase<LambdaMangleContext> {
-  llvm::DenseMap<const FunctionProtoType *, unsigned> ManglingNumbers;
+/// \brief Keeps track of the mangled names of lambda expressions and block
+/// literals within a particular context.
+class MangleNumberingContext 
+    : public RefCountedBase<MangleNumberingContext> {
+  llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
   
 public:
   /// \brief Retrieve the mangling number of a new lambda expression with the
-  /// given call operator within this lambda context.
+  /// given call operator within this context.
   unsigned getManglingNumber(CXXMethodDecl *CallOperator);
+
+  /// \brief Retrieve the mangling number of a new block literal within this
+  /// context.
+  unsigned getManglingNumber(BlockDecl *BD);
 };
   
 } // end namespace clang
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h	(revision 184607)
+++ include/clang/Sema/Sema.h	(working copy)
@@ -20,7 +20,7 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/ExternalASTSource.h"
-#include "clang/AST/LambdaMangleContext.h"
+#include "clang/AST/MangleNumberingContext.h"
 #include "clang/AST/NSAPI.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/TypeLoc.h"
@@ -662,17 +662,17 @@
     /// is indeed an unevaluated context.
     SmallVector<LambdaExpr *, 2> Lambdas;
 
-    /// \brief The declaration that provides context for the lambda expression
-    /// if the normal declaration context does not suffice, e.g., in a
-    /// default function argument.
-    Decl *LambdaContextDecl;
+    /// \brief The declaration that provides context for lambda expressions
+    /// and block literals if the normal declaration context does not
+    /// suffice, e.g., in a default function argument.
+    Decl *ManglingContextDecl;
 
     /// \brief The context information used to mangle lambda expressions
-    /// within this context.
+    /// and block literals within this context.
     ///
     /// This mangling information is allocated lazily, since most contexts
-    /// do not have lambda expressions.
-    IntrusiveRefCntPtr<LambdaMangleContext> LambdaMangle;
+    /// do not have lambda expressions or block literals.
+    IntrusiveRefCntPtr<MangleNumberingContext> MangleNumbering;
 
     /// \brief If we are processing a decltype type, a set of call expressions
     /// for which we have deferred checking the completeness of the return type.
@@ -685,18 +685,19 @@
     ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
                                       unsigned NumCleanupObjects,
                                       bool ParentNeedsCleanups,
-                                      Decl *LambdaContextDecl,
+                                      Decl *ManglingContextDecl,
                                       bool IsDecltype)
       : Context(Context), ParentNeedsCleanups(ParentNeedsCleanups),
         IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects),
-        LambdaContextDecl(LambdaContextDecl), LambdaMangle() { }
+        ManglingContextDecl(ManglingContextDecl), MangleNumbering() { }
 
-    /// \brief Retrieve the mangling context for lambdas.
-    LambdaMangleContext &getLambdaMangleContext() {
-      assert(LambdaContextDecl && "Need to have a lambda context declaration");
-      if (!LambdaMangle)
-        LambdaMangle = new LambdaMangleContext;
-      return *LambdaMangle;
+    /// \brief Retrieve the mangling numbering context, used to consistently
+    /// number constructs like lambdas for mangling.
+    MangleNumberingContext &getMangleNumberingContext() {
+      assert(ManglingContextDecl && "Need to have a context declaration");
+      if (!MangleNumbering)
+        MangleNumbering = new MangleNumberingContext;
+      return *MangleNumbering;
     }
 
     bool isUnevaluated() const {
@@ -707,6 +708,18 @@
   /// A stack of expression evaluation contexts.
   SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
 
+  /// \brief Compute the mangling number context for a lambda expression or
+  /// block literal.
+  ///
+  /// \param DC - The DeclContext containing the lambda expression or
+  /// block literal.
+  /// \param[out] ManglingContextDecl - Returns the ManglingContextDecl
+  /// associated with the context, if relevant.
+  MangleNumberingContext *getCurrentMangleNumberContext(
+    DeclContext *DC,
+    Decl *&ManglingContextDecl);
+
+
   /// SpecialMemberOverloadResult - The overloading result for a special member
   /// function.
   ///
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp	(revision 184607)
+++ lib/AST/ASTContext.cpp	(working copy)
@@ -8017,13 +8017,10 @@
   return I != UnnamedMangleNumbers.end() ? I->second : -1;
 }
 
-unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) {
-  CXXRecordDecl *Lambda = CallOperator->getParent();
-  return LambdaMangleContexts[Lambda->getDeclContext()]
-           .getManglingNumber(CallOperator);
+MangleNumberingContext &ASTContext::getManglingNumberContext(DeclContext *DC) {
+  return MangleNumberingContexts[DC];
 }
 
-
 void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) {
   ParamIndices[D] = index;
 }
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp	(revision 184607)
+++ lib/AST/Decl.cpp	(working copy)
@@ -287,13 +287,12 @@
 static LinkageInfo getLVForDecl(const NamedDecl *D,
                                 LVComputationKind computation);
 
-static const FunctionDecl *getOutermostFunctionContext(const Decl *D) {
-  const FunctionDecl *Ret = NULL;
+static const Decl *getOutermostFuncOrBlockContext(const Decl *D) {
+  const Decl *Ret = NULL;
   const DeclContext *DC = D->getDeclContext();
   while (DC->getDeclKind() != Decl::TranslationUnit) {
-    const FunctionDecl *F = dyn_cast<FunctionDecl>(DC);
-    if (F)
-      Ret = F;
+    if (isa<FunctionDecl>(DC) || isa<BlockDecl>(DC))
+      Ret = cast<Decl>(DC);
     DC = DC->getParent();
   }
   return Ret;
@@ -996,6 +995,22 @@
   return None;
 }
 
+static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl,
+                                   LVComputationKind computation) {
+  // This lambda has its linkage/visibility determined by its owner.
+  if (ContextDecl) {
+    if (isa<ParmVarDecl>(ContextDecl))
+      DC = ContextDecl->getDeclContext()->getRedeclContext();
+    else
+      return getLVForDecl(cast<NamedDecl>(ContextDecl), computation);
+  }
+
+  if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
+    return getLVForDecl(ND, computation);
+
+  return LinkageInfo::external();
+}
+
 static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
                                      LVComputationKind computation) {
   if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
@@ -1052,14 +1067,25 @@
   if (!Context.getLangOpts().CPlusPlus)
     return LinkageInfo::none();
 
-  const FunctionDecl *FD = getOutermostFunctionContext(D);
-  if (!FD)
+  const Decl *OuterD = getOutermostFuncOrBlockContext(D);
+  if (!OuterD)
     return LinkageInfo::none();
 
-  if (!FD->isInlined() && FD->getTemplateSpecializationKind() == TSK_Undeclared)
-    return LinkageInfo::none();
+  LinkageInfo LV;
+  if (const BlockDecl *BD = dyn_cast<BlockDecl>(OuterD)) {
+    if (!BD->getBlockManglingNumber())
+      return LinkageInfo::none();
 
-  LinkageInfo LV = getLVForDecl(FD, computation);
+    LV = getLVForClosure(BD->getDeclContext()->getRedeclContext(),
+                         BD->getBlockManglingContextDecl(), computation);
+  } else {
+    const FunctionDecl *FD = cast<FunctionDecl>(OuterD);
+    if (!FD->isInlined() &&
+        FD->getTemplateSpecializationKind() == TSK_Undeclared)
+      return LinkageInfo::none();
+
+    LV = getLVForDecl(FD, computation);
+  }
   if (!isExternallyVisible(LV.getLinkage()))
     return LinkageInfo::none();
   return LinkageInfo(VisibleNoLinkage, LV.getVisibility(),
@@ -1095,20 +1121,10 @@
           // 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), computation);
-        }
-
-        if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
-          return getLVForDecl(ND, computation);
-        
-        return LinkageInfo::external();
+        return getLVForClosure(D->getDeclContext()->getRedeclContext(),
+                               Record->getLambdaContextDecl(), computation);
       }
       
       break;
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp	(revision 184607)
+++ lib/AST/ItaniumMangle.cpp	(working copy)
@@ -1415,12 +1415,24 @@
     return;
 
   if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) {
-    manglePrefix(getEffectiveParentContext(DC), NoFunction);    
-    SmallString<64> Name;
-    llvm::raw_svector_ostream NameStream(Name);
-    Context.mangleBlock(Block, NameStream);
-    NameStream.flush();
-    Out << Name.size() << Name;
+    manglePrefix(getEffectiveParentContext(DC), NoFunction);
+    if (unsigned Number = Block->getBlockManglingNumber()) {
+      // If we have a mangling number, add a prefix for the block.
+      SmallString<16> BlockPrefix;
+      BlockPrefix += "__block_prefix";
+      if (Number > 1)
+        BlockPrefix += llvm::utostr_32(Number - 2);
+      Out << BlockPrefix.size() << BlockPrefix;
+      return;
+    }
+    // Otherwise, the symbol we're adding a prefix for isn't externally
+    // visible; make up something sane.
+    SmallString<16> BlockPrefix;
+    BlockPrefix += "__block_prefix_internal";
+    unsigned Number = Context.getBlockId(Block, false);
+    if (Number > 1)
+      BlockPrefix += llvm::utostr_32(Number - 2);
+    Out << BlockPrefix.size() << BlockPrefix;
     return;
   } else if (isa<CapturedDecl>(DC)) {
     // Skip CapturedDecl context.
Index: lib/AST/LambdaMangleContext.cpp
===================================================================
--- lib/AST/LambdaMangleContext.cpp	(revision 184607)
+++ lib/AST/LambdaMangleContext.cpp	(working copy)
@@ -1,30 +0,0 @@
-//===--- LambdaMangleContext.cpp - Context for mangling lambdas -*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-//  This file defines the LambdaMangleContext class, which keeps track of
-//  the Itanium C++ ABI mangling numbers for lambda expressions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/LambdaMangleContext.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclCXX.h"
-
-using namespace clang;
-
-unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) {
-  const FunctionProtoType *Proto
-    = CallOperator->getType()->getAs<FunctionProtoType>();
-  ASTContext &Context = CallOperator->getASTContext();
-
-  QualType Key = Context.getFunctionType(Context.VoidTy, Proto->getArgTypes(),
-                                         FunctionProtoType::ExtProtoInfo());
-  Key = Context.getCanonicalType(Key);
-  return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
-}
Index: lib/AST/MangleNumberingContext.cpp
===================================================================
--- lib/AST/MangleNumberingContext.cpp	(working copy)
+++ lib/AST/MangleNumberingContext.cpp	(working copy)
@@ -1,4 +1,4 @@
-//===--- LambdaMangleContext.cpp - Context for mangling lambdas -*- C++ -*-===//
+//===--- MangleNumberingContext.cpp - Context for mangling numbers --------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -12,13 +12,14 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/AST/LambdaMangleContext.h"
+#include "clang/AST/MangleNumberingContext.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclCXX.h"
 
 using namespace clang;
 
-unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) {
+unsigned
+MangleNumberingContext::getManglingNumber(CXXMethodDecl *CallOperator) {
   const FunctionProtoType *Proto
     = CallOperator->getType()->getAs<FunctionProtoType>();
   ASTContext &Context = CallOperator->getASTContext();
@@ -28,3 +29,10 @@
   Key = Context.getCanonicalType(Key);
   return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
 }
+
+unsigned
+MangleNumberingContext::getManglingNumber(BlockDecl *BD) {
+  // FIXME: Compute a BlockPointerType?  Not obvious how.
+  const Type *Ty = 0;
+  return ++ManglingNumbers[Ty];
+}
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp	(revision 184607)
+++ lib/CodeGen/CGDecl.cpp	(working copy)
@@ -130,9 +130,27 @@
     if (D.isExternallyVisible()) {
       const Decl *D = CurCodeDecl;
       while (true) {
-        if (isa<BlockDecl>(D)) {
-          // FIXME: Handle this case properly!  (Should be similar to the
-          // way we handle lambdas in computeLVForDecl in Decl.cpp.)
+        if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+          if (!BD->getBlockManglingNumber())
+            break;
+
+          // This block has the linkage/visibility of its contained variables
+          // determined by its owner.
+          const DeclContext *DC = D->getDeclContext()->getRedeclContext();
+          if (Decl *ContextDecl = BD->getBlockManglingContextDecl()) {
+            if (isa<ParmVarDecl>(ContextDecl)) {
+              DC = ContextDecl->getDeclContext()->getRedeclContext();
+            } else {
+              D = ContextDecl;
+              continue;
+            }
+          }
+
+          if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC)) {
+            D = ND;
+            continue;
+          }
+
           break;
         } else if (isa<CapturedDecl>(D)) {
           D = cast<Decl>(cast<CapturedDecl>(D)->getParent());
@@ -140,13 +158,26 @@
           break;
         }
       }
-      // FIXME: Do we really only care about FunctionDecls here?
+      llvm::GlobalValue::LinkageTypes ParentLinkage;
       if (isa<FunctionDecl>(D)) {
-        llvm::GlobalValue::LinkageTypes ParentLinkage =
-            CGM.getFunctionLinkage(cast<FunctionDecl>(D));
-        if (llvm::GlobalValue::isWeakForLinker(ParentLinkage))
-          Linkage = ParentLinkage;
+        ParentLinkage = CGM.getFunctionLinkage(cast<FunctionDecl>(D));
+      } else if (isa<VarDecl>(D)) {
+        // FIXME: I'm pretty sure this is wrong...
+        ParentLinkage = CGM.GetLLVMLinkageVarDefinition(cast<VarDecl>(D),
+                                                        /*constant*/false);
+      } else {
+        assert(isa<FieldDecl>(D) && "Expect function, variable, or field");
+        // FIXME: Is this right?
+        ParentLinkage = llvm::GlobalValue::LinkOnceODRLinkage;
       }
+
+      if (llvm::GlobalValue::isWeakForLinker(ParentLinkage))
+        Linkage = ParentLinkage;
+
+      // FIXME: We need to force the emission/use of a guard variable for
+      // some variables even if we can constant-evaluate them because
+      // we can't guarantee every translation unit will constant-evaluate them.
+      // Also, we might need to fix up the linkage.
     }
 
     return EmitStaticVarDecl(D, Linkage);
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp	(revision 184607)
+++ lib/CodeGen/CodeGenModule.cpp	(working copy)
@@ -1789,7 +1789,7 @@
 
   // Set the llvm linkage type as appropriate.
   llvm::GlobalValue::LinkageTypes Linkage = 
-    GetLLVMLinkageVarDefinition(D, GV);
+    GetLLVMLinkageVarDefinition(D, GV->isConstant());
   GV->setLinkage(Linkage);
   if (Linkage == llvm::GlobalVariable::CommonLinkage)
     // common vars aren't constant even if declared const.
@@ -1820,8 +1820,7 @@
 }
 
 llvm::GlobalValue::LinkageTypes
-CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D,
-                                           llvm::GlobalVariable *GV) {
+CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant) {
   GVALinkage Linkage = getContext().GetGVALinkageForVariable(D);
   if (Linkage == GVA_Internal)
     return llvm::Function::InternalLinkage;
@@ -1836,7 +1835,7 @@
     // http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx
     return llvm::GlobalVariable::WeakODRLinkage;
   } else if (D->hasAttr<WeakAttr>()) {
-    if (GV->isConstant())
+    if (isConstant)
       return llvm::GlobalVariable::WeakODRLinkage;
     else
       return llvm::GlobalVariable::WeakAnyLinkage;
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h	(revision 184607)
+++ lib/CodeGen/CodeGenModule.h	(working copy)
@@ -942,8 +942,7 @@
   /// GetLLVMLinkageVarDefinition - Returns LLVM linkage for a global 
   /// variable.
   llvm::GlobalValue::LinkageTypes 
-  GetLLVMLinkageVarDefinition(const VarDecl *D,
-                              llvm::GlobalVariable *GV);
+  GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant);
   
   /// Emit all the global annotations.
   void EmitGlobalAnnotations();
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp	(revision 184607)
+++ lib/Sema/SemaExpr.cpp	(working copy)
@@ -9816,6 +9816,17 @@
 /// ActOnBlockStart - This callback is invoked when a block literal is started.
 void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
   BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc);
+
+  {
+    Decl *ManglingContextDecl;
+    if (MangleNumberingContext *MCtx =
+            getCurrentMangleNumberContext(Block->getDeclContext(),
+                                          ManglingContextDecl)) {
+      unsigned ManglingNumber = MCtx->getManglingNumber(Block);
+      Block->setBlockMangling(ManglingNumber, ManglingContextDecl);
+    }
+  }
+
   PushBlockScope(CurScope, Block);
   CurContext->addDecl(Block);
   if (CurScope)
@@ -9935,11 +9946,7 @@
   // Finally we can process decl attributes.
   ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
 
-  // Put the parameter variables in scope.  We can bail out immediately
-  // if we don't have any.
-  if (Params.empty())
-    return;
-
+  // Put the parameter variables in scope.
   for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
          E = CurBlock->TheDecl->param_end(); AI != E; ++AI) {
     (*AI)->setOwningFunction(CurBlock->TheDecl);
@@ -10647,8 +10654,8 @@
 Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
                                       ReuseLambdaContextDecl_t,
                                       bool IsDecltype) {
-  Decl *LambdaContextDecl = ExprEvalContexts.back().LambdaContextDecl;
-  PushExpressionEvaluationContext(NewContext, LambdaContextDecl, IsDecltype);
+  Decl *ClosureContextDecl = ExprEvalContexts.back().ManglingContextDecl;
+  PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype);
 }
 
 void Sema::PopExpressionEvaluationContext() {
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp	(revision 184607)
+++ lib/Sema/SemaLambda.cpp	(working copy)
@@ -52,6 +52,72 @@
   return false;
 }
 
+MangleNumberingContext *
+Sema::getCurrentMangleNumberContext(DeclContext *DC,
+                                    Decl *&ManglingContextDecl) {
+  // Compute the context for allocating mangling numbers in the current
+  // expression, if the ABI requires them.
+  ManglingContextDecl = ExprEvalContexts.back().ManglingContextDecl;
+
+  enum ContextKind {
+    Normal,
+    DefaultArgument,
+    DataMember,
+    StaticDataMember
+  } Kind = Normal;
+
+  // Default arguments of member function parameters that appear in a class
+  // definition, as well as the initializers of data members, receive special
+  // treatment. Identify them.
+  if (ManglingContextDecl) {
+    if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ManglingContextDecl)) {
+      if (const DeclContext *LexicalDC
+          = Param->getDeclContext()->getLexicalParent())
+        if (LexicalDC->isRecord())
+          Kind = DefaultArgument;
+    } else if (VarDecl *Var = dyn_cast<VarDecl>(ManglingContextDecl)) {
+      if (Var->getDeclContext()->isRecord())
+        Kind = StaticDataMember;
+    } else if (isa<FieldDecl>(ManglingContextDecl)) {
+      Kind = DataMember;
+    }
+  }
+
+  // Itanium ABI [5.1.7]:
+  //   In the following contexts [...] the one-definition rule requires closure
+  //   types in different translation units to "correspond":
+  bool IsInNonspecializedTemplate =
+    !ActiveTemplateInstantiations.empty() || CurContext->isDependentContext();
+  switch (Kind) {
+  case Normal:
+    //  -- the bodies of non-exported nonspecialized template functions
+    //  -- the bodies of inline functions
+    if ((IsInNonspecializedTemplate &&
+         !(ManglingContextDecl && isa<ParmVarDecl>(ManglingContextDecl))) ||
+        isInInlineFunction(CurContext)) {
+      ManglingContextDecl = 0;
+      return &Context.getManglingNumberContext(DC);
+    }
+
+    ManglingContextDecl = 0;
+    return 0;
+
+  case StaticDataMember:
+    //  -- the initializers of nonspecialized static members of template classes
+    if (!IsInNonspecializedTemplate) {
+      ManglingContextDecl = 0;
+      return 0;
+    }
+    // Fall through to get the current context.
+
+  case DataMember:
+    //  -- the in-class initializers of class members
+  case DefaultArgument:
+    //  -- default arguments appearing in class definitions
+    return &ExprEvalContexts.back().getMangleNumberingContext();
+  }
+}
+
 CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
                  SourceRange IntroducerRange,
                  TypeSourceInfo *MethodType,
@@ -98,75 +164,14 @@
       (*P)->setOwningFunction(Method);
   }
 
-  // Allocate a mangling number for this lambda expression, if the ABI
-  // requires one.
-  Decl *ContextDecl = ExprEvalContexts.back().LambdaContextDecl;
-
-  enum ContextKind {
-    Normal,
-    DefaultArgument,
-    DataMember,
-    StaticDataMember
-  } Kind = Normal;
-
-  // Default arguments of member function parameters that appear in a class
-  // 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 = StaticDataMember;
-    } else if (isa<FieldDecl>(ContextDecl)) {
-      Kind = DataMember;
-    }
+  Decl *ManglingContextDecl;
+  if (MangleNumberingContext *MCtx =
+          getCurrentMangleNumberContext(Class->getDeclContext(),
+                                        ManglingContextDecl)) {
+    unsigned ManglingNumber = MCtx->getManglingNumber(Method);
+    Class->setLambdaMangling(ManglingNumber, ManglingContextDecl);
   }
 
-  // Itanium ABI [5.1.7]:
-  //   In the following contexts [...] the one-definition rule requires closure
-  //   types in different translation units to "correspond":
-  bool IsInNonspecializedTemplate =
-    !ActiveTemplateInstantiations.empty() || CurContext->isDependentContext();
-  unsigned ManglingNumber;
-  switch (Kind) {
-  case Normal:
-    //  -- the bodies of non-exported nonspecialized template functions
-    //  -- the bodies of inline functions
-    if ((IsInNonspecializedTemplate &&
-         !(ContextDecl && isa<ParmVarDecl>(ContextDecl))) ||
-        isInInlineFunction(CurContext))
-      ManglingNumber = Context.getLambdaManglingNumber(Method);
-    else
-      ManglingNumber = 0;
-
-    // There is no special context for this lambda.
-    ContextDecl = 0;
-    break;
-
-  case StaticDataMember:
-    //  -- the initializers of nonspecialized static members of template classes
-    if (!IsInNonspecializedTemplate) {
-      ManglingNumber = 0;
-      ContextDecl = 0;
-      break;
-    }
-    // Fall through to assign a mangling number.
-
-  case DataMember:
-    //  -- the in-class initializers of class members
-  case DefaultArgument:
-    //  -- default arguments appearing in class definitions
-    ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
-                       .getManglingNumber(Method);
-    break;
-  }
-
-  Class->setLambdaMangling(ManglingNumber, ContextDecl);
-
   return Method;
 }
 
Index: test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm
===================================================================
--- test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm	(revision 184607)
+++ test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm	(working copy)
@@ -14,7 +14,7 @@
   }
 
   // CHECK: define internal zeroext i1 @___ZN7PR127462f1EPi_block_invoke
-  // CHECK: call zeroext i1 @"_ZNK7PR127462f132___ZN7PR127462f1EPi_block_invoke3$_0clEv"
+  // CHECK: call zeroext i1 @"_ZNK7PR127462f123__block_prefix_internal3$_0clEv"
 
   bool f2(int *x) {
     auto outer = [&]() -> bool {
Index: test/CodeGenObjCXX/mangle-blocks.mm
===================================================================
--- test/CodeGenObjCXX/mangle-blocks.mm	(revision 184607)
+++ test/CodeGenObjCXX/mangle-blocks.mm	(working copy)
@@ -1,12 +1,14 @@
 // RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 %s | FileCheck %s
 
-// CHECK: @_ZGVN3foo22___Z3foov_block_invoke5valueE = internal global i64 0
+// CHECK: @_ZGVN3foo23__block_prefix_internal5valueE = internal global i64 0
+// CHECK: @_ZN26externally_visible_statics1S14__block_prefix1jE = linkonce_odr global i32 0
+// CHECK: @_ZN26externally_visible_statics10inlinefunc14__block_prefix1iE = linkonce_odr global i32 0
 
 int f();
 
 void foo() {
   // CHECK: define internal i32 @___Z3foov_block_invoke
-  // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVN3foo22___Z3foov_block_invoke5valueE
+  // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVN3foo23__block_prefix_internal5valueE
   (void)^(int x) { 
     static int value = f();
     return x + value;
@@ -24,7 +26,7 @@
 - (void)method { 
   // CHECK: define internal signext i8 @"__11-[A method]_block_invoke"
   (void)^(int x) {
-    // CHECK: @"_ZN11-[A method]28__11-[A method]_block_invoke4nameE"
+    // CHECK: @"_ZN11-[A method]24__block_prefix_internal04nameE"
     static const char *name = "hello";
     return name[x];
   };
@@ -42,9 +44,35 @@
   // CHECK: define internal signext i8 @___Z3fooi_block_invoke
   void bar() {
     (void)^(int x) { 
-      // CHECK: @_ZN1N3bar26___ZN1N3barEv_block_invoke4nameE
+      // CHECK: @_ZN1N3bar24__block_prefix_internal24nameE
       static const char *name = "hello";
       return name[x];
     };
   }
 }
+
+int f();
+namespace externally_visible_statics {
+  inline void inlinefunc() {
+    ^{
+      static int i = f();
+    }();
+  }
+  struct S {
+    int x = ^{
+      static int j = f();
+      return j;
+    }();
+    void foo(int y = ^{ static int k = f(); return k; }()) {}
+  };
+  void g() {
+    inlinefunc();
+    S s;
+#if 0
+    // FIXME: We know how to mangle k, but crash trying to mangle the
+    // block itself.
+    s.foo();
+#endif
+  }
+}
+


More information about the cfe-commits mailing list