]> granicus.if.org Git - clang/commitdiff
Implement the conversion to a function pointer for lambda expressions,
authorDouglas Gregor <dgregor@apple.com>
Fri, 10 Feb 2012 08:36:38 +0000 (08:36 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 10 Feb 2012 08:36:38 +0000 (08:36 +0000)
per C++ [expr.prim.lambda]p6.

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

lib/Sema/SemaLambda.cpp
lib/Sema/SemaOverload.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp [new file with mode: 0644]

index 6e9bea781db32d52a78a2b595c3e549ca875abdb..1a7f1a12b3b7387bfe14e7544e2d474e65a517fa 100644 (file)
@@ -102,7 +102,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
                             EndLoc);
   Method->setAccess(AS_public);
   Class->addDecl(Method);
-  Method->setLexicalDeclContext(DC); // FIXME: Minor hack.
+
+  // Temporarily set the lexical declaration context to the current
+  // context, so that the Scope stack matches the lexical nesting.
+  Method->setLexicalDeclContext(DC);
 
   // Attributes on the lambda apply to the method.  
   ProcessDeclAttributes(CurScope, Method, ParamInfo);
@@ -289,12 +292,13 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
   llvm::SmallVector<Expr *, 4> CaptureInits;
   LambdaCaptureDefault CaptureDefault;
   CXXRecordDecl *Class;
+  CXXMethodDecl *CallOperator;
   SourceRange IntroducerRange;
   bool ExplicitParams;
   bool LambdaExprNeedsCleanups;
   {
     LambdaScopeInfo *LSI = getCurLambda();
-    CXXMethodDecl *CallOperator = LSI->CallOperator;
+    CallOperator = LSI->CallOperator;
     Class = LSI->Lambda;
     IntroducerRange = LSI->IntroducerRange;
     ExplicitParams = LSI->ExplicitParams;
@@ -427,5 +431,48 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
     break;
   }
 
+  // C++11 [expr.prim.lambda]p6:
+  //   The closure type for a lambda-expression with no lambda-capture
+  //   has a public non-virtual non-explicit const conversion function
+  //   to pointer to function having the same parameter and return
+  //   types as the closure type's function call operator.
+  if (Captures.empty() && CaptureDefault == LCD_None) {
+    const FunctionProtoType *Proto
+      = CallOperator->getType()->getAs<FunctionProtoType>(); 
+    QualType FunctionPtrTy;
+    {
+      FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
+      ExtInfo.TypeQuals = 0;
+      QualType FunctionTy
+        = Context.getFunctionType(Proto->getResultType(),
+                                  Proto->arg_type_begin(),
+                                  Proto->getNumArgs(),
+                                  ExtInfo);
+      FunctionPtrTy = Context.getPointerType(FunctionTy);
+    }
+
+    FunctionProtoType::ExtProtoInfo ExtInfo;
+    ExtInfo.TypeQuals = Qualifiers::Const;
+    QualType ConvTy = Context.getFunctionType(FunctionPtrTy, 0, 0, ExtInfo);
+
+    SourceLocation Loc = IntroducerRange.getBegin();
+    DeclarationName Name
+      = Context.DeclarationNames.getCXXConversionFunctionName(
+          Context.getCanonicalType(FunctionPtrTy));
+    DeclarationNameLoc NameLoc;
+    NameLoc.NamedType.TInfo = Context.getTrivialTypeSourceInfo(FunctionPtrTy,
+                                                               Loc);
+    CXXConversionDecl *Conversion 
+      = CXXConversionDecl::Create(Context, Class, Loc, 
+                                  DeclarationNameInfo(Name, Loc, NameLoc),
+                                  ConvTy, 
+                                  Context.getTrivialTypeSourceInfo(ConvTy, Loc),
+                                  /*isInline=*/false, /*isExplicit=*/false,
+                                  /*isConstexpr=*/false, Body->getLocEnd());
+    Conversion->setAccess(AS_public);
+    Conversion->setImplicit(true);
+    Class->addDecl(Conversion);
+  }
+
   return MaybeBindToTemporary(Lambda);
 }
index 54dd5f86527154e2a09240cef8b776c442ffcd17..3493b2a9dec8d12ae6e2da8ed7df55f14519da83 100644 (file)
@@ -7583,9 +7583,11 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
     if (Meth->isMoveAssignmentOperator())
       return oc_implicit_move_assignment;
 
-    assert(Meth->isCopyAssignmentOperator()
-           && "implicit method is not copy assignment operator?");
-    return oc_implicit_copy_assignment;
+    if (Meth->isCopyAssignmentOperator())
+      return oc_implicit_copy_assignment;
+
+    assert(isa<CXXConversionDecl>(Meth) && "expected conversion");
+    return oc_method;
   }
 
   return isTemplate ? oc_function_template : oc_function;
index 9df0f64ad31c9817d41f46b525cfaebd5d85d7aa..74003431c683f94381971c741f1a68a62b38a10f 100644 (file)
@@ -15,13 +15,13 @@ void test_quals() {
   // This function call operator is declared const (9.3.1) if and only
   // if the lambda- expression's parameter-declaration-clause is not
   // followed by mutable.
-  auto l = [](){}; // expected-note{{method is not marked volatile}}
+  auto l = [=](){}; // expected-note{{method is not marked volatile}}
   const decltype(l) lc = l;
   l();
   lc();
 
-  auto ml = []() mutable{}; // expected-note{{method is not marked const}} \
-                            // expected-note{{method is not marked volatile}} 
+  auto ml = [=]() mutable{}; // expected-note{{method is not marked const}} \
+                             // expected-note{{method is not marked volatile}} 
   const decltype(ml) mlc = ml;
   ml();
   mlc(); // expected-error{{no matching function for call to object of type}}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp
new file mode 100644 (file)
index 0000000..8b43cef
--- /dev/null
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+void test_conversion() {
+  int (*fp1)(int) = [](int x) { return x + 1; };
+  void (*fp2)(int) = [](int x) { };
+
+  const auto lambda = [](int x) { };
+  void (*fp3)(int) = lambda;
+
+  volatile const auto lambda2 = [](int x) { }; // expected-note{{but method is not marked volatile}}
+  void (*fp4)(int) = lambda2; // expected-error{{no viable conversion}}
+}
+
+void test_no_conversion() { 
+  int (*fp1)(int) = [=](int x) { return x + 1; }; // expected-error{{no viable conversion}}
+  void (*fp2)(int) = [&](int x) { }; // expected-error{{no viable conversion}}
+}
+
+void test_wonky() {
+  const auto l = [](int x) mutable -> int { return + 1; };
+  l(17); // okay: uses conversion function
+}