[clang] [Clang] Preserve CXXParenListInitExpr in TreeTransform. (PR #138518)

via cfe-commits cfe-commits at lists.llvm.org
Mon May 5 05:36:49 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: cor3ntin (cor3ntin)

<details>
<summary>Changes</summary>

We were converting a CXXParenListInitExpr to a ParenListExpr in TreeTransform.

However, ParenListExpr is typeless, so Clang could not rebuild the correct initialization sequence in some contexts.

#Fixes 72880

---
Full diff: https://github.com/llvm/llvm-project/pull/138518.diff


6 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+1) 
- (modified) clang/include/clang/AST/ExprCXX.h (+2-2) 
- (modified) clang/include/clang/Sema/Sema.h (+5) 
- (modified) clang/lib/Sema/SemaExpr.cpp (+9) 
- (modified) clang/lib/Sema/TreeTransform.h (+28-4) 
- (modified) clang/test/SemaCXX/paren-list-agg-init.cpp (+32-5) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4bd9d904e1ea9..55a46fb6f947e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -642,6 +642,7 @@ Bug Fixes to C++ Support
   (#GH136432), (#GH137014), (#GH138018)
 - Fixed an assertion when trying to constant-fold various builtins when the argument
   referred to a reference to an incomplete type. (#GH129397)
+- Fixed a crash when a cast involved a parenthesized aggregate initialization in dependent context. (#GH72880)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 844f6dd90ae1d..04d08b022c562 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -5124,8 +5124,8 @@ class CXXParenListInitExpr final
 
   void updateDependence() { setDependence(computeDependence(this)); }
 
-  ArrayRef<Expr *> getInitExprs() {
-    return ArrayRef(getTrailingObjects<Expr *>(), NumExprs);
+  MutableArrayRef<Expr *> getInitExprs() {
+    return MutableArrayRef(getTrailingObjects<Expr *>(), NumExprs);
   }
 
   const ArrayRef<Expr *> getInitExprs() const {
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 19343eb0af092..741951cb9ea0e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7167,6 +7167,11 @@ class Sema final : public SemaBase {
   ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E);
   ExprResult ActOnParenListExpr(SourceLocation L, SourceLocation R,
                                 MultiExprArg Val);
+  ExprResult ActOnCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
+                                       unsigned NumUserSpecifiedExprs,
+                                       SourceLocation InitLoc,
+                                       SourceLocation LParenLoc,
+                                       SourceLocation RParenLoc);
 
   /// ActOnStringLiteral - The specified tokens were lexed as pasted string
   /// fragments (e.g. "foo" "bar" L"baz").  The result string has to handle
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index d72d97addfac2..787b07c4080ea 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7985,6 +7985,15 @@ ExprResult Sema::ActOnParenListExpr(SourceLocation L,
   return ParenListExpr::Create(Context, L, Val, R);
 }
 
+ExprResult Sema::ActOnCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
+                                           unsigned NumUserSpecifiedExprs,
+                                           SourceLocation InitLoc,
+                                           SourceLocation LParenLoc,
+                                           SourceLocation RParenLoc) {
+  return CXXParenListInitExpr::Create(Context, Args, T, NumUserSpecifiedExprs,
+                                      InitLoc, LParenLoc, RParenLoc);
+}
+
 bool Sema::DiagnoseConditionalForNull(const Expr *LHSExpr, const Expr *RHSExpr,
                                       SourceLocation QuestionLoc) {
   const Expr *NullExpr = LHSExpr;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index aed00e0ff06cd..a3120f61f0d9c 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3099,6 +3099,15 @@ class TreeTransform {
     return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, SubExprs);
   }
 
+  ExprResult RebuildCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
+                                         unsigned NumUserSpecifiedExprs,
+                                         SourceLocation InitLoc,
+                                         SourceLocation LParenLoc,
+                                         SourceLocation RParenLoc) {
+    return getSema().ActOnCXXParenListInitExpr(Args, T, NumUserSpecifiedExprs,
+                                               InitLoc, LParenLoc, RParenLoc);
+  }
+
   /// Build a new address-of-label expression.
   ///
   /// By default, performs semantic analysis, using the name of the label
@@ -3315,6 +3324,11 @@ class TreeTransform {
       return getSema().BuildCXXTypeConstructExpr(
           TInfo, LParenLoc, MultiExprArg(PLE->getExprs(), PLE->getNumExprs()),
           RParenLoc, ListInitialization);
+
+    if (auto *PLE = dyn_cast<CXXParenListInitExpr>(Sub))
+      return getSema().BuildCXXTypeConstructExpr(
+          TInfo, LParenLoc, PLE->getInitExprs(), RParenLoc, ListInitialization);
+
     return getSema().BuildCXXTypeConstructExpr(TInfo, LParenLoc,
                                                MultiExprArg(&Sub, 1), RParenLoc,
                                                ListInitialization);
@@ -16487,12 +16501,22 @@ ExprResult
 TreeTransform<Derived>::TransformCXXParenListInitExpr(CXXParenListInitExpr *E) {
   SmallVector<Expr *, 4> TransformedInits;
   ArrayRef<Expr *> InitExprs = E->getInitExprs();
-  if (TransformExprs(InitExprs.data(), InitExprs.size(), true,
-                     TransformedInits))
+
+  QualType T = getDerived().TransformType(E->getType());
+
+  bool ArgChanged = false;
+  ;
+
+  if (getDerived().TransformExprs(InitExprs.data(), InitExprs.size(), true,
+                                  TransformedInits, &ArgChanged))
     return ExprError();
 
-  return getDerived().RebuildParenListExpr(E->getBeginLoc(), TransformedInits,
-                                           E->getEndLoc());
+  if (!ArgChanged && T == E->getType())
+    return E;
+
+  return getDerived().RebuildCXXParenListInitExpr(
+      TransformedInits, T, E->getUserSpecifiedInitExprs().size(),
+      E->getInitLoc(), E->getBeginLoc(), E->getEndLoc());
 }
 
 template<typename Derived>
diff --git a/clang/test/SemaCXX/paren-list-agg-init.cpp b/clang/test/SemaCXX/paren-list-agg-init.cpp
index b2d0f2564bb59..ba7dffdc1af9f 100644
--- a/clang/test/SemaCXX/paren-list-agg-init.cpp
+++ b/clang/test/SemaCXX/paren-list-agg-init.cpp
@@ -83,7 +83,7 @@ template <typename T, char CH>
 void bar() {
   T t = 0;
   A a(CH, 1.1); // OK; C++ paren list constructors are supported in semantic tree transformations.
-  // beforecxx20-warning at -1 2{{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
+  // beforecxx20-warning at -1 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
 }
 
 template <class T, class... Args>
@@ -157,9 +157,6 @@ void foo(int n) { // expected-note {{declared here}}
   constexpr F f2(1, 1); // OK: f2.b is initialized by a constant expression.
   // beforecxx20-warning at -1 {{aggregate initialization of type 'const F' from a parenthesized list of values is a C++20 extension}}
 
-  bar<int, 'a'>();
-  // beforecxx20-note at -1 {{in instantiation of function template specialization 'bar<int, 'a'>' requested here}}
-
   G<char> g('b', 'b');
   // beforecxx20-warning at -1 {{aggregate initialization of type 'G<char>' from a parenthesized list of values is a C++20 extension}}
 
@@ -354,7 +351,7 @@ using Td = int[]; Td d(42,43);
 // beforecxx20-warning at -1 {{aggregate initialization of type 'int[2]' from a parenthesized list of values is a C++20 extension}}
 template<typename T, int Sz> using ThroughAlias = T[Sz];
 ThroughAlias<int, 1> e(42);
-// beforecxx20-warning at -1 {{aggregate initialization of type 'ThroughAlias<int, 1>' (aka 'int[1]') from a parenthesized list of values is a C++20 extension}} 
+// beforecxx20-warning at -1 {{aggregate initialization of type 'ThroughAlias<int, 1>' (aka 'int[1]') from a parenthesized list of values is a C++20 extension}}
 
 }
 
@@ -376,3 +373,33 @@ static_assert(S(1, 2) == S(3, 4));
 // beforecxx20-warning at -1 2{{C++20 extension}}
 
 }
+
+namespace GH72880 {
+struct Base {};
+struct Derived : Base {
+    int count = 42;
+};
+
+template <typename T>
+struct BaseTpl {};
+template <typename T>
+struct DerivedTpl : BaseTpl<T> {
+    int count = 43;
+};
+template <typename T> struct S {
+  void f() {
+      Derived a = static_cast<Derived>(Base());
+      // beforecxx20-warning at -1 {{C++20 extension}}
+      DerivedTpl b = static_cast<DerivedTpl<T>>(BaseTpl<T>());
+      // beforecxx20-warning at -1 {{C++20 extension}}
+      static_assert(static_cast<Derived>(Base()).count == 42);
+      // beforecxx20-warning at -1 {{C++20 extension}}
+      static_assert(static_cast<DerivedTpl<T>>(BaseTpl<T>()).count == 43);
+      // beforecxx20-warning at -1 {{C++20 extension}}
+  }
+};
+
+void test() {
+    S<int>{}.f(); // beforecxx20-note {{requested here}}
+}
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/138518


More information about the cfe-commits mailing list