Skip to content

[Clang] Preserve CXXParenListInitExpr in TreeTransform. #138518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
31 changes: 27 additions & 4 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -16487,12 +16501,21 @@ 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 (!getDerived().AlwaysRebuild() && !ArgChanged && T == E->getType())
return E;

return getDerived().RebuildCXXParenListInitExpr(
TransformedInits, T, E->getUserSpecifiedInitExprs().size(),
E->getInitLoc(), E->getBeginLoc(), E->getEndLoc());
}

template<typename Derived>
Expand Down
37 changes: 32 additions & 5 deletions clang/test/SemaCXX/paren-list-agg-init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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@-1 2{{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
// beforecxx20-warning@-1 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
}

template <class T, class... Args>
Expand Down Expand Up @@ -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@-1 {{aggregate initialization of type 'const F' from a parenthesized list of values is a C++20 extension}}

bar<int, 'a'>();
// beforecxx20-note@-1 {{in instantiation of function template specialization 'bar<int, 'a'>' requested here}}

G<char> g('b', 'b');
// beforecxx20-warning@-1 {{aggregate initialization of type 'G<char>' from a parenthesized list of values is a C++20 extension}}

Expand Down Expand Up @@ -354,7 +351,7 @@ using Td = int[]; Td d(42,43);
// beforecxx20-warning@-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@-1 {{aggregate initialization of type 'ThroughAlias<int, 1>' (aka 'int[1]') from a parenthesized list of values is a C++20 extension}}
// beforecxx20-warning@-1 {{aggregate initialization of type 'ThroughAlias<int, 1>' (aka 'int[1]') from a parenthesized list of values is a C++20 extension}}

}

Expand All @@ -376,3 +373,33 @@ static_assert(S(1, 2) == S(3, 4));
// beforecxx20-warning@-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@-1 {{C++20 extension}}
DerivedTpl b = static_cast<DerivedTpl<T>>(BaseTpl<T>());
// beforecxx20-warning@-1 {{C++20 extension}}
static_assert(static_cast<Derived>(Base()).count == 42);
// beforecxx20-warning@-1 {{C++20 extension}}
static_assert(static_cast<DerivedTpl<T>>(BaseTpl<T>()).count == 43);
// beforecxx20-warning@-1 {{C++20 extension}}
}
};

void test() {
S<int>{}.f(); // beforecxx20-note {{requested here}}
}
}