Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -2775,10 +2775,9 @@ Declarator &D, SmallVectorImpl &ParamInfo); void ParseParameterDeclarationClause( - DeclaratorContext DeclaratorContext, - ParsedAttributes &attrs, - SmallVectorImpl &ParamInfo, - SourceLocation &EllipsisLoc); + DeclaratorContext DeclaratorContext, ParsedAttributes &attrs, + SmallVectorImpl &ParamInfo, + SourceLocation &EllipsisLoc, bool InConstantConstext = false); void ParseBracketDeclarator(Declarator &D); void ParseMisplacedBracketDeclarator(Declarator &D); Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -1067,6 +1067,16 @@ /// Whether we are in a decltype expression. bool IsDecltype; + enum ImmediateInvocationEndScopeAction { + IIESA_Handle, ///< Immediate invocation can and should be handeled at the + ///< end of the scope. + IIESA_Propagate, ///< Immediate invocation cannot be handeled at the end + ///< of the scope and should be propagated to the outer + ///< scope. + IIESA_Drop, ///< Immediate invocation should be dropped at the end of the + ///< scope. + } IIEndScopeAction = IIESA_Handle; + /// The number of active cleanup objects when we entered /// this expression evaluation context. unsigned NumCleanupObjects; @@ -4469,7 +4479,8 @@ void PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, ExpressionEvaluationContextRecord::ExpressionKind Type = - ExpressionEvaluationContextRecord::EK_Other); + ExpressionEvaluationContextRecord::EK_Other, + bool IsLambdaParamScope = false); enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; void PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, @@ -12096,11 +12107,11 @@ Decl *LambdaContextDecl = nullptr, Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = Sema::ExpressionEvaluationContextRecord::EK_Other, - bool ShouldEnter = true) + bool ShouldEnter = true, bool IsLambdaParamScope = false) : Actions(Actions), Entered(ShouldEnter) { if (Entered) Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, - ExprContext); + ExprContext, IsLambdaParamScope); } EnterExpressionEvaluationContext( Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -6441,8 +6441,9 @@ ProhibitAttributes(FnAttrs); } else { if (Tok.isNot(tok::r_paren)) - ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo, - EllipsisLoc); + ParseParameterDeclarationClause( + D.getContext(), FirstArgAttrs, ParamInfo, EllipsisLoc, + D.getDeclSpec().getConstexprSpecifier() == CSK_consteval); else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); @@ -6687,10 +6688,9 @@ /// [C++11] attribute-specifier-seq parameter-declaration /// void Parser::ParseParameterDeclarationClause( - DeclaratorContext DeclaratorCtx, - ParsedAttributes &FirstArgAttrs, - SmallVectorImpl &ParamInfo, - SourceLocation &EllipsisLoc) { + DeclaratorContext DeclaratorCtx, ParsedAttributes &FirstArgAttrs, + SmallVectorImpl &ParamInfo, + SourceLocation &EllipsisLoc, bool InConstantConstext) { // Avoid exceeding the maximum function scope depth. // See https://bugs.llvm.org/show_bug.cgi?id=19607 @@ -6816,8 +6816,13 @@ // used. EnterExpressionEvaluationContext Eval( Actions, - Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, - Param); + InConstantConstext + ? Sema::ExpressionEvaluationContext::ConstantEvaluated + : Sema::ExpressionEvaluationContext:: + PotentiallyEvaluatedIfUsed, + Param, Sema::ExpressionEvaluationContextRecord::EK_Other, + /*ShouldEnter*/ true, + DeclaratorCtx == DeclaratorContext::LambdaExprContext); ExprResult DefArgResult; if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -16715,6 +16715,11 @@ if (isNonlocalVariable(D)) PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated, D); + + bool HasConstantInitializer = false; + if (auto *VD = dyn_cast(D)) + HasConstantInitializer = VD->isConstexpr() || VD->hasAttr(); + isConstantEvaluatedOverride = HasConstantInitializer; } /// Invoked after we are finished parsing an initializer for the declaration D. @@ -16728,6 +16733,7 @@ if (S && D->isOutOfLine()) ExitDeclaratorContext(S); + isConstantEvaluatedOverride = false; } /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -15196,10 +15196,14 @@ void Sema::PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl, - ExpressionEvaluationContextRecord::ExpressionKind ExprContext) { + ExpressionEvaluationContextRecord::ExpressionKind ExprContext, + bool IsLambdaParamScope) { ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup, LambdaContextDecl, ExprContext); Cleanup.reset(); + if (IsLambdaParamScope) + ExprEvalContexts.back().IIEndScopeAction = + Sema::ExpressionEvaluationContextRecord::IIESA_Propagate; if (!MaybeODRUseExprs.empty()) std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); } @@ -15279,7 +15283,9 @@ ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { if (!E.isUsable() || !Decl || !Decl->isConsteval() || isConstantEvaluated() || - RebuildingImmediateInvocation) + RebuildingImmediateInvocation || + ExprEvalContexts.back().IIEndScopeAction == + ExpressionEvaluationContextRecord::IIESA_Drop) return E; /// Opportunistically remove the callee from ReferencesToConsteval if we can. @@ -15413,8 +15419,26 @@ Sema::ExpressionEvaluationContextRecord &Rec) { if ((Rec.ImmediateInvocationCandidates.size() == 0 && Rec.ReferenceToConsteval.size() == 0) || - SemaRef.RebuildingImmediateInvocation) + SemaRef.RebuildingImmediateInvocation || + Rec.IIEndScopeAction == + Sema::ExpressionEvaluationContextRecord::IIESA_Drop) + return; + + /// If we can't handle immediate invocations yet. add them to the outer scope. + /// This occurs for default argument of lambdas as we can't know if the lambda + /// is consteval until after the parameter context has been poped. + if (Rec.IIEndScopeAction == + Sema::ExpressionEvaluationContextRecord::IIESA_Propagate) { + assert(SemaRef.ExprEvalContexts.size() >= 2); + (SemaRef.ExprEvalContexts.rbegin() + 1) + ->ImmediateInvocationCandidates.append( + Rec.ImmediateInvocationCandidates.begin(), + Rec.ImmediateInvocationCandidates.end()); + (SemaRef.ExprEvalContexts.rbegin() + 1) + ->ReferenceToConsteval.insert(Rec.ReferenceToConsteval.begin(), + Rec.ReferenceToConsteval.end()); return; + } /// When we have more then 1 ImmediateInvocationCandidates we need to check /// for nested ImmediateInvocationCandidates. when we have only 1 we only Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ clang/lib/Sema/SemaLambda.cpp @@ -889,6 +889,10 @@ LambdaScopeInfo *const LSI = getCurLambda(); assert(LSI && "LambdaScopeInfo should be on stack!"); + if (ParamInfo.getDeclSpec().getConstexprSpecifier() == CSK_consteval) + ExprEvalContexts.back().IIEndScopeAction = + ExpressionEvaluationContextRecord::IIESA_Drop; + // Determine if we're within a context where we know that the lambda will // be dependent, because there are template parameters in scope. bool KnownDependent; Index: clang/test/SemaCXX/cxx2a-consteval.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-consteval.cpp +++ clang/test/SemaCXX/cxx2a-consteval.cpp @@ -258,6 +258,26 @@ return f(0); }; +consteval int f1() { +// expected-note@-1+ {{declared here}} + return 0; +} +consteval auto g() { return f1; } +consteval int h(int (*p)() = g()) { return p(); } +int h1(int (*p)() = g()) { return p(); } +// expected-error@-1 {{is not a constant expression}} +// expected-note@-2 {{pointer to a consteval}} + +constexpr auto e = g(); +// expected-error@-1 {{must be initialized by a constant expression}} +// expected-note@-2 {{is not a constant expression}} + +auto l = [](int (*p)() = g()) { return p(); }; +// expected-error@-1 {{is not a constant expression}} +// expected-note@-2 {{pointer to a consteval}} + +auto l2 = [](int (*p)() = g()) consteval { return p(); }; + } namespace std {