https://github.com/GeneralK1ng created 
https://github.com/llvm/llvm-project/pull/176896

## What
Clang could assert in `clang::concepts::ExprRequirement::getExpr()` when an 
expression requirement becomes a substitution failure during template 
instantiation.

## Why
Substitution-failure `ExprRequirements` intentionally do not have an associated 
expression. Calling `getExpr()` in this case violates the API contract and 
triggers an assertion.

## Where 
This occurred while checking requirements in `RequirementContainsError` during 
`RequiresExpr` construction.

## Fix
Guard `RequirementContainsError` against substitution-failure 
`ExprRequirements` and avoid calling `getExpr()` in that case.

## Tests
- `clang/test/SemaTemplate/concepts-crash-expr-requirement.cpp`

Fixes #176402 

> This is my first contribution to LLVM/Clang — feedback and suggestions are 
> very welcome.

>From 962a9ef62e3be3bca293d5a176a90c47b97cef21 Mon Sep 17 00:00:00 2001
From: General_K1ng <[email protected]>
Date: Tue, 20 Jan 2026 19:03:18 +0800
Subject: [PATCH] [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:
+

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to