From 4a043c6376468f1883bbfcdac1a160e5bc97f640 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena Date: Thu, 25 Aug 2022 16:05:50 +0200 Subject: [PATCH] PotentiallyEvaluatedContext in a ImmediateFunctionContext. Body of `consteval` should be in an `ImmediateFunctionContext` instead of `ConstantEvaluated`. PotentiallyEvaluated expressions in Immediate functions are in a `ImmediateFunctionContext` as well. Fixes https://github.com/llvm/llvm-project/issues/51182 Original divergence: https://godbolt.org/z/vadGT5j6f Differential Revision: https://reviews.llvm.org/D132659 --- clang/docs/ReleaseNotes.rst | 3 +++ clang/include/clang/Sema/Sema.h | 9 +++++++++ clang/lib/Sema/SemaDecl.cpp | 6 +++++- clang/lib/Sema/SemaExpr.cpp | 4 ++-- clang/test/SemaCXX/cxx2a-consteval.cpp | 31 +++++++++++++++++++++++++++++++ 5 files changed, 50 insertions(+), 3 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 6b68172..82f4ee4 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -174,6 +174,9 @@ C++20 Feature Support - Class member variables are now in scope when parsing a ``requires`` clause. Fixes `GH55216 `_. +- Correctly set expression evaluation context as 'immediate function context' in + consteval functions. + This fixes `GH51182 https://github.com/llvm/llvm-project/issues/51182` C++2b Feature Support diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 3e9a748..0ee21cf 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1351,6 +1351,15 @@ public: bool isImmediateFunctionContext() const { return Context == ExpressionEvaluationContext::ImmediateFunctionContext || (Context == ExpressionEvaluationContext::DiscardedStatement && + InImmediateFunctionContext) || + // C++2b [expr.const]p14: + // An expression or conversion is in an immediate function + // context if it is potentially evaluated and either: + // * its innermost enclosing non-block scope is a function + // parameter scope of an immediate function, or + // * its enclosing statement is enclosed by the compound- + // statement of a consteval if statement. + (Context == ExpressionEvaluationContext::PotentiallyEvaluated && InImmediateFunctionContext); } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 873051f..1a29e6b 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14800,8 +14800,12 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, // Do not push if it is a lambda because one is already pushed when building // the lambda in ActOnStartOfLambdaDefinition(). if (!isLambdaCallOperator(FD)) + // [expr.const]/p14.1 + // An expression or conversion is in an immediate function context if it is + // potentially evaluated and either: its innermost enclosing non-block scope + // is a function parameter scope of an immediate function. PushExpressionEvaluationContext( - FD->isConsteval() ? ExpressionEvaluationContext::ConstantEvaluated + FD->isConsteval() ? ExpressionEvaluationContext::ImmediateFunctionContext : ExprEvalContexts.back().Context); // Check for defining attributes before the check for redefinition. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index eb1690c..80ac673 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -19675,8 +19675,8 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { if (auto *FD = dyn_cast(E->getDecl())) if (!isUnevaluatedContext() && !isConstantEvaluated() && - FD->isConsteval() && !RebuildingImmediateInvocation && - !FD->isDependentContext()) + !isImmediateFunctionContext() && FD->isConsteval() && + !RebuildingImmediateInvocation && !FD->isDependentContext()) ExprEvalContexts.back().ReferenceToConsteval.insert(E); MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse, RefsMinusAssignments); diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index 78011e2..09129a2 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -908,3 +908,34 @@ int test() { return testDefaultArgForParam() + testDefaultArgForParam((E)1); } } + +namespace GH51182 { +// Nested consteval function. +consteval int f(int v) { + return v; +} + +template +consteval int g(T a) { + // An immediate function context. + int n = f(a); + return n; +} +static_assert(g(100) == 100); +// -------------------------------------- +template +consteval T max(const T& a, const T& b) { + return (a > b) ? a : b; +} +template +consteval T mid(const T& a, const T& b, const T& c) { + T m = max(max(a, b), c); + if (m == a) + return max(b, c); + if (m == b) + return max(a, c); + return max(a, b); +} +static_assert(max(1,2)==2); +static_assert(mid(1,2,3)==2); +} // namespace GH51182 -- 2.7.4