[clang] 838c705 - [clang] Return early if a value dependent recovery init appeared in constant evaluation context in legacy constant evaluator (#225027)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 22 18:06:12 PDT 2026
Author: Yihan Wang
Date: 2026-09-23T09:06:05+08:00
New Revision: 838c705ee43c97dcb11664f926c8937c224d6987
URL: https://github.com/llvm/llvm-project/commit/838c705ee43c97dcb11664f926c8937c224d6987
DIFF: https://github.com/llvm/llvm-project/commit/838c705ee43c97dcb11664f926c8937c224d6987.diff
LOG: [clang] Return early if a value dependent recovery init appeared in constant evaluation context in legacy constant evaluator (#225027)
A recovery default member initializer can be value-dependent even when
the expression referring to the variable is not. Clang should return
early to avoid crash.
This fix the issue found in
https://github.com/llvm/llvm-project/issues/185874#issuecomment-4058045596.
---------
Signed-off-by: yronglin <yronglin777 at gmail.com>
Added:
Modified:
clang/docs/ReleaseNotes.md
clang/lib/AST/ExprConstant.cpp
clang/test/SemaCXX/recovery-expr-type.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 8e5e5e5732a9b..e5da258b9950a 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -679,6 +679,9 @@ features cannot lower the translation-unit ABI level;
using ``__is_constructible`` on a nested class template inside the definition
of the containing class. (#GH215166)
+- Fixed a crash issue when a value dependent recovery init appeared in constant
+ evaluation context in default constant evaluator.
+
- Fixed a bug where Clang incorrectly required `promise.return_value()` for a
dependent `co_return` operand that inits to `void`, instead of using
`promise.return_void()`. (#GH218368)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 9242491832841..9749d0b43a629 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -3520,19 +3520,27 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// Used to be C++20 [expr.const]p5.12:
// ... reference has a preceding initialization and either ...
if (Init && Init->isValueDependent()) {
+ if (!Info.checkingPotentialConstantExpression()) {
+ Info.FFDiag(E,
+ Info.getLangOpts().CPlusPlus11
+ ? diag::note_constexpr_ltor_non_constexpr
+ : diag::note_constexpr_ltor_non_integral,
+ 1)
+ << VD << VD->getType();
+ NoteLValueLocation(Info, Base);
+ }
+
+ // A recovery initializer can be value-dependent even when the expression
+ // referring to the variable is not.
+ if (Init->containsErrors())
+ return false;
+
// The DeclRefExpr is not value-dependent, but the variable it refers to
// has a value-dependent initializer. This should only happen in
// constant-folding cases, where the variable is not actually of a suitable
// type for use in a constant expression (otherwise the DeclRefExpr would
// have been value-dependent too), so diagnose that.
assert(!VD->mightBeUsableInConstantExpressions(Info.Ctx));
- if (!Info.checkingPotentialConstantExpression()) {
- Info.FFDiag(E, Info.getLangOpts().CPlusPlus11
- ? diag::note_constexpr_ltor_non_constexpr
- : diag::note_constexpr_ltor_non_integral, 1)
- << VD << VD->getType();
- NoteLValueLocation(Info, Base);
- }
return false;
}
diff --git a/clang/test/SemaCXX/recovery-expr-type.cpp b/clang/test/SemaCXX/recovery-expr-type.cpp
index bdab2940d6597..101d0155e3b98 100644
--- a/clang/test/SemaCXX/recovery-expr-type.cpp
+++ b/clang/test/SemaCXX/recovery-expr-type.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -o - %s -std=gnu++17 -fsyntax-only -verify -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -o - %s -std=gnu++20 -fsyntax-only -verify -fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -o - %s -std=gnu++17 -fsyntax-only -verify
-// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -o - %s -std=gnu++20 -fsyntax-only -verify
+// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -o - %s -std=gnu++17 -fsyntax-only -verify=expected,ref
+// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -o - %s -std=gnu++20 -fsyntax-only -verify=expected,ref
namespace test0 {
@@ -199,3 +199,26 @@ template<int*> struct P;
S<P> s;
} // namespace GH202117
+namespace test17 {
+struct A { int arr[1]; };
+struct B {
+ static constexpr A &a = A{{0}}; // expected-error {{non-const lvalue reference to type 'A' cannot bind to a temporary of type 'A'}}
+};
+
+B x;
+
+int v = x.a.arr[0]; // Do not crash when evaluating a static reference with an invalid initializer.
+} // namespace test17
+
+namespace test18 {
+struct B {
+ static constexpr int &a = 0; // expected-error {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} \
+ ref-note {{declared here}}
+};
+
+B x;
+// Diagnose why constant evaluation fails when reading a reference with an
+// invalid initializer.
+static_assert(x.a == 0); // expected-error {{static assertion expression is not an integral constant expression}} \
+ ref-note {{read of non-constexpr variable 'a' is not allowed in a constant expression}}
+} // namespace test18
More information about the cfe-commits
mailing list