[clang] Suppress printing lambda body for constexpr diagnostics (PR #185800)
Sherman Pay via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 9 16:15:36 PDT 2026
https://github.com/shermpay updated https://github.com/llvm/llvm-project/pull/185800
>From 274e898ca4abfdb8bef6df4bc093cb1617e91e3a Mon Sep 17 00:00:00 2001
From: Sherman Pay <shermanpay at google.com>
Date: Tue, 10 Mar 2026 20:54:59 -0700
Subject: [PATCH 1/2] Suppress printing lambda body for constexpr diagnostics
closes: 125914
Introduce `SupressLambdaBody` `PrintingPolicy` that is used only for
constexpr diagnostics. This ensures `--print-ast` still works the same.
Add two tests:
1. To ast-printer-lambda to ensure `--print-ast` works the same.
2. Ensure lambda body is not printed for constexpr diagnostics.
---
clang/include/clang/AST/PrettyPrinter.h | 4 ++++
clang/lib/AST/ExprConstant.cpp | 12 +++++++-----
clang/lib/AST/StmtPrinter.cpp | 2 +-
clang/test/AST/ast-printer-lambda.cpp | 10 +++++++++-
clang/test/AST/constexpr-lambda-diagnostic.cpp | 8 ++++++++
5 files changed, 29 insertions(+), 7 deletions(-)
create mode 100644 clang/test/AST/constexpr-lambda-diagnostic.cpp
diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h
index a937d020b7277..534424fac606f 100644
--- a/clang/include/clang/AST/PrettyPrinter.h
+++ b/clang/include/clang/AST/PrettyPrinter.h
@@ -371,6 +371,10 @@ struct PrintingPolicy {
LLVM_PREFERRED_TYPE(bool)
unsigned SuppressDeclAttributes : 1;
+ /// Whether to suppress printing the body of a lambda.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned SuppressLambdaBody : 1;
+
/// Callbacks to use to allow the behavior of printing to be customized.
const PrintingCallbacks *Callbacks = nullptr;
};
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 429fef0a1afa8..76cd7dfbc4542 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1862,19 +1862,22 @@ APValue *EvalInfo::createHeapAlloc(const Expr *E, QualType T, LValue &LV) {
void CallStackFrame::describe(raw_ostream &Out) const {
bool IsMemberCall = false;
bool ExplicitInstanceParam = false;
+ auto PrintingPolicy = Info.Ctx.getPrintingPolicy();
+ PrintingPolicy.SuppressLambdaBody = true;
+
if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee)) {
IsMemberCall = !isa<CXXConstructorDecl>(MD) && !MD->isStatic();
ExplicitInstanceParam = MD->isExplicitObjectMemberFunction();
}
if (!IsMemberCall)
- Callee->getNameForDiagnostic(Out, Info.Ctx.getPrintingPolicy(),
+ Callee->getNameForDiagnostic(Out, PrintingPolicy,
/*Qualified=*/false);
if (This && IsMemberCall) {
if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(CallExpr)) {
const Expr *Object = MCE->getImplicitObjectArgument();
- Object->printPretty(Out, /*Helper=*/nullptr, Info.Ctx.getPrintingPolicy(),
+ Object->printPretty(Out, /*Helper=*/nullptr, PrintingPolicy,
/*Indentation=*/0);
if (Object->getType()->isPointerType())
Out << "->";
@@ -1882,8 +1885,7 @@ void CallStackFrame::describe(raw_ostream &Out) const {
Out << ".";
} else if (const auto *OCE =
dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) {
- OCE->getArg(0)->printPretty(Out, /*Helper=*/nullptr,
- Info.Ctx.getPrintingPolicy(),
+ OCE->getArg(0)->printPretty(Out, /*Helper=*/nullptr, PrintingPolicy,
/*Indentation=*/0);
Out << ".";
} else {
@@ -1894,7 +1896,7 @@ void CallStackFrame::describe(raw_ostream &Out) const {
Info.Ctx.getLValueReferenceType(This->Designator.MostDerivedType));
Out << ".";
}
- Callee->getNameForDiagnostic(Out, Info.Ctx.getPrintingPolicy(),
+ Callee->getNameForDiagnostic(Out, PrintingPolicy,
/*Qualified=*/false);
}
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 4d364fdcd5502..86adf6626ed15 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2463,7 +2463,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
// Print the body.
OS << ' ';
- if (Policy.TerseOutput)
+ if (Policy.TerseOutput || Policy.SuppressLambdaBody)
OS << "{}";
else
PrintRawCompoundStmt(Node->getCompoundStmtBody());
diff --git a/clang/test/AST/ast-printer-lambda.cpp b/clang/test/AST/ast-printer-lambda.cpp
index 08f1ff555b0b1..015aa7e791205 100644
--- a/clang/test/AST/ast-printer-lambda.cpp
+++ b/clang/test/AST/ast-printer-lambda.cpp
@@ -51,6 +51,14 @@ void test1(int i, T... t) {
auto lambda = [k{t...}] {};
//CHECK: [k{t...}] {
}
+{
+ auto lambda = [i]{
+ (void)i;
+ };
+ //CHECK: [i] {
+ //CHECK-NEXT: (void)i;
+ //CHECK-NEXT: };
+}
}
-};
\ No newline at end of file
+};
diff --git a/clang/test/AST/constexpr-lambda-diagnostic.cpp b/clang/test/AST/constexpr-lambda-diagnostic.cpp
new file mode 100644
index 0000000000000..1edc873718967
--- /dev/null
+++ b/clang/test/AST/constexpr-lambda-diagnostic.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++17 -verify=expected %s
+constexpr void undefined(); // expected-note {{declared here}}
+static constexpr int r = [] { // expected-error {{constexpr variable 'r' must be initialized by a constant expression}} \
+ expected-note {{in call to '[] {}.operator()()'}}}
+ undefined(); // expected-note {{undefined function 'undefined' cannot be used in a constant expression}}
+ return 0;
+ }();
+
>From b9a07daebbc8afda3846a5352484025de44d6306 Mon Sep 17 00:00:00 2001
From: Sherman Pay <shermanpay at google.com>
Date: Wed, 11 Mar 2026 22:43:45 -0700
Subject: [PATCH 2/2] Add ReleaseNotes and update new interpreter with test
Also set `SuppressLambdaPolicy` default to `false`.
---
clang/docs/ReleaseNotes.rst | 2 +
clang/include/clang/AST/PrettyPrinter.h | 2 +-
clang/lib/AST/ByteCode/InterpFrame.cpp | 8 ++--
clang/lib/AST/ExprConstant.cpp | 2 +-
.../test/AST/constexpr-lambda-diagnostic.cpp | 39 ++++++++++++++++++-
5 files changed, 46 insertions(+), 7 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3617786f09595..63e0db48c5d66 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -294,6 +294,8 @@ Improvements to Clang's diagnostics
(``-fimplicit-module-maps``). This does not affect module maps specified
explicitly via ``-fmodule-map-file=``.
+- Removed the body of lambdas from some diagnostic messages.
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h
index 534424fac606f..f95d54c0f05b9 100644
--- a/clang/include/clang/AST/PrettyPrinter.h
+++ b/clang/include/clang/AST/PrettyPrinter.h
@@ -94,7 +94,7 @@ struct PrintingPolicy {
UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false),
CleanUglifiedParameters(false), EntireContentsOfLargeArray(true),
UseEnumerators(true), UseHLSLTypes(LO.HLSL),
- SuppressDeclAttributes(false) {}
+ SuppressDeclAttributes(false), SuppressLambdaBody(false) {}
/// Adjust this printing policy for cases where it's known that we're
/// printing C++ code (for instance, if AST dumping reaches a C++-only
diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp
index 3c185a0ad661a..5ad1618e50fe2 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -158,6 +158,8 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
const Expr *CallExpr = Caller->getExpr(getRetPC());
const FunctionDecl *F = getCallee();
+ auto PrintingPolicy = S.getASTContext().getPrintingPolicy();
+ PrintingPolicy.SuppressLambdaBody = true;
bool IsMemberCall = false;
bool ExplicitInstanceParam = false;
@@ -170,7 +172,7 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(CallExpr)) {
const Expr *Object = MCE->getImplicitObjectArgument();
Object->printPretty(OS, /*Helper=*/nullptr,
- S.getASTContext().getPrintingPolicy(),
+ PrintingPolicy,
/*Indentation=*/0);
if (Object->getType()->isPointerType())
OS << "->";
@@ -179,7 +181,7 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
} else if (const auto *OCE =
dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) {
OCE->getArg(0)->printPretty(OS, /*Helper=*/nullptr,
- S.getASTContext().getPrintingPolicy(),
+ PrintingPolicy,
/*Indentation=*/0);
OS << ".";
} else if (const auto *M = dyn_cast<CXXMethodDecl>(F)) {
@@ -190,7 +192,7 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
}
}
- F->getNameForDiagnostic(OS, S.getASTContext().getPrintingPolicy(),
+ F->getNameForDiagnostic(OS, PrintingPolicy,
/*Qualified=*/false);
OS << '(';
unsigned Off = 0;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 76cd7dfbc4542..ae3cf65bd960d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1862,7 +1862,7 @@ APValue *EvalInfo::createHeapAlloc(const Expr *E, QualType T, LValue &LV) {
void CallStackFrame::describe(raw_ostream &Out) const {
bool IsMemberCall = false;
bool ExplicitInstanceParam = false;
- auto PrintingPolicy = Info.Ctx.getPrintingPolicy();
+ clang::PrintingPolicy PrintingPolicy = Info.Ctx.getPrintingPolicy();
PrintingPolicy.SuppressLambdaBody = true;
if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee)) {
diff --git a/clang/test/AST/constexpr-lambda-diagnostic.cpp b/clang/test/AST/constexpr-lambda-diagnostic.cpp
index 1edc873718967..ff053d514670c 100644
--- a/clang/test/AST/constexpr-lambda-diagnostic.cpp
+++ b/clang/test/AST/constexpr-lambda-diagnostic.cpp
@@ -1,8 +1,43 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++17 -verify=expected %s
-constexpr void undefined(); // expected-note {{declared here}}
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++17 -verify=expected %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++17 -verify=expected %s -fexperimental-new-constant-interpreter
+constexpr void undefined(); // expected-note 4 {{declared here}}
static constexpr int r = [] { // expected-error {{constexpr variable 'r' must be initialized by a constant expression}} \
expected-note {{in call to '[] {}.operator()()'}}}
undefined(); // expected-note {{undefined function 'undefined' cannot be used in a constant expression}}
return 0;
}();
+static constexpr auto valid_lambda = [] {};
+
+static constexpr int nested = [] { // expected-error {{constexpr variable 'nested' must be initialized by a constant expression}} \
+ expected-note {{in call to '[] {}.operator()()'}}}
+ valid_lambda();
+ auto inner = [] { // expected-note {{in call to '[] {}.operator()()'}}}
+ undefined(); // expected-note {{undefined function 'undefined' cannot be used in a constant expression}}
+ return 1;
+ }();
+ return 0;
+}();
+
+static constexpr float type_mismatch = [] { // expected-error {{cannot initialize a variable of type 'const float' with an rvalue of type 'void'}}
+}();
+
+constexpr auto named_lambda = [] {
+ undefined(); // expected-note {{undefined function 'undefined' cannot be used in a constant expression}}
+ return 0;
+};
+
+static constexpr int named_lambda_result = named_lambda(); // expected-error {{constexpr variable 'named_lambda_result' must be initialized by a constant expression}} \
+expected-note {{in call to 'named_lambda.operator()()'}}
+
+static constexpr int undeclared = []{ // expected-error {{constexpr variable 'undeclared' must be initialized by a constant expression}}
+ foo(); // expected-error {{use of undeclared identifier 'foo'}}
+ return 0;
+}();
+
+
+static constexpr int with_param = [](int x) { // expected-error {{constexpr variable 'with_param' must be initialized by a constant expression}} \
+expected-note {{in call to '[](int x) {}.operator()(2)'}}
+ undefined(); // expected-note {{undefined function 'undefined' cannot be used in a constant expression}}
+ return x;
+}(2);
More information about the cfe-commits
mailing list