From f3523cd93ad4d091222c0004bb0fd9b4039c7952 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Wed, 5 Mar 2014 10:35:06 +0000 Subject: [PATCH] MS ABI: Mangle lambdas 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 | 33 ++++++++++++++++++++++++++++- test/CodeGenCXX/mangle-ms-cxx11.cpp | 18 ++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 24bd2a5a36..53c2d3ce52 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -87,6 +87,7 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext { typedef std::pair DiscriminatorKeyTy; llvm::DenseMap Discriminator; llvm::DenseMap Uniquifier; + llvm::DenseMap 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::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(TD)) { + if (Record->isLambda()) { + llvm::SmallString<10> Name("getLambdaManglingNumber()) + LambdaId = Record->getLambdaManglingNumber(); + else + LambdaId = Context.getLambdaId(Record); + + Name += llvm::utostr(LambdaId); + Name += ">"; + + mangleSourceName(Name); + break; + } + } + llvm::SmallString<64> Name("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) { // ::= [] // ::= [] + if (isLambda(ND)) + return; + const DeclContext *DC = ND->getDeclContext(); while (!DC->isTranslationUnit()) { diff --git a/test/CodeGenCXX/mangle-ms-cxx11.cpp b/test/CodeGenCXX/mangle-ms-cxx11.cpp index c5da330a40..3acd7a2100 100644 --- a/test/CodeGenCXX/mangle-ms-cxx11.cpp +++ b/test/CodeGenCXX/mangle-ms-cxx11.cpp @@ -101,3 +101,21 @@ decltype(a) fun(decltype(a) x, decltype(a)) { return x; } // CHECK-DAG: ?fun@PR18022@@YA?AU@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 "" inside of +// "define_lambda". +// CHECK-DAG: ?lambda@?1??define_lambda@@YAHXZ@4V@@A +// Next, we have the "operator()" for "" which is inside of +// "define_lambda". +// CHECK-DAG: ??R@?define_lambda@@YAHXZ@QBEHXZ +// Finally, we have the local which is inside of "" which is inside of +// "define_lambda". Hooray. +// CHECK-DAG: ?local@?2???R@?define_lambda@@YAHXZ@QBEHXZ@4HA + return lambda(); +} + +int call_lambda() { + return define_lambda(); +} -- 2.40.0