diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-02-10 08:36:38 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-02-10 08:36:38 +0000 |
commit | ef7d78bd5be466c369b04af742ed8268244d4fe7 (patch) | |
tree | 7cfef66f103fb26328263fabb9fdae0542bf9876 | |
parent | 4d8d22bfaed6e5d7da6b5556415b18c43b44e36c (diff) |
Implement the conversion to a function pointer for lambda expressions,
per C++ [expr.prim.lambda]p6.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150236 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 51 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 8 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp | 6 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp | 22 |
4 files changed, 79 insertions, 8 deletions
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 6e9bea781d..1a7f1a12b3 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -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); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 54dd5f8652..3493b2a9de 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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; diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp index 9df0f64ad3..74003431c6 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp @@ -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 index 0000000000..8b43cefa92 --- /dev/null +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp @@ -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 +} |