[clang] [Clang] Preserve CXXParenListInitExpr in TreeTransform. (PR #138518)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 5 05:36:15 PDT 2025
https://github.com/cor3ntin created https://github.com/llvm/llvm-project/pull/138518
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
>From 22af52cc153282e27178f16350fc9a2bb312b0a0 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 5 May 2025 14:31:10 +0200
Subject: [PATCH] [Clang] Preserve CXXParenListInitExpr in TreeTransform.
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
---
clang/docs/ReleaseNotes.rst | 1 +
clang/include/clang/AST/ExprCXX.h | 4 +--
clang/include/clang/Sema/Sema.h | 5 +++
clang/lib/Sema/SemaExpr.cpp | 9 ++++++
clang/lib/Sema/TreeTransform.h | 32 ++++++++++++++++---
clang/test/SemaCXX/paren-list-agg-init.cpp | 37 +++++++++++++++++++---
6 files changed, 77 insertions(+), 11 deletions(-)
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}}
+}
+}
More information about the cfe-commits
mailing list