diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0155c2d8fb0bef..c88555dff8b286 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -864,6 +864,8 @@ Bug Fixes to C++ Support - Clang now instantiates local constexpr functions eagerly for constant evaluators. (#GH35052), (#GH94849) - Fixed a failed assertion when attempting to convert an integer representing the difference between the addresses of two labels (a GNU extension) to a pointer within a constant expression. (#GH95366). +- Fix immediate escalation bugs in the presence of dependent call arguments. (#GH94935) + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a47aeaa7e6c7f6..174b9dbc6d980c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5239,6 +5239,12 @@ class Sema final : public SemaBase { return ExprEvalContexts.back(); }; + ExpressionEvaluationContextRecord ¤tEvaluationContext() { + assert(!ExprEvalContexts.empty() && + "Must be in an expression evaluation context"); + return ExprEvalContexts.back(); + }; + ExpressionEvaluationContextRecord &parentEvaluationContext() { assert(ExprEvalContexts.size() >= 2 && "Must be in an expression evaluation context"); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 453af8f28f946a..acaff304be193f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6471,6 +6471,14 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, if (LangOpts.CPlusPlus) { if (const auto *CE = dyn_cast(Call.get())) DiagnosedUnqualifiedCallsToStdFunctions(*this, CE); + + // If we previously found that the id-expression of this call refers to a + // consteval function but the call is dependent, we should not treat is an + // an invalid immediate call. + if (auto *DRE = dyn_cast(Fn->IgnoreParens()); + DRE && Call.get()->isValueDependent()) { + currentEvaluationContext().ReferenceToConsteval.erase(DRE); + } } return Call; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 3bfda09d5f80fc..94eee1cb3f0777 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14545,6 +14545,9 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { E->getCallOperator()->isConsteval() ? Sema::ExpressionEvaluationContext::ImmediateFunctionContext : Sema::ExpressionEvaluationContext::PotentiallyEvaluated); + getSema().currentEvaluationContext().InImmediateEscalatingFunctionContext = + getSema().getLangOpts().CPlusPlus20 && + E->getCallOperator()->isImmediateEscalating(); Sema::CodeSynthesisContext C; C.Kind = clang::Sema::CodeSynthesisContext::LambdaExpressionSubstitution; diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index 622ec31c459ddf..fb8385eb020519 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -1195,14 +1195,18 @@ namespace GH66562 { namespace ns { - consteval int foo(int x) { return 1; } // expected-note {{declared here}} + consteval int foo(int x) { return 1; } // expected-note {{declared here}} \ + // expected-note {{passing argument to parameter 'x' here}} } template struct T { - static constexpr auto xx = ns::foo(A{}); // expected-error {{cannot take address of consteval function 'foo' outside of an immediate invocation}} + static constexpr auto xx = ns::foo(A{}); // expected-error {{cannot take address of consteval function 'foo' outside of an immediate invocation}} \ + // expected-error {{cannot initialize a parameter of type 'int' with an rvalue of type 'char *'}} }; +template class T; // expected-note {{in instantiation}} + } namespace GH65520 { diff --git a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp index b70c02201ac3c2..378414f1361729 100644 --- a/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp +++ b/clang/test/SemaCXX/cxx2b-consteval-propagate.cpp @@ -454,3 +454,45 @@ namespace GH91308 { } using R1 = decltype(&f); } + +namespace GH94935 { + +consteval void f(int) {} +consteval void undef(int); // expected-note {{declared here}} + +template +struct G { + void g() { + GH94935::f(T::fn()); + GH94935::f(T::undef2()); // expected-error {{call to consteval function 'GH94935::f' is not a constant expression}} \ + // expected-note {{undefined function 'undef2' cannot be used in a constant expression}} + GH94935::undef(T::fn()); // expected-error {{call to consteval function 'GH94935::undef' is not a constant expression}} \ + // expected-note {{undefined function 'undef' cannot be used in a constant expression}} + } +}; + +struct X { + static consteval int fn() { return 0; } + static consteval int undef2(); // expected-note {{declared here}} + +}; + +void test() { + G{}.g(); // expected-note {{instantiation}} +} + + +template +void g() { + auto l = []{ + ::f(T::fn()); + }; +} + +struct Y { + static int fn(); +}; + +template void g(); + +}