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-&gt;isLValue()
- CL_PRValue must satisfy E-&gt;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
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to