[cfe-commits] r150620 - in /cfe/trunk: lib/Sema/SemaLambda.cpp test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp

Douglas Gregor dgregor at apple.com
Wed Feb 15 14:08:38 PST 2012


Author: dgregor
Date: Wed Feb 15 16:08:38 2012
New Revision: 150620

URL: http://llvm.org/viewvc/llvm-project?rev=150620&view=rev
Log:
Lambda closure types have a conversion function to a block pointer
with the same parameter types and return type as the function call
operator. This is the real answer to

  http://stackoverflow.com/questions/4148242/is-it-possible-to-convert-a-c0x-lambda-to-a-clang-block

:)

Modified:
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=150620&r1=150619&r2=150620&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Wed Feb 15 16:08:38 2012
@@ -411,6 +411,48 @@
   Class->addDecl(Conversion);
 }
 
+/// \brief Add a lambda's conversion to block pointer.
+static void addBlockPointerConversion(Sema &S, 
+                                      SourceRange IntroducerRange,
+                                      CXXRecordDecl *Class,
+                                      CXXMethodDecl *CallOperator) {
+  const FunctionProtoType *Proto
+    = CallOperator->getType()->getAs<FunctionProtoType>(); 
+  QualType BlockPtrTy;
+  {
+    FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
+    ExtInfo.TypeQuals = 0;
+    QualType FunctionTy
+      = S.Context.getFunctionType(Proto->getResultType(),
+                                  Proto->arg_type_begin(),
+                                  Proto->getNumArgs(),
+                                  ExtInfo);
+    BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
+  }
+  
+  FunctionProtoType::ExtProtoInfo ExtInfo;
+  ExtInfo.TypeQuals = Qualifiers::Const;
+  QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, 0, 0, ExtInfo);
+  
+  SourceLocation Loc = IntroducerRange.getBegin();
+  DeclarationName Name
+    = S.Context.DeclarationNames.getCXXConversionFunctionName(
+        S.Context.getCanonicalType(BlockPtrTy));
+  DeclarationNameLoc NameLoc;
+  NameLoc.NamedType.TInfo = S.Context.getTrivialTypeSourceInfo(BlockPtrTy, Loc);
+  CXXConversionDecl *Conversion 
+    = CXXConversionDecl::Create(S.Context, Class, Loc, 
+                                DeclarationNameInfo(Name, Loc, NameLoc),
+                                ConvTy, 
+                                S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
+                                /*isInline=*/false, /*isExplicit=*/false,
+                                /*isConstexpr=*/false, 
+                                CallOperator->getBody()->getLocEnd());
+  Conversion->setAccess(AS_public);
+  Conversion->setImplicit(true);
+  Class->addDecl(Conversion);
+}
+
 ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, 
                                  Scope *CurScope, bool IsInstantiation) {
   // Leave the expression-evaluation context.
@@ -543,6 +585,14 @@
       addFunctionPointerConversion(*this, IntroducerRange, Class,
                                    CallOperator);
 
+    // Objective-C++:
+    //   The closure type for a lambda-expression has a public non-virtual
+    //   non-explicit const conversion function to a block pointer having the
+    //   same parameter and return types as the closure type's function call
+    //   operator.
+    if (getLangOptions().Blocks)
+      addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
+    
     // Finalize the lambda class.
     SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
     ActOnFields(0, Class->getLocation(), Class, Fields, 

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp?rev=150620&r1=150619&r2=150620&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp Wed Feb 15 16:08:38 2012
@@ -6,3 +6,10 @@
 
   (void)[=] { var = 17; }; // expected-error{{__block variable 'var' cannot be captured in a lambda}}
 }
+
+void conversion_to_block(int captured) {
+  int (^b1)(int) = [=](int x) { return x + captured; };
+
+  const auto lambda = [=](int x) { return x + captured; };
+  int (^b2)(int) = lambda;
+}





More information about the cfe-commits mailing list