Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -3024,10 +3024,9 @@ Declarator &D, SmallVectorImpl &ParamInfo); void ParseParameterDeclarationClause( - DeclaratorContext DeclaratorContext, - ParsedAttributes &attrs, - SmallVectorImpl &ParamInfo, - SourceLocation &EllipsisLoc); + DeclaratorContext DeclaratorContext, ParsedAttributes &attrs, + SmallVectorImpl &ParamInfo, + SourceLocation &EllipsisLoc, bool InConstantContext = false); void ParseBracketDeclarator(Declarator &D); void ParseMisplacedBracketDeclarator(Declarator &D); Index: clang/include/clang/Sema/ScopeInfo.h =================================================================== --- clang/include/clang/Sema/ScopeInfo.h +++ clang/include/clang/Sema/ScopeInfo.h @@ -895,6 +895,14 @@ /// A map of explicit capture indices to their introducer source ranges. llvm::DenseMap ExplicitCaptureRanges; + /// Set of candidates for starting an immediate invocation. + llvm::SmallVector, 2> + ImmediateInvocationCandidates; + + /// Set of DeclRefExprs referencing a consteval function when used in a + /// context not already known to be immediately invoked. + llvm::SmallPtrSet ReferenceToConsteval; + /// Contains all of the variables defined in this lambda that shadow variables /// that were defined in parent contexts. Used to avoid warnings when the /// shadowed variables are uncaptured by this lambda. Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -6109,6 +6109,11 @@ /// invocation. ExprResult CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl); + void HandleImmediateInvocations( + llvm::SmallVectorImpl + &ImmediateInvocationCandidates, + llvm::SmallPtrSetImpl &ReferenceToConsteval); + bool CompleteConstructorCall(CXXConstructorDecl *Constructor, QualType DeclInitType, MultiExprArg ArgsPtr, SourceLocation Loc, Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -2452,13 +2452,13 @@ assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() && "Unexpected number of commas!"); - InitScope.pop(); - ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(), T.getCloseLocation(), Exprs); Actions.AddInitializerToDecl(ThisDecl, Initializer.get(), /*DirectInit=*/true); + + InitScope.pop(); } break; } @@ -2471,16 +2471,19 @@ PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl); ExprResult Init(ParseBraceInitializer()); - InitScope.pop(); - if (Init.isInvalid()) { Actions.ActOnInitializerError(ThisDecl); } else Actions.AddInitializerToDecl(ThisDecl, Init.get(), /*DirectInit=*/true); + + InitScope.pop(); break; } case InitKind::Uninitialized: { + InitializerScopeRAII InitScope(*this, D, ThisDecl); + Actions.ActOnUninitializedDecl(ThisDecl); + InitScope.pop(); break; } } @@ -6614,7 +6617,9 @@ } else { if (Tok.isNot(tok::r_paren)) ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo, - EllipsisLoc); + EllipsisLoc, + D.getDeclSpec().getConstexprSpecifier() == + ConstexprSpecKind::Consteval); else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); @@ -6865,10 +6870,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 InConstantContext) { // Avoid exceeding the maximum function scope depth. // See https://bugs.llvm.org/show_bug.cgi?id=19607 @@ -7019,7 +7023,10 @@ // used. EnterExpressionEvaluationContext Eval( Actions, - Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, + InConstantContext + ? Sema::ExpressionEvaluationContext::ConstantEvaluated + : Sema::ExpressionEvaluationContext:: + PotentiallyEvaluatedIfUsed, Param); ExprResult DefArgResult; Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -14505,6 +14505,16 @@ // meant to pop the context added in ActOnStartOfFunctionDef(). ExitFunctionBodyRAII ExitRAII(*this, isLambdaCallOperator(FD)); + if (isLambdaCallOperator(FD)) { + LambdaScopeInfo* LSI = getCurLambda(); + /// When processing the default argument of lambdas we dont know wether the + /// lambda is consteval or not because the consteval token arrives later. + /// so here we do not try to diagnose consteval lambdas. + if (!FD->isConsteval()) + HandleImmediateInvocations(LSI->ImmediateInvocationCandidates, + LSI->ReferenceToConsteval); + } + if (FD) { FD->setBody(Body); FD->setWillHaveBody(false); Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -16667,7 +16667,10 @@ ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(), getASTContext()), /*IsImmediateInvocation*/ true); - ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0); + if (LambdaScopeInfo *LSI = getCurLambda()) + LSI->ImmediateInvocationCandidates.emplace_back(Res, 0); + else + ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0); return Res; } @@ -16700,16 +16703,19 @@ } static void RemoveNestedImmediateInvocation( - Sema &SemaRef, Sema::ExpressionEvaluationContextRecord &Rec, + Sema &SemaRef, + llvm::SmallVectorImpl + &ImmediateInvocationCandidates, + llvm::SmallPtrSetImpl &ReferenceToConsteval, SmallVector::reverse_iterator It) { struct ComplexRemove : TreeTransform { using Base = TreeTransform; llvm::SmallPtrSetImpl &DRSet; - SmallVector &IISet; + SmallVectorImpl &IISet; SmallVector::reverse_iterator CurrentII; ComplexRemove(Sema &SemaRef, llvm::SmallPtrSetImpl &DR, - SmallVector &II, + SmallVectorImpl &II, SmallVector::reverse_iterator Current) : Base(SemaRef), DRSet(DR), IISet(II), CurrentII(Current) {} @@ -16759,8 +16765,8 @@ return Res; } bool AllowSkippingFirstCXXConstructExpr = true; - } Transformer(SemaRef, Rec.ReferenceToConsteval, - Rec.ImmediateInvocationCandidates, It); + } Transformer(SemaRef, ReferenceToConsteval, ImmediateInvocationCandidates, + It); /// CXXConstructExpr with a single argument are getting skipped by /// TreeTransform in some situtation because they could be implicit. This @@ -16777,33 +16783,35 @@ It->getPointer()->setSubExpr(Res.get()); } -static void -HandleImmediateInvocations(Sema &SemaRef, - Sema::ExpressionEvaluationContextRecord &Rec) { - if ((Rec.ImmediateInvocationCandidates.size() == 0 && - Rec.ReferenceToConsteval.size() == 0) || - SemaRef.RebuildingImmediateInvocation) +void Sema::HandleImmediateInvocations( + llvm::SmallVectorImpl + &ImmediateInvocationCandidates, + llvm::SmallPtrSetImpl &ReferenceToConsteval) { + if ((ImmediateInvocationCandidates.size() == 0 && + ReferenceToConsteval.size() == 0) || + RebuildingImmediateInvocation || isUnevaluatedContext()) return; /// When we have more then 1 ImmediateInvocationCandidates we need to check /// for nested ImmediateInvocationCandidates. when we have only 1 we only /// need to remove ReferenceToConsteval in the immediate invocation. - if (Rec.ImmediateInvocationCandidates.size() > 1) { + if (ImmediateInvocationCandidates.size() > 1) { /// Prevent sema calls during the tree transform from adding pointers that /// are already in the sets. - llvm::SaveAndRestore DisableIITracking( - SemaRef.RebuildingImmediateInvocation, true); + llvm::SaveAndRestore DisableIITracking(RebuildingImmediateInvocation, + true); /// Prevent diagnostic during tree transfrom as they are duplicates - Sema::TentativeAnalysisScope DisableDiag(SemaRef); + Sema::TentativeAnalysisScope DisableDiag(*this); - for (auto It = Rec.ImmediateInvocationCandidates.rbegin(); - It != Rec.ImmediateInvocationCandidates.rend(); It++) + for (auto It = ImmediateInvocationCandidates.rbegin(); + It != ImmediateInvocationCandidates.rend(); It++) if (!It->getInt()) - RemoveNestedImmediateInvocation(SemaRef, Rec, It); - } else if (Rec.ImmediateInvocationCandidates.size() == 1 && - Rec.ReferenceToConsteval.size()) { + RemoveNestedImmediateInvocation(*this, ImmediateInvocationCandidates, + ReferenceToConsteval, It); + } else if (ImmediateInvocationCandidates.size() == 1 && + ReferenceToConsteval.size()) { struct SimpleRemove : RecursiveASTVisitor { llvm::SmallPtrSetImpl &DRSet; SimpleRemove(llvm::SmallPtrSetImpl &S) : DRSet(S) {} @@ -16811,18 +16819,17 @@ DRSet.erase(E); return DRSet.size(); } - } Visitor(Rec.ReferenceToConsteval); + } Visitor(ReferenceToConsteval); Visitor.TraverseStmt( - Rec.ImmediateInvocationCandidates.front().getPointer()->getSubExpr()); + ImmediateInvocationCandidates.front().getPointer()->getSubExpr()); } - for (auto CE : Rec.ImmediateInvocationCandidates) - if (!CE.getInt()) - EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE); - for (auto DR : Rec.ReferenceToConsteval) { + for (auto CE : ImmediateInvocationCandidates) + if (!CE.getInt() && !CE.getPointer()->hasAPValueResult()) + EvaluateAndDiagnoseImmediateInvocation(*this, CE); + for (auto DR : ReferenceToConsteval) { auto *FD = cast(DR->getDecl()); - SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) - << FD; - SemaRef.Diag(FD->getLocation(), diag::note_declared_at); + Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) << FD; + Diag(FD->getLocation(), diag::note_declared_at); } } @@ -16861,7 +16868,8 @@ } WarnOnPendingNoDerefs(Rec); - HandleImmediateInvocations(*this, Rec); + HandleImmediateInvocations(Rec.ImmediateInvocationCandidates, + Rec.ReferenceToConsteval); // Warn on any volatile-qualified simple-assignments that are not discarded- // value expressions nor unevaluated operands (those cases get removed from @@ -18767,8 +18775,12 @@ if (auto *FD = dyn_cast(E->getDecl())) if (!isUnevaluatedContext() && !isConstantEvaluated() && - FD->isConsteval() && !RebuildingImmediateInvocation) - ExprEvalContexts.back().ReferenceToConsteval.insert(E); + FD->isConsteval() && !RebuildingImmediateInvocation) { + if (LambdaScopeInfo *LSI = getCurLambda()) + LSI->ReferenceToConsteval.insert(E); + else + ExprEvalContexts.back().ReferenceToConsteval.insert(E); + } MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse, RefsMinusAssignments); } 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}} + +// FIXME: These 2 cases generate 2 errors instead of just 1. +// constexpr auto e = g(); +// constexpr auto e1 = f1; + +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 { @@ -643,3 +663,22 @@ // Show that we reject when not in an immediate context. int w2 = (a.*&test::f)(); // expected-error {{cannot take address of consteval function 'f' outside of an immediate invocation}} } + +namespace top_level { +struct S { + consteval S() {} + int a; +// expected-note@-1 {{subobject declared here}} +}; + +S s; // expected-error {{is not a constant expression}} +// expected-note@-1 {{is not initialized}} + +struct S1 { + consteval S1() {} + int a = 0; +}; + +S1 s1; + +}