From: Douglas Gregor Date: Tue, 14 Feb 2012 00:00:48 +0000 (+0000) Subject: Link together the call operator produced from transforming a lambda X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d5387e86ce3dfe1ae09e050ee11d86ca0d066d04;p=clang Link together the call operator produced from transforming a lambda expression with the original call operator, so that we don't try to separately instantiate the call operator. Test and tweak a few more bits for template instantiation of lambda expressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150440 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index f97b5232ac..0ce1c74163 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -521,19 +521,21 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand // (Clause 5). - switch (ExprEvalContexts.back().Context) { - case Unevaluated: - // We don't actually diagnose this case immediately, because we - // could be within a context where we might find out later that - // the expression is potentially evaluated (e.g., for typeid). - ExprEvalContexts.back().Lambdas.push_back(Lambda); - break; - - case ConstantEvaluated: - case PotentiallyEvaluated: - case PotentiallyEvaluatedIfUsed: - break; - } + if (!CurContext->isDependentContext()) { + switch (ExprEvalContexts.back().Context) { + case Unevaluated: + // We don't actually diagnose this case immediately, because we + // could be within a context where we might find out later that + // the expression is potentially evaluated (e.g., for typeid). + ExprEvalContexts.back().Lambdas.push_back(Lambda); + break; + case ConstantEvaluated: + case PotentiallyEvaluated: + case PotentiallyEvaluatedIfUsed: + break; + } + } + return MaybeBindToTemporary(Lambda); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index ba6ec82c81..a63b9c804a 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -7672,6 +7672,13 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { E->getCallOperator()->getLocEnd()); getDerived().transformAttrs(E->getCallOperator(), CallOperator); + // FIXME: Instantiation-specific. + CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(), + TSK_ImplicitInstantiation); + + // Introduce the context of the call operator. + Sema::ContextRAII SavedContext(getSema(), CallOperator); + // Enter the scope of the lambda. sema::LambdaScopeInfo *LSI = getSema().enterLambdaScope(CallOperator, E->getIntroducerRange(), @@ -7741,17 +7748,12 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { } // Instantiate the body of the lambda expression. - StmtResult Body; - { - Sema::ContextRAII SavedContext(getSema(), CallOperator); - - Body = getDerived().TransformStmt(E->getBody()); - if (Body.isInvalid()) { - getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0, - /*IsInstantiation=*/true); - return ExprError(); - } - } + StmtResult Body = getDerived().TransformStmt(E->getBody()); + if (Body.isInvalid()) { + getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0, + /*IsInstantiation=*/true); + return ExprError(); + } return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(), /*CurScope=*/0, diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp index 4126dd96b9..baa29ea944 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp @@ -43,3 +43,74 @@ int infer_result(T x, T y) { template int infer_result(int, int); template int infer_result(X, X); // expected-note{{in instantiation of function template specialization 'infer_result' requested here}} +// Make sure that lambda's operator() can be used from templates. +template +void accept_lambda(F f) { + f(1); +} + +template +void pass_lambda(T x) { + accept_lambda([&x](T y) { return x + y; }); +} + +template void pass_lambda(int); + +namespace std { + class type_info; +} + +namespace p2 { + struct P { + virtual ~P(); + }; + + template + struct Boom { + Boom(const Boom&) { + T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} \ + // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}} + } + void tickle() const; + }; + + template + void odr_used(R &r, Boom boom) { + const std::type_info &ti + = typeid([=,&r] () -> R& { // expected-error{{lambda expression in an unevaluated operand}} + boom.tickle(); // expected-note{{in instantiation of member function}} + return r; + }()); + } + + template void odr_used(int&, Boom); // expected-note{{in instantiation of function template specialization}} + + template + void odr_used2(R &r, Boom boom) { + const std::type_info &ti + = typeid([=,&r] () -> R& { + boom.tickle(); // expected-note{{in instantiation of member function}} + return r; + }()); + } + + template void odr_used2(P&, Boom); +} + +namespace p5 { + struct NonConstCopy { + NonConstCopy(const NonConstCopy&) = delete; + NonConstCopy(NonConstCopy&); + }; + + template + void double_capture(T &nc) { + [=] () mutable { + [=] () mutable { + T nc2(nc); + }(); + }(); + } + + template void double_capture(NonConstCopy&); +}