[clang] [clang][ExprConst] Add `EvalStatus::DiagEmitted` flag (PR #203838)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 15 00:25:19 PDT 2026
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/203838
There are some instances where we want to know _if_ a diagnostic has been emitted, but we're not interested in the actual diagnostic. Emitting the diagnostics can be rather costly, especially because we add the callstack as notes.
>From 55f9cbb4e5b9e64191ca524845b202c54a90c8a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 15 Jun 2026 07:19:24 +0200
Subject: [PATCH] DiagEmmitted flag
---
clang/include/clang/AST/Expr.h | 4 ++++
clang/lib/AST/ByteCode/State.cpp | 3 +++
clang/lib/AST/ComputeDependence.cpp | 6 ++----
clang/lib/AST/ExprConstant.cpp | 6 ++----
clang/lib/Sema/SemaExpr.cpp | 4 +---
5 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index eeac69cb1d0eb..b17957f2c08f6 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -619,6 +619,10 @@ class Expr : public ValueStmt {
/// Likewise, INT_MAX + 1 can be folded to INT_MIN, but has UB.
bool HasUndefinedBehavior = false;
+ /// Whether any diagnostic has been emitted. This is set regardless of
+ /// whether @ref #Diag is set or not.
+ bool DiagEmitted = false;
+
/// Diag - If this is non-null, it will be filled in with a stack of notes
/// indicating why evaluation failed (or why it failed to produce a constant
/// expression).
diff --git a/clang/lib/AST/ByteCode/State.cpp b/clang/lib/AST/ByteCode/State.cpp
index e612c6863e60f..e62b77272046c 100644
--- a/clang/lib/AST/ByteCode/State.cpp
+++ b/clang/lib/AST/ByteCode/State.cpp
@@ -25,6 +25,7 @@ OptionalDiagnostic State::FFDiag(SourceLocation Loc, diag::kind DiagId,
OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind DiagId,
unsigned ExtraNotes) {
+ EvalStatus.DiagEmitted = true;
if (EvalStatus.Diag)
return diag(E->getExprLoc(), DiagId, ExtraNotes, false);
setActiveDiagnostic(false);
@@ -33,6 +34,7 @@ OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind DiagId,
OptionalDiagnostic State::FFDiag(SourceInfo SI, diag::kind DiagId,
unsigned ExtraNotes) {
+ EvalStatus.DiagEmitted = true;
if (EvalStatus.Diag)
return diag(SI.getLoc(), DiagId, ExtraNotes, false);
setActiveDiagnostic(false);
@@ -41,6 +43,7 @@ OptionalDiagnostic State::FFDiag(SourceInfo SI, diag::kind DiagId,
OptionalDiagnostic State::CCEDiag(SourceLocation Loc, diag::kind DiagId,
unsigned ExtraNotes) {
+ EvalStatus.DiagEmitted = true;
// Don't override a previous diagnostic. Don't bother collecting
// diagnostics if we're evaluating for overflow.
if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) {
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 34167eee8d8f2..95cfd19c0bcc8 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -57,11 +57,9 @@ ExprDependence clang::computeDependence(UnaryOperator *E,
if (Ctx.getLangOpts().CPlusPlus && E->getOpcode() == UO_AddrOf &&
!(Dep & ExprDependence::Value)) {
Expr::EvalResult Result;
- SmallVector<PartialDiagnosticAt, 8> Diag;
- Result.Diag = &Diag;
// FIXME: This doesn't enforce the C++98 constant expression rules.
- if (E->getSubExpr()->EvaluateAsConstantExpr(Result, Ctx) && Diag.empty() &&
- Result.Val.isLValue()) {
+ if (E->getSubExpr()->EvaluateAsConstantExpr(Result, Ctx) &&
+ !Result.DiagEmitted && Result.Val.isLValue()) {
auto *VD = Result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
if (VD && VD->isTemplated()) {
auto *VarD = dyn_cast<VarDecl>(VD);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 1642c41a99a2f..0c5bf231c9f0a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -22292,17 +22292,15 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result) const {
// Build evaluation settings.
Expr::EvalStatus Status;
- SmallVector<PartialDiagnosticAt, 8> Diags;
- Status.Diag = &Diags;
EvalInfo Info(Ctx, Status, EvaluationMode::ConstantExpression);
bool IsConstExpr =
::EvaluateAsRValue(Info, this, Result ? *Result : Scratch) &&
- // FIXME: We don't produce a diagnostic for this, but the callers that
+ // NOTE: We don't produce a diagnostic for this, but the callers that
// call us on arbitrary full-expressions should generally not care.
Info.discardCleanups() && !Status.HasSideEffects;
- return IsConstExpr && Diags.empty();
+ return IsConstExpr && !Status.DiagEmitted;
}
bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index f2745425588f5..675d0bd389e28 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18340,12 +18340,10 @@ ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
// immediate invocation.
APValue Cached;
auto CheckConstantExpressionAndKeepResult = [&]() {
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
Expr::EvalResult Eval;
- Eval.Diag = &Notes;
bool Res = E.get()->EvaluateAsConstantExpr(
Eval, getASTContext(), ConstantExprKind::ImmediateInvocation);
- if (Res && Notes.empty()) {
+ if (Res && !Eval.DiagEmitted) {
Cached = std::move(Eval.Val);
return true;
}
More information about the cfe-commits
mailing list