diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 9ed70dfb4ba0..1082806834f7 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -21,6 +21,7 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/VersionTuple.h" #include "clang/AST/Decl.h" +#include "clang/AST/LambdaMangleContext.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TemplateName.h" @@ -326,6 +327,10 @@ class ASTContext : public RefCountedBase { /// expression used to copy the lambda object. llvm::DenseMap LambdaBlockPointerInits; + /// \brief Mapping from each declaration context to its corresponding lambda + /// mangling context. + llvm::DenseMap LambdaMangleContexts; + friend class CXXConversionDecl; /// \brief Mapping that stores parameterIndex values for ParmVarDecls @@ -1765,6 +1770,8 @@ public: /// it is not used. bool DeclMustBeEmitted(const Decl *D); + /// \brief Retrieve the lambda mangling number for a lambda expression. + unsigned getLambdaManglingNumber(CXXMethodDecl *CallOperator); /// \brief Used by ParmVarDecl to store on the side the /// index of the parameter when it exceeds the size of the normal bitfield. diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 5db16ed1dc5a..15c37813de9a 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -569,8 +569,12 @@ class CXXRecordDecl : public RecordDecl { unsigned NumCaptures : 16; /// \brief The number of explicit captures in this lambda. - unsigned NumExplicitCaptures : 15; + unsigned NumExplicitCaptures : 16; + /// \brief The number used to indicate this lambda expression for name + /// mangling in the Itanium C++ ABI. + unsigned ManglingNumber; + /// \brief The "extra" data associated with the lambda, including /// captures, capture initializers, the body of the lambda, and the /// array-index variables for array captures. @@ -1442,6 +1446,17 @@ public: /// actually abstract. bool mayBeAbstract() const; + /// \brief If this is the closure type of a lambda expression, retrieve the + /// number to be used for name mangling in the Itanium C++ ABI. + /// + /// Zero indicates that this closure type has internal linkage, so the + /// mangling number does not matter, while a non-zero value indicates which + /// lambda expression this is in this particular context. + unsigned getLambdaManglingNumber() const { + assert(isLambda() && "Not a lambda closure type!"); + return getLambdaData().ManglingNumber; + } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstCXXRecord && K <= lastCXXRecord; diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 458c96f3b548..0d3b86269f51 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -1166,7 +1166,8 @@ private: ArrayRef CaptureInits, ArrayRef ArrayIndexVars, ArrayRef ArrayIndexStarts, - SourceLocation ClosingBrace); + SourceLocation ClosingBrace, + unsigned ManglingNumber); /// \brief Construct an empty lambda expression. LambdaExpr(EmptyShell Empty, unsigned NumCaptures, bool HasArrayIndexVars) @@ -1204,7 +1205,8 @@ public: ArrayRef CaptureInits, ArrayRef ArrayIndexVars, ArrayRef ArrayIndexStarts, - SourceLocation ClosingBrace); + SourceLocation ClosingBrace, + unsigned ManglingNumber); /// \brief Construct a new lambda expression that will be deserialized from /// an external source. @@ -1296,7 +1298,7 @@ public: /// \brief Whether this lambda had its result type explicitly specified. bool hasExplicitResultType() const { return ExplicitResultType; } - + static bool classof(const Stmt *T) { return T->getStmtClass() == LambdaExprClass; } diff --git a/clang/include/clang/AST/LambdaMangleContext.h b/clang/include/clang/AST/LambdaMangleContext.h new file mode 100644 index 000000000000..3e2fbad2f8e6 --- /dev/null +++ b/clang/include/clang/AST/LambdaMangleContext.h @@ -0,0 +1,36 @@ +//===--- 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 "llvm/ADT/DenseMap.h" + +namespace clang { + +class CXXMethodDecl; +class FunctionProtoType; + +/// \brief Keeps track of the mangled names of lambda expressions within a +/// particular context. +class LambdaMangleContext { + llvm::DenseMap 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 diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index bd285c78b951..5df80891f339 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3555,7 +3555,10 @@ public: /// ActOnLambdaExpr - This is called when the body of a lambda expression /// was successfully completed. ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, - Scope *CurScope, bool IsInstantiation = false); + Scope *CurScope, + llvm::Optional ManglingNumber + = llvm::Optional(), + bool IsInstantiation = false); /// \brief Define the "body" of the conversion from a lambda object to a /// function pointer. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index cc651f9c9c59..e0056da60bc3 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6748,6 +6748,13 @@ size_t ASTContext::getSideTableAllocatedMemory() const { + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); } +unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) { + CXXRecordDecl *Lambda = CallOperator->getParent(); + return LambdaMangleContexts[Lambda->getDeclContext()] + .getManglingNumber(CallOperator); +} + + void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { ParamIndices[D] = index; } diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index 1f0100a580a3..651bcc485783 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -28,6 +28,7 @@ add_clang_library(clangAST InheritViz.cpp ItaniumCXXABI.cpp ItaniumMangle.cpp + LambdaMangleContext.cpp Mangle.cpp MicrosoftCXXABI.cpp MicrosoftMangle.cpp diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index f52f88105058..cbc5950f8350 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -764,7 +764,8 @@ LambdaExpr::LambdaExpr(QualType T, ArrayRef CaptureInits, ArrayRef ArrayIndexVars, ArrayRef ArrayIndexStarts, - SourceLocation ClosingBrace) + SourceLocation ClosingBrace, + unsigned ManglingNumber) : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary, T->isDependentType(), T->isDependentType(), T->isDependentType(), /*ContainsUnexpandedParameterPack=*/false), @@ -785,6 +786,7 @@ LambdaExpr::LambdaExpr(QualType T, ASTContext &Context = Class->getASTContext(); Data.NumCaptures = NumCaptures; Data.NumExplicitCaptures = 0; + Data.ManglingNumber = ManglingNumber; Data.Captures = (Capture *)Context.Allocate(sizeof(Capture) * NumCaptures); Capture *ToCapture = Data.Captures; for (unsigned I = 0, N = Captures.size(); I != N; ++I) { @@ -824,7 +826,8 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, ArrayRef CaptureInits, ArrayRef ArrayIndexVars, ArrayRef ArrayIndexStarts, - SourceLocation ClosingBrace) { + SourceLocation ClosingBrace, + unsigned ManglingNumber) { // Determine the type of the expression (i.e., the type of the // function object we're creating). QualType T = Context.getTypeDeclType(Class); @@ -837,7 +840,7 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault, Captures, ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, ArrayIndexStarts, - ClosingBrace); + ClosingBrace, ManglingNumber); } LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures, diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 4843716909fb..a0bb6c74c33a 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -122,6 +122,13 @@ public: } bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { + // Lambda closure types with external linkage (indicated by a + // non-zero lambda mangling number) have their own numbering scheme, so + // they do not need a discriminator. + if (const CXXRecordDecl *RD = dyn_cast(ND)) + if (RD->isLambda() && RD->getLambdaManglingNumber() > 0) + return false; + unsigned &discriminator = Uniquifier[ND]; if (!discriminator) discriminator = ++Discriminator; @@ -1076,6 +1083,38 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, break; } + // ::= + // + // ::= Ul E [ ] _ + // ::= + # Parameter types or 'v' for 'void'. + if (const CXXRecordDecl *Record = dyn_cast(TD)) { + if (Record->isLambda()) { + // FIXME: Figure out if we're in a function body, default argument, + // or initializer for a class member. + + Out << "Ul"; + DeclarationName Name + = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); + const FunctionProtoType *Proto + = cast(*Record->lookup(Name).first)->getType()-> + getAs(); + mangleBareFunctionType(Proto, /*MangleReturnType=*/false); + Out << "E"; + + // The number is omitted for the first closure type with a given + // in a given context; it is n-2 for the nth closure type + // (in lexical order) with that same and context. + // + // The AST keeps track of the number for us. + if (unsigned Number = Record->getLambdaManglingNumber()) { + if (Number > 1) + mangleNumber(Number - 2); + } + Out << '_'; + break; + } + } + // Get a unique id for the anonymous struct. uint64_t AnonStructId = Context.getAnonymousStructId(TD); diff --git a/clang/lib/AST/LambdaMangleContext.cpp b/clang/lib/AST/LambdaMangleContext.cpp new file mode 100644 index 000000000000..f5272a7fdbce --- /dev/null +++ b/clang/lib/AST/LambdaMangleContext.cpp @@ -0,0 +1,30 @@ +//===--- 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/DeclCXX.h" + +using namespace clang; + +unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) { + const FunctionProtoType *Proto + = CallOperator->getType()->getAs(); + ASTContext &Context = CallOperator->getASTContext(); + + QualType Key = Context.getFunctionType(Context.VoidTy, + Proto->arg_type_begin(), + Proto->getNumArgs(), + FunctionProtoType::ExtProtoInfo()); + Key = Context.getCanonicalType(Key); + return ++ManglingNumbers[Key->castAs()]; +} diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 0d33e30183c8..fecf7b77657d 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -886,8 +886,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( BodyScope.Exit(); if (!Stmt.isInvalid()) - return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.take(), - getCurScope()); + return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.take(), getCurScope()); Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); return ExprError(); diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 1a362d48e282..d1f87a2c1898 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -483,7 +483,9 @@ static void addBlockPointerConversion(Sema &S, } ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, - Scope *CurScope, bool IsInstantiation) { + Scope *CurScope, + llvm::Optional ManglingNumber, + bool IsInstantiation) { // Leave the expression-evaluation context. DiscardCleanupsInEvaluationContext(); PopExpressionEvaluationContext(); @@ -633,11 +635,19 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, if (LambdaExprNeedsCleanups) ExprNeedsCleanups = true; + // If we don't already have a mangling number for this lambda expression, + // allocate one now. + if (!ManglingNumber) { + // FIXME: Default arguments, data member initializers are special. + ManglingNumber = Context.getLambdaManglingNumber(CallOperator); + } + LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault, Captures, ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, - ArrayIndexStarts, Body->getLocEnd()); + ArrayIndexStarts, Body->getLocEnd(), + *ManglingNumber); // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 8a47a37d1c6b..7e095f7336bc 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -7769,8 +7769,9 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { return ExprError(); } + unsigned ManglingNumber = E->getLambdaClass()->getLambdaManglingNumber(); return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(), - /*CurScope=*/0, + /*CurScope=*/0, ManglingNumber, /*IsInstantiation=*/true); } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 6e044fd0dba2..b7d6a91dfee8 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1105,6 +1105,7 @@ void ASTDeclReader::ReadCXXDefinitionData( = static_cast(Data); Lambda.NumCaptures = Record[Idx++]; Lambda.NumExplicitCaptures = Record[Idx++]; + Lambda.ManglingNumber = Record[Idx++]; Lambda.Captures = (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures); Capture *ToCapture = Lambda.Captures; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 48b14e3bd7f3..add89ea8e289 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4332,6 +4332,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec CXXRecordDecl::LambdaDefinitionData &Lambda = D->getLambdaData(); Record.push_back(Lambda.NumCaptures); Record.push_back(Lambda.NumExplicitCaptures); + Record.push_back(Lambda.ManglingNumber); for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { LambdaExpr::Capture &Capture = Lambda.Captures[I]; AddSourceLocation(Capture.getLocation(), Record); diff --git a/clang/test/CodeGenCXX/lambda-expressions.cpp b/clang/test/CodeGenCXX/lambda-expressions.cpp index e1aab1889c03..203ca4d805c8 100644 --- a/clang/test/CodeGenCXX/lambda-expressions.cpp +++ b/clang/test/CodeGenCXX/lambda-expressions.cpp @@ -2,8 +2,8 @@ int a() { return []{ return 1; }(); } // CHECK: define i32 @_Z1av -// CHECK: call i32 @"_ZZ1avENK3$_0clEv" -// CHECK: define internal i32 @"_ZZ1avENK3$_0clEv" +// CHECK: call i32 @_ZZ1avENKUlvE_clEv +// CHECK: define internal i32 @_ZZ1avENKUlvE_clEv // CHECK: ret i32 1 int b(int x) { return [x]{return x;}(); } @@ -11,8 +11,8 @@ int b(int x) { return [x]{return x;}(); } // CHECK: store i32 // CHECK: load i32* // CHECK: store i32 -// CHECK: call i32 @"_ZZ1biENK3$_1clEv" -// CHECK: define internal i32 @"_ZZ1biENK3$_1clEv" +// CHECK: call i32 @_ZZ1biENKUlvE_clEv +// CHECK: define internal i32 @_ZZ1biENKUlvE_clEv // CHECK: load i32* // CHECK: ret i32 @@ -20,8 +20,8 @@ int c(int x) { return [&x]{return x;}(); } // CHECK: define i32 @_Z1ci // CHECK: store i32 // CHECK: store i32* -// CHECK: call i32 @"_ZZ1ciENK3$_2clEv" -// CHECK: define internal i32 @"_ZZ1ciENK3$_2clEv" +// CHECK: call i32 @_ZZ1ciENKUlvE_clEv +// CHECK: define internal i32 @_ZZ1ciENKUlvE_clEv // CHECK: load i32** // CHECK: load i32* // CHECK: ret i32 @@ -33,8 +33,8 @@ int d(int x) { D y[10]; [x,y] { return y[x].x; }(); } // CHECK: call void @_ZN1DC1Ev // CHECK: icmp ult i64 %{{.*}}, 10 // CHECK: call void @_ZN1DC1ERKS_ -// CHECK: call i32 @"_ZZ1diENK3$_3clEv" -// CHECK: define internal i32 @"_ZZ1diENK3$_3clEv" +// CHECK: call i32 @_ZZ1diENKUlvE_clEv +// CHECK: define internal i32 @_ZZ1diENKUlvE_clEv // CHECK: load i32* // CHECK: load i32* // CHECK: ret i32 @@ -44,29 +44,29 @@ int e(E a, E b, bool cond) { [a,b,cond](){ return (cond ? a : b).x; }(); } // CHECK: define i32 @_Z1e1ES_b // CHECK: call void @_ZN1EC1ERKS_ // CHECK: invoke void @_ZN1EC1ERKS_ -// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_4clEv" -// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev" -// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev" +// CHECK: invoke i32 @_ZZ1e1ES_bENKUlvE_clEv +// CHECK: call void @_ZZ1e1ES_bENUlvE_D1Ev +// CHECK: call void @_ZZ1e1ES_bENUlvE_D1Ev -// CHECK: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv" +// CHECK: define internal i32 @_ZZ1e1ES_bENKUlvE_clEv // CHECK: trunc i8 // CHECK: load i32* // CHECK: ret i32 void f() { // CHECK: define void @_Z1fv() - // CHECK: {{call.*_5cvPFiiiEEv}} + // CHECK: {{call.*@_ZZ1fvENKUliiE_cvPFiiiEEv}} // 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 @"_ZZ1fvEN3$_58__invokeEii" +// CHECK: define internal i32 @_ZZ1fvENUliiE_8__invokeEii // CHECK: store i32 // CHECK-NEXT: store i32 // CHECK-NEXT: load i32* // CHECK-NEXT: load i32* -// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_5clEii" +// CHECK-NEXT: call i32 @_ZZ1fvENKUliiE_clEii // CHECK-NEXT: ret i32 -// CHECK: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev" +// CHECK: define internal void @_ZZ1e1ES_bENUlvE_D2Ev diff --git a/clang/test/CodeGenCXX/mangle-lambdas.cpp b/clang/test/CodeGenCXX/mangle-lambdas.cpp new file mode 100644 index 000000000000..b2376648c206 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-lambdas.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s | FileCheck %s + +// CHECK: define linkonce_odr void @_Z11inline_funci +inline void inline_func(int n) { + // CHECK: call i32 @_ZZ11inline_funciENKUlvE_clEv + int i = []{ return 1; }(); + + // CHECK: call i32 @_ZZ11inline_funciENKUlvE0_clEv + int j = [=] { return n + i; }(); + + // CHECK: call double @_ZZ11inline_funciENKUlvE1_clEv + int k = [=] () -> double { return n + i; }(); + + // CHECK: call i32 @_ZZ11inline_funciENKUliE_clEi + int l = [=] (int x) -> int { return x + i; }(n); + + // CHECK: ret void +} + +void call_inline_func() { + inline_func(17); +}