From: Douglas Gregor Date: Fri, 10 Feb 2012 16:13:20 +0000 (+0000) Subject: Don't introduce a lambda's operator() into the class until after we X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b555971345750350c21d541afe135054c7402933;p=clang Don't introduce a lambda's operator() into the class until after we have finished parsing the body, so that name lookup will never find anything within the closure type. Then, add this operator() and the conversion function (if available) before completing the class. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150252 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index ed05eff8e1..64fe7f7dce 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -102,7 +102,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, /*isConstExpr=*/false, EndLoc); Method->setAccess(AS_public); - Class->addDecl(Method); // Temporarily set the lexical declaration context to the current // context, so that the Scope stack matches the lexical nesting. @@ -393,17 +392,63 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, CallOperator->setType(FunctionTy); } - // Finalize the lambda class. - SmallVector Fields(Class->field_begin(), Class->field_end()); - ActOnFields(0, Class->getLocation(), Class, Fields, - SourceLocation(), SourceLocation(), 0); - CheckCompletedCXXClass(Class); + // 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(); + 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); + } // C++ [expr.prim.lambda]p7: // The lambda-expression's compound-statement yields the // function-body (8.4) of the function call operator [...]. ActOnFinishFunctionBody(CallOperator, Body, /*IsInstantation=*/false); + + // Finalize the lambda class. + SmallVector Fields(Class->field_begin(), Class->field_end()); CallOperator->setLexicalDeclContext(Class); + Class->addDecl(CallOperator); + ActOnFields(0, Class->getLocation(), Class, Fields, + SourceLocation(), SourceLocation(), 0); + CheckCompletedCXXClass(Class); + } if (LambdaExprNeedsCleanups) @@ -432,48 +477,5 @@ 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(); - 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/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp index 21c8e22092..8fa3837214 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp @@ -43,3 +43,12 @@ void test_capture_constness(int i, const int ic) { } +struct S1 { + int x, y; + int operator()(int); + void f() { + [&]()->int { + return operator()(this->x + y); + }(); + } +};