[clang] 48a4b66 - [clang] Classify binary op value kinds use ClassifyExprValueKind when it's type-dependent (#202696)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 9 09:49:40 PDT 2026
Author: Yihan Wang
Date: 2026-06-10T00:49:35+08:00
New Revision: 48a4b66451149e0c456a5479c695d894d368de2d
URL: https://github.com/llvm/llvm-project/commit/48a4b66451149e0c456a5479c695d894d368de2d
DIFF: https://github.com/llvm/llvm-project/commit/48a4b66451149e0c456a5479c695d894d368de2d.diff
LOG: [clang] Classify binary op value kinds use ClassifyExprValueKind when it's type-dependent (#202696)
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.
Signed-off-by: yronglin <yronglin777 at gmail.com>
Added:
clang/test/AST/dependent-assignment-classification.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/AST/ExprClassification.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 48e5b1fd931d1..a00f7212512d4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -748,6 +748,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{});
More information about the cfe-commits
mailing list