leoetlino created this revision. leoetlino added a reviewer: rsmith. Herald added a subscriber: kristof.beyls. leoetlino requested review of this revision. Herald added a project: clang.
If any arguments of a consteval function call are value-dependent, the call cannot be evaluated until instantiation. This patch fixes Sema::CheckForImmediateInvocation so we don't attempt to evaluate consteval function calls too early (before instantiation). This fixes things like: consteval int f(int n) { return n; } template <int M> constexpr int broken() { return f(M); } Without the value-dependency checks, what happens is that the constant expression evaluation engine is called on the following expression: ConstantExpr 'int' `-CallExpr 'int' |-ImplicitCastExpr 'int (*)(int)' <FunctionToPointerDecay> | `-DeclRefExpr 'int (int)' lvalue Function 'f' 'int (int)' `-DeclRefExpr 'int' NonTypeTemplateParm 'M' 'int' which obviously fails when it tries to evaluate M. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D113859 Files: clang/lib/Sema/SemaExpr.cpp clang/test/SemaCXX/cxx2a-consteval.cpp Index: clang/test/SemaCXX/cxx2a-consteval.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-consteval.cpp +++ clang/test/SemaCXX/cxx2a-consteval.cpp @@ -61,6 +61,20 @@ struct E : C { consteval ~E() {} // expected-error {{cannot be declared consteval}} }; + +template <int X> +constexpr int callConstevalWithNameDependentArg() { + return f1(X); +} + +template <int X> +constexpr int callConstevalWithNameDependentArgAsVariable() { + constexpr int x = X; + return f1(x); +} + +auto foo = callConstevalWithNameDependentArg<42>(); + } consteval int main() { // expected-error {{'main' is not allowed to be declared consteval}} Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -16654,11 +16654,22 @@ /// It's OK if this fails; we'll also remove this in /// HandleImmediateInvocations, but catching it here allows us to avoid /// walking the AST looking for it in simple cases. - if (auto *Call = dyn_cast<CallExpr>(E.get()->IgnoreImplicit())) + if (auto *Call = dyn_cast<CallExpr>(E.get()->IgnoreImplicit())) { if (auto *DeclRef = dyn_cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit())) ExprEvalContexts.back().ReferenceToConsteval.erase(DeclRef); + // If any arguments are value-dependent, we will not be able to evaluate + // the function call until instantiation. + if (Call->isValueDependent()) + return E; + + for (Expr *Arg : Call->arguments()) { + if (Arg->isValueDependent()) + return E; + } + } + E = MaybeCreateExprWithCleanups(E); ConstantExpr *Res = ConstantExpr::Create(
Index: clang/test/SemaCXX/cxx2a-consteval.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-consteval.cpp +++ clang/test/SemaCXX/cxx2a-consteval.cpp @@ -61,6 +61,20 @@ struct E : C { consteval ~E() {} // expected-error {{cannot be declared consteval}} }; + +template <int X> +constexpr int callConstevalWithNameDependentArg() { + return f1(X); +} + +template <int X> +constexpr int callConstevalWithNameDependentArgAsVariable() { + constexpr int x = X; + return f1(x); +} + +auto foo = callConstevalWithNameDependentArg<42>(); + } consteval int main() { // expected-error {{'main' is not allowed to be declared consteval}} Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -16654,11 +16654,22 @@ /// It's OK if this fails; we'll also remove this in /// HandleImmediateInvocations, but catching it here allows us to avoid /// walking the AST looking for it in simple cases. - if (auto *Call = dyn_cast<CallExpr>(E.get()->IgnoreImplicit())) + if (auto *Call = dyn_cast<CallExpr>(E.get()->IgnoreImplicit())) { if (auto *DeclRef = dyn_cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit())) ExprEvalContexts.back().ReferenceToConsteval.erase(DeclRef); + // If any arguments are value-dependent, we will not be able to evaluate + // the function call until instantiation. + if (Call->isValueDependent()) + return E; + + for (Expr *Arg : Call->arguments()) { + if (Arg->isValueDependent()) + return E; + } + } + E = MaybeCreateExprWithCleanups(E); ConstantExpr *Res = ConstantExpr::Create(
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits