]> granicus.if.org Git - clang/commitdiff
Basic support for name mangling of C++11 lambda expressions. Because
authorDouglas Gregor <dgregor@apple.com>
Mon, 20 Feb 2012 19:44:39 +0000 (19:44 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 20 Feb 2012 19:44:39 +0000 (19:44 +0000)
name mangling in the Itanium C++ ABI for lambda expressions is so
dependent on context, we encode the number used to encode each lambda
as part of the lambda closure type, and maintain this value within
Sema.

Note that there are a several pieces still missing:
  - We still get the linkage of lambda expressions wrong
  - We aren't properly numbering or mangling lambda expressions that
  occur in default function arguments or in data member initializers.
  - We aren't (de-)serializing the lambda numbering tables

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

17 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/DeclCXX.h
include/clang/AST/ExprCXX.h
include/clang/AST/LambdaMangleContext.h [new file with mode: 0644]
include/clang/Sema/Sema.h
lib/AST/ASTContext.cpp
lib/AST/CMakeLists.txt
lib/AST/ExprCXX.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/LambdaMangleContext.cpp [new file with mode: 0644]
lib/Parse/ParseExprCXX.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriter.cpp
test/CodeGenCXX/lambda-expressions.cpp
test/CodeGenCXX/mangle-lambdas.cpp [new file with mode: 0644]

index 9ed70dfb4ba000ec9c69691c3b5c67734de10f81..1082806834f7d899950ce3218ffdb8f5b7e944ce 100644 (file)
@@ -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<ASTContext> {
   /// expression used to copy the lambda object.
   llvm::DenseMap<const CXXConversionDecl *, Expr *> LambdaBlockPointerInits;
   
+  /// \brief Mapping from each declaration context to its corresponding lambda 
+  /// mangling context.
+  llvm::DenseMap<const DeclContext *, LambdaMangleContext> 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.
index 5db16ed1dc5a6fd350f1157d3a07384b0db527d8..15c37813de9a19d7ac2db213753ee759ecdf8db3 100644 (file)
@@ -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;
index 458c96f3b548fe1684c7abbaa3f252e604611bc7..0d3b86269f516060a62cc8b7a9e2be198691ec77 100644 (file)
@@ -1166,7 +1166,8 @@ private:
              ArrayRef<Expr *> CaptureInits,
              ArrayRef<VarDecl *> ArrayIndexVars,
              ArrayRef<unsigned> 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<Expr *> CaptureInits,
                             ArrayRef<VarDecl *> ArrayIndexVars,
                             ArrayRef<unsigned> 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/include/clang/AST/LambdaMangleContext.h b/include/clang/AST/LambdaMangleContext.h
new file mode 100644 (file)
index 0000000..3e2fbad
--- /dev/null
@@ -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<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 bd285c78b951d3f58ccbb91ed10f187a456993fc..5df80891f339cf65865077a5469f7d1a2250e06a 100644 (file)
@@ -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<unsigned> ManglingNumber 
+                               = llvm::Optional<unsigned>(),
+                             bool IsInstantiation = false);
 
   /// \brief Define the "body" of the conversion from a lambda object to a 
   /// function pointer.
index cc651f9c9c5926bc3debfbc0ff2526d6c6bb3d35..e0056da60bc34dae902ebef978a70b0bee9ef13e 100644 (file)
@@ -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;
 }
index 1f0100a580a3ea0a37695efa1a0becf6bb4fe43a..651bcc485783aca6a02ecbe27bcbe5dd396af2f3 100644 (file)
@@ -28,6 +28,7 @@ add_clang_library(clangAST
   InheritViz.cpp
   ItaniumCXXABI.cpp
   ItaniumMangle.cpp
+  LambdaMangleContext.cpp
   Mangle.cpp
   MicrosoftCXXABI.cpp
   MicrosoftMangle.cpp
index f52f88105058de8b22ba3b7d0e55b5c69eff2f08..cbc5950f8350a03e3970c03e482a954eae7d5de0 100644 (file)
@@ -764,7 +764,8 @@ LambdaExpr::LambdaExpr(QualType T,
                        ArrayRef<Expr *> CaptureInits,
                        ArrayRef<VarDecl *> ArrayIndexVars,
                        ArrayRef<unsigned> 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<Expr *> CaptureInits,
                                ArrayRef<VarDecl *> ArrayIndexVars,
                                ArrayRef<unsigned> 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,
index 4843716909fb237eb57be57a744432c87c941b1e..a0bb6c74c33a15e5a4182152d43d972c41dd923b 100644 (file)
@@ -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<CXXRecordDecl>(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;
     }
 
+    // <unnamed-type-name> ::= <closure-type-name>
+    // 
+    // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+    // <lambda-sig> ::= <parameter-type>+   # Parameter types or 'v' for 'void'.
+    if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(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<CXXMethodDecl>(*Record->lookup(Name).first)->getType()->
+              getAs<FunctionProtoType>();
+        mangleBareFunctionType(Proto, /*MangleReturnType=*/false);        
+        Out << "E";
+        
+        // The number is omitted for the first closure type with a given 
+        // <lambda-sig> in a given context; it is n-2 for the nth closure type 
+        // (in lexical order) with that same <lambda-sig> 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/lib/AST/LambdaMangleContext.cpp b/lib/AST/LambdaMangleContext.cpp
new file mode 100644 (file)
index 0000000..f5272a7
--- /dev/null
@@ -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<FunctionProtoType>();
+  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<FunctionProtoType>()];
+}
index 0d33e30183c8a9875d2c9888200e83f5d7c6c1aa..fecf7b77657d1afb08886e4147b00ec24a0def91 100644 (file)
@@ -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();
index 1a362d48e282cc12fe63a7735c48e288ffed4ed4..d1f87a2c18980e32922585e45840918c6624d2d7 100644 (file)
@@ -483,7 +483,9 @@ static void addBlockPointerConversion(Sema &S,
 }
 
 ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, 
-                                 Scope *CurScope, bool IsInstantiation) {
+                                 Scope *CurScope, 
+                                 llvm::Optional<unsigned> 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
index 8a47a37d1c6b1542396bc162a7bfcd39d20303d0..7e095f7336bce476dd73c406e600d647387528ff 100644 (file)
@@ -7769,8 +7769,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
     return ExprError();    
   }
   
+  unsigned ManglingNumber = E->getLambdaClass()->getLambdaManglingNumber();
   return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(), 
-                                   /*CurScope=*/0, 
+                                   /*CurScope=*/0, ManglingNumber,
                                    /*IsInstantiation=*/true);
 }
 
index 6e044fd0dba2a7df53b11763dd0ac3fe28784f6e..b7d6a91dfee8e0451c67f822215fe9f48e57b2bd 100644 (file)
@@ -1105,6 +1105,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
       = static_cast<CXXRecordDecl::LambdaDefinitionData &>(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;
index 48b14e3bd7f37860b75048876394baa639b96c5d..add89ea8e289e837a5435704523b60e4b330f231 100644 (file)
@@ -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);
index e1aab1889c034579d16544b4beb83cfaa4c3c0da..203ca4d805c81848d8006409ce1b30527097e0f3 100644 (file)
@@ -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/test/CodeGenCXX/mangle-lambdas.cpp b/test/CodeGenCXX/mangle-lambdas.cpp
new file mode 100644 (file)
index 0000000..b237664
--- /dev/null
@@ -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);
+}