Skip to content

Commit 13926e1

Browse files
authored
[Clang] Preserve CXXParenListInitExpr in TreeTransform. (#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
1 parent 15c2f79 commit 13926e1

File tree

6 files changed

+76
-11
lines changed

6 files changed

+76
-11
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ Bug Fixes to C++ Support
649649
(#GH136432), (#GH137014), (#GH138018)
650650
- Fixed an assertion when trying to constant-fold various builtins when the argument
651651
referred to a reference to an incomplete type. (#GH129397)
652+
- Fixed a crash when a cast involved a parenthesized aggregate initialization in dependent context. (#GH72880)
652653

653654
Bug Fixes to AST Handling
654655
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/ExprCXX.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5124,8 +5124,8 @@ class CXXParenListInitExpr final
51245124

51255125
void updateDependence() { setDependence(computeDependence(this)); }
51265126

5127-
ArrayRef<Expr *> getInitExprs() {
5128-
return ArrayRef(getTrailingObjects<Expr *>(), NumExprs);
5127+
MutableArrayRef<Expr *> getInitExprs() {
5128+
return MutableArrayRef(getTrailingObjects<Expr *>(), NumExprs);
51295129
}
51305130

51315131
const ArrayRef<Expr *> getInitExprs() const {

clang/include/clang/Sema/Sema.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7167,6 +7167,11 @@ class Sema final : public SemaBase {
71677167
ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E);
71687168
ExprResult ActOnParenListExpr(SourceLocation L, SourceLocation R,
71697169
MultiExprArg Val);
7170+
ExprResult ActOnCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
7171+
unsigned NumUserSpecifiedExprs,
7172+
SourceLocation InitLoc,
7173+
SourceLocation LParenLoc,
7174+
SourceLocation RParenLoc);
71707175

71717176
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
71727177
/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle

clang/lib/Sema/SemaExpr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7985,6 +7985,15 @@ ExprResult Sema::ActOnParenListExpr(SourceLocation L,
79857985
return ParenListExpr::Create(Context, L, Val, R);
79867986
}
79877987

7988+
ExprResult Sema::ActOnCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
7989+
unsigned NumUserSpecifiedExprs,
7990+
SourceLocation InitLoc,
7991+
SourceLocation LParenLoc,
7992+
SourceLocation RParenLoc) {
7993+
return CXXParenListInitExpr::Create(Context, Args, T, NumUserSpecifiedExprs,
7994+
InitLoc, LParenLoc, RParenLoc);
7995+
}
7996+
79887997
bool Sema::DiagnoseConditionalForNull(const Expr *LHSExpr, const Expr *RHSExpr,
79897998
SourceLocation QuestionLoc) {
79907999
const Expr *NullExpr = LHSExpr;

clang/lib/Sema/TreeTransform.h

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3099,6 +3099,15 @@ class TreeTransform {
30993099
return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, SubExprs);
31003100
}
31013101

3102+
ExprResult RebuildCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
3103+
unsigned NumUserSpecifiedExprs,
3104+
SourceLocation InitLoc,
3105+
SourceLocation LParenLoc,
3106+
SourceLocation RParenLoc) {
3107+
return getSema().ActOnCXXParenListInitExpr(Args, T, NumUserSpecifiedExprs,
3108+
InitLoc, LParenLoc, RParenLoc);
3109+
}
3110+
31023111
/// Build a new address-of-label expression.
31033112
///
31043113
/// By default, performs semantic analysis, using the name of the label
@@ -3315,6 +3324,11 @@ class TreeTransform {
33153324
return getSema().BuildCXXTypeConstructExpr(
33163325
TInfo, LParenLoc, MultiExprArg(PLE->getExprs(), PLE->getNumExprs()),
33173326
RParenLoc, ListInitialization);
3327+
3328+
if (auto *PLE = dyn_cast<CXXParenListInitExpr>(Sub))
3329+
return getSema().BuildCXXTypeConstructExpr(
3330+
TInfo, LParenLoc, PLE->getInitExprs(), RParenLoc, ListInitialization);
3331+
33183332
return getSema().BuildCXXTypeConstructExpr(TInfo, LParenLoc,
33193333
MultiExprArg(&Sub, 1), RParenLoc,
33203334
ListInitialization);
@@ -16487,12 +16501,21 @@ ExprResult
1648716501
TreeTransform<Derived>::TransformCXXParenListInitExpr(CXXParenListInitExpr *E) {
1648816502
SmallVector<Expr *, 4> TransformedInits;
1648916503
ArrayRef<Expr *> InitExprs = E->getInitExprs();
16490-
if (TransformExprs(InitExprs.data(), InitExprs.size(), true,
16491-
TransformedInits))
16504+
16505+
QualType T = getDerived().TransformType(E->getType());
16506+
16507+
bool ArgChanged = false;
16508+
16509+
if (getDerived().TransformExprs(InitExprs.data(), InitExprs.size(), true,
16510+
TransformedInits, &ArgChanged))
1649216511
return ExprError();
1649316512

16494-
return getDerived().RebuildParenListExpr(E->getBeginLoc(), TransformedInits,
16495-
E->getEndLoc());
16513+
if (!getDerived().AlwaysRebuild() && !ArgChanged && T == E->getType())
16514+
return E;
16515+
16516+
return getDerived().RebuildCXXParenListInitExpr(
16517+
TransformedInits, T, E->getUserSpecifiedInitExprs().size(),
16518+
E->getInitLoc(), E->getBeginLoc(), E->getEndLoc());
1649616519
}
1649716520

1649816521
template<typename Derived>

clang/test/SemaCXX/paren-list-agg-init.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ template <typename T, char CH>
8383
void bar() {
8484
T t = 0;
8585
A a(CH, 1.1); // OK; C++ paren list constructors are supported in semantic tree transformations.
86-
// beforecxx20-warning@-1 2{{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
86+
// beforecxx20-warning@-1 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
8787
}
8888

8989
template <class T, class... Args>
@@ -157,9 +157,6 @@ void foo(int n) { // expected-note {{declared here}}
157157
constexpr F f2(1, 1); // OK: f2.b is initialized by a constant expression.
158158
// beforecxx20-warning@-1 {{aggregate initialization of type 'const F' from a parenthesized list of values is a C++20 extension}}
159159

160-
bar<int, 'a'>();
161-
// beforecxx20-note@-1 {{in instantiation of function template specialization 'bar<int, 'a'>' requested here}}
162-
163160
G<char> g('b', 'b');
164161
// beforecxx20-warning@-1 {{aggregate initialization of type 'G<char>' from a parenthesized list of values is a C++20 extension}}
165162

@@ -354,7 +351,7 @@ using Td = int[]; Td d(42,43);
354351
// beforecxx20-warning@-1 {{aggregate initialization of type 'int[2]' from a parenthesized list of values is a C++20 extension}}
355352
template<typename T, int Sz> using ThroughAlias = T[Sz];
356353
ThroughAlias<int, 1> e(42);
357-
// beforecxx20-warning@-1 {{aggregate initialization of type 'ThroughAlias<int, 1>' (aka 'int[1]') from a parenthesized list of values is a C++20 extension}}
354+
// beforecxx20-warning@-1 {{aggregate initialization of type 'ThroughAlias<int, 1>' (aka 'int[1]') from a parenthesized list of values is a C++20 extension}}
358355

359356
}
360357

@@ -376,3 +373,33 @@ static_assert(S(1, 2) == S(3, 4));
376373
// beforecxx20-warning@-1 2{{C++20 extension}}
377374

378375
}
376+
377+
namespace GH72880 {
378+
struct Base {};
379+
struct Derived : Base {
380+
int count = 42;
381+
};
382+
383+
template <typename T>
384+
struct BaseTpl {};
385+
template <typename T>
386+
struct DerivedTpl : BaseTpl<T> {
387+
int count = 43;
388+
};
389+
template <typename T> struct S {
390+
void f() {
391+
Derived a = static_cast<Derived>(Base());
392+
// beforecxx20-warning@-1 {{C++20 extension}}
393+
DerivedTpl b = static_cast<DerivedTpl<T>>(BaseTpl<T>());
394+
// beforecxx20-warning@-1 {{C++20 extension}}
395+
static_assert(static_cast<Derived>(Base()).count == 42);
396+
// beforecxx20-warning@-1 {{C++20 extension}}
397+
static_assert(static_cast<DerivedTpl<T>>(BaseTpl<T>()).count == 43);
398+
// beforecxx20-warning@-1 {{C++20 extension}}
399+
}
400+
};
401+
402+
void test() {
403+
S<int>{}.f(); // beforecxx20-note {{requested here}}
404+
}
405+
}

0 commit comments

Comments
 (0)