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
