[clang] [clang] Classify binary op value kinds use ClassifyExprValueKind when it's type-dependent (PR #202696)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 9 08:52:08 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Yihan Wang (yronglin)
<details>
<summary>Changes</summary>
The crash is from an internal inconsistency in Clang’s expression classification.
Expr::ClassifyImpl computes a classification like CL_LValue or CL_PRValue, then asserts that this agrees with the AST node’s own value category:
- clang/lib/AST/ExprClassification.cpp:37
- CL_LValue must satisfy E->isLValue()
- CL_PRValue must satisfy E->isPRValue()
Fixes https://github.com/llvm/llvm-project/issues/202693.
---
Full diff: https://github.com/llvm/llvm-project/pull/202696.diff
3 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+2)
- (modified) clang/lib/AST/ExprClassification.cpp (+5-4)
- (added) clang/test/AST/dependent-assignment-classification.cpp (+39)
``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8a00b235860e4..340c0285072f9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -744,6 +744,8 @@ Bug Fixes to C++ Support
- We no longer consider conversion operators when copy-initializing from the same type. This was non
conforming and could lead to recursive constraint satisfaction checking. (#GH149443)
- Fixed a crash in Itanium C++ name mangling for a lambda in a local class field initializer inside a constructor/destructor. (#GH176395)
+- Fixed a crash when Expr::ClassifyImpl computes a classification like CL_LValue or CL_PRValue, then asserts that this
+ agrees with the AST node's own value category. (#GH202693)
- Fixed crashes in Itanium C++ name mangling for lambdas with trailing requires-clauses involving requires-expressions. (#GH100774) (#GH123854)
- Fixed an invalid rejection and assertion failure while generating ``operator=`` for fields with the ``__restrict`` qualifier. (#GH37979)
- Fixed a use-after-free bug when parsing default arguments containing lambdas in declarations with template-id declarators. (#GH196725)
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index a83c17074ea69..d153afda71c4b 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -617,11 +617,12 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) {
assert(Ctx.getLangOpts().CPlusPlus &&
"This is only relevant for C++.");
- // For binary operators which are unknown due to type dependence, the
- // convention is to classify them as a prvalue. This does not matter much, but
- // it needs to agree with how they are created.
+ // For binary operators which are unknown due to type dependence, use the
+ // value kind assigned when the expression was created. Dependent assignment
+ // expressions can be either lvalues or prvalues depending on whether they
+ // might resolve to an overloaded operator.
if (E->getType() == Ctx.DependentTy)
- return Cl::CL_PRValue;
+ return ClassifyExprValueKind(Ctx.getLangOpts(), E, E->getValueKind());
// C++ [expr.ass]p1: All [...] return an lvalue referring to the left operand.
// Except we override this for writes to ObjC properties.
diff --git a/clang/test/AST/dependent-assignment-classification.cpp b/clang/test/AST/dependent-assignment-classification.cpp
new file mode 100644
index 0000000000000..d31fa07fe0116
--- /dev/null
+++ b/clang/test/AST/dependent-assignment-classification.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++26 %s
+
+// expected-no-diagnostics
+
+template <auto X, class = decltype(X)>
+struct constant_wrapper;
+
+template <class T>
+concept constexpr_param = requires { typename constant_wrapper<T::value>; };
+
+struct ops {
+ template <constexpr_param T, constexpr_param R>
+ constexpr auto operator+=(this T, R)
+ -> constant_wrapper<(T::value += R::value)> {
+ return {};
+ }
+};
+
+template <auto X, class>
+struct constant_wrapper : ops {
+ static constexpr decltype(auto) value = (X);
+
+ template <constexpr_param R>
+ constexpr auto operator=(R) const -> constant_wrapper<(value = R::value)> {
+ return {};
+ }
+};
+
+struct A {
+ int n;
+ constexpr A(int n) : n(n) {}
+ constexpr A operator=(A rhs) const { return A{rhs.n}; }
+ constexpr A operator+=(A rhs) const { return A{n + rhs.n}; }
+};
+
+using X = constant_wrapper<A{1}>;
+using Y = constant_wrapper<A{2}>;
+using SimpleAssignment = decltype(X{} = Y{});
+using CompoundAssignment = decltype(X{} += Y{});
``````````
</details>
https://github.com/llvm/llvm-project/pull/202696
More information about the cfe-commits
mailing list