[clang] [Clang] Avoid crash when expression requirements are substitution failures (PR #176896)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 20 07:07:29 PST 2026
https://github.com/GeneralK1ng updated https://github.com/llvm/llvm-project/pull/176896
>From 962a9ef62e3be3bca293d5a176a90c47b97cef21 Mon Sep 17 00:00:00 2001
From: General_K1ng <generak1ng0 at gmail.com>
Date: Tue, 20 Jan 2026 19:03:18 +0800
Subject: [PATCH 1/3] [Clang] Avoid crashing on substitution failure in
expression requirements
---
clang/lib/AST/ExprConcepts.cpp | 9 +++++++--
.../concepts-crash-expr-requirement.cpp | 19 +++++++++++++++++++
2 files changed, 26 insertions(+), 2 deletions(-)
create mode 100644 clang/test/SemaTemplate/concepts-crash-expr-requirement.cpp
diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp
index 36f910da49bfb..b2e4d6b00a647 100644
--- a/clang/lib/AST/ExprConcepts.cpp
+++ b/clang/lib/AST/ExprConcepts.cpp
@@ -101,8 +101,13 @@ concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
// Search through the requirements, and see if any have a RecoveryExpr in it,
// which means this RequiresExpr ALSO needs to be invalid.
static bool RequirementContainsError(concepts::Requirement *R) {
- if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(R))
- return ExprReq->getExpr() && ExprReq->getExpr()->containsErrors();
+ if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(R)) {
+ if (ExprReq->isExprSubstitutionFailure())
+ return true;
+ if (auto *E = ExprReq->getExpr())
+ return E->containsErrors();
+ return false;
+ }
if (auto *NestedReq = dyn_cast<concepts::NestedRequirement>(R))
return !NestedReq->hasInvalidConstraint() &&
diff --git a/clang/test/SemaTemplate/concepts-crash-expr-requirement.cpp b/clang/test/SemaTemplate/concepts-crash-expr-requirement.cpp
new file mode 100644
index 0000000000000..9e6474371a245
--- /dev/null
+++ b/clang/test/SemaTemplate/concepts-crash-expr-requirement.cpp
@@ -0,0 +1,19 @@
+// RUN: not %clang_cc1 -std=c++23 -fsyntax-only %s 2>&1 | FileCheck %s
+// Regression test: don't crash when an expression requirement becomes a
+// substitution failure during template instantiation (see #176402).
+
+void f() {
+ auto recursiveLambda = [](auto self, int depth) -> void {
+ struct MyClass;
+ auto testConcept = []<typename T> {
+ return requires(T) { &MyClass::operator0 }
+ };
+ };
+ recursiveLambda(recursiveLambda, 5);
+}
+
+// CHECK: error:
+// CHECK: expected ';' at end of requirement
+// CHECK-NOT: Assertion failed
+// CHECK-NOT: Stack dump:
+
>From 6eb6b066cbc481a4f3d58d406fa487883d79e693 Mon Sep 17 00:00:00 2001
From: General_K1ng <generak1ng0 at gmail.com>
Date: Tue, 20 Jan 2026 22:32:54 +0800
Subject: [PATCH 2/3] refactor(concepts): consolidate concept requirement tests
---
.../concepts-crash-expr-requirement.cpp | 19 -------------------
clang/test/SemaTemplate/concepts.cpp | 13 +++++++++++++
2 files changed, 13 insertions(+), 19 deletions(-)
delete mode 100644 clang/test/SemaTemplate/concepts-crash-expr-requirement.cpp
diff --git a/clang/test/SemaTemplate/concepts-crash-expr-requirement.cpp b/clang/test/SemaTemplate/concepts-crash-expr-requirement.cpp
deleted file mode 100644
index 9e6474371a245..0000000000000
--- a/clang/test/SemaTemplate/concepts-crash-expr-requirement.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: not %clang_cc1 -std=c++23 -fsyntax-only %s 2>&1 | FileCheck %s
-// Regression test: don't crash when an expression requirement becomes a
-// substitution failure during template instantiation (see #176402).
-
-void f() {
- auto recursiveLambda = [](auto self, int depth) -> void {
- struct MyClass;
- auto testConcept = []<typename T> {
- return requires(T) { &MyClass::operator0 }
- };
- };
- recursiveLambda(recursiveLambda, 5);
-}
-
-// CHECK: error:
-// CHECK: expected ';' at end of requirement
-// CHECK-NOT: Assertion failed
-// CHECK-NOT: Stack dump:
-
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index d93391baf9926..2701c16f56fc0 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1713,3 +1713,16 @@ template<C<void, bool> T> int f();
void main() { f<int>(); }
}
+
+namespace GH176402 {
+ void f() {
+ auto recursiveLambda = [](auto self, int depth) -> void {
+ struct MyClass;
+ auto testConcept = []<typename T> {
+ return requires(T) { &MyClass::operator0 }
+ // expected-error {{expected ';' at end of requirement}}
+ };
+ };
+ recursiveLambda(recursiveLambda, 5);
+ }
+}
>From 2cc0b9b9a6de60aea7b2944315165b76e6966251 Mon Sep 17 00:00:00 2001
From: General_K1ng <generak1ng0 at gmail.com>
Date: Tue, 20 Jan 2026 22:40:40 +0800
Subject: [PATCH 3/3] doc: add release note
---
clang/docs/ReleaseNotes.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index bde3bb1e81210..611e3fba2bc2b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -137,6 +137,7 @@ Bug Fixes to Attribute Support
Bug Fixes to C++ Support
^^^^^^^^^^^^^^^^^^^^^^^^
+- Fixed a crash when instantiating ``requires`` expressions involving substitution failures in C++ concepts. (#GH176402)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
More information about the cfe-commits
mailing list