]> granicus.if.org Git - clang/commitdiff
MS ABI: Mangle lambdas
authorDavid Majnemer <david.majnemer@gmail.com>
Wed, 5 Mar 2014 10:35:06 +0000 (10:35 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Wed, 5 Mar 2014 10:35:06 +0000 (10:35 +0000)
Use a scheme inspired by the Itanium ABI to properly implement the
mangling of lambdas.

N.B.  The incredibly astute observer will notice that we do not generate
external names that are identical, or even compatible with, MSVC.
This is fine because they don't generate names that they can use across
translation units.  Technically, we can generate any name we'd like so
long as that name wouldn't conflict with any other and would be stable
across translation units.

This fixes PR15512.

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

lib/AST/MicrosoftMangle.cpp
test/CodeGenCXX/mangle-ms-cxx11.cpp

index 24bd2a5a365f62ddc13aaec1d1931d026af59604..53c2d3ce52fbada4352de8cc8753022d3f65c8ff 100644 (file)
@@ -87,6 +87,7 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
   typedef std::pair<const DeclContext *, IdentifierInfo *> DiscriminatorKeyTy;
   llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
   llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
+  llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
 
 public:
   MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
@@ -148,6 +149,16 @@ public:
     return true;
   }
 
+  unsigned getLambdaId(const CXXRecordDecl *RD) {
+    assert(RD->isLambda() && "RD must be a lambda!");
+    assert(!RD->isExternallyVisible() && "RD must not be visible!");
+    assert(RD->getLambdaManglingNumber() == 0 &&
+           "RD must not have a mangling number!");
+    std::pair<llvm::DenseMap<const CXXRecordDecl *, unsigned>::iterator, bool>
+        Result = LambdaIds.insert(std::make_pair(RD, LambdaIds.size()));
+    return Result.first->second;
+  }
+
 private:
   void mangleInitFiniStub(const VarDecl *D, raw_ostream &Out, char CharCode);
 };
@@ -704,6 +715,23 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
         break;
       }
 
+      if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
+        if (Record->isLambda()) {
+          llvm::SmallString<10> Name("<lambda_");
+          unsigned LambdaId;
+          if (Record->getLambdaManglingNumber())
+            LambdaId = Record->getLambdaManglingNumber();
+          else
+            LambdaId = Context.getLambdaId(Record);
+
+          Name += llvm::utostr(LambdaId);
+          Name += ">";
+
+          mangleSourceName(Name);
+          break;
+        }
+      }
+
       llvm::SmallString<64> Name("<unnamed-type-");
       if (TD->hasDeclaratorForAnonDecl()) {
         // Anonymous types with no tag or typedef get the name of their
@@ -712,7 +740,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
       } else {
         // Otherwise, number the types using a $S prefix.
         Name += "$S";
-        Name += llvm::utostr(Context.getAnonymousStructId(TD) + 1);
+        Name += llvm::utostr(Context.getAnonymousStructId(TD));
       }
       Name += ">";
       mangleSourceName(Name.str());
@@ -770,6 +798,9 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
 void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) {
   // <postfix> ::= <unqualified-name> [<postfix>]
   //           ::= <substitution> [<postfix>]
+  if (isLambda(ND))
+    return;
+
   const DeclContext *DC = ND->getDeclContext();
 
   while (!DC->isTranslationUnit()) {
index c5da330a40d77bc508dfc3fb5b2e74eb40431053..3acd7a21001eeb70cb075a67be18b88f8d2a553f 100644 (file)
@@ -101,3 +101,21 @@ decltype(a) fun(decltype(a) x, decltype(a)) { return x; }
 // CHECK-DAG: ?fun@PR18022@@YA?AU<unnamed-type-a>@1@U21@0@Z
 
 }
+
+inline int define_lambda() {
+  static auto lambda = [] { static int local; ++local; return local; };
+// First, we have the static local variable of type "<lambda_1>" inside of
+// "define_lambda".
+// CHECK-DAG: ?lambda@?1??define_lambda@@YAHXZ@4V<lambda_1>@@A
+// Next, we have the "operator()" for "<lambda_1>" which is inside of
+// "define_lambda".
+// CHECK-DAG: ??R<lambda_1>@?define_lambda@@YAHXZ@QBEHXZ
+// Finally, we have the local which is inside of "<lambda_1>" which is inside of
+// "define_lambda". Hooray.
+// CHECK-DAG: ?local@?2???R<lambda_1>@?define_lambda@@YAHXZ@QBEHXZ@4HA
+  return lambda();
+}
+
+int call_lambda() {
+  return define_lambda();
+}