Skip to content

Commit 943ad73

Browse files
authored
Merge branch 'main' into clang-CWG2517
2 parents 5a939a7 + f3a1421 commit 943ad73

File tree

394 files changed

+9061
-7162
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

394 files changed

+9061
-7162
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ Bug Fixes to C++ Support
356356
- Fixed an assertion failure affecting code that uses C++23 "deducing this". (#GH130272)
357357
- Clang now properly instantiates destructors for initialized members within non-delegating constructors. (#GH93251)
358358
- Correctly diagnoses if unresolved using declarations shadows template paramters (#GH129411)
359+
- Fixed C++20 aggregate initialization rules being incorrectly applied in certain contexts. (#GH131320)
359360
- Clang was previously coalescing volatile writes to members of volatile base class subobjects.
360361
The issue has been addressed by propagating qualifiers during derived-to-base conversions in the AST. (#GH127824)
361362
- Fixed a Clang regression in C++20 mode where unresolved dependent call expressions were created inside non-dependent contexts (#GH122892)

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,7 +1818,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
18181818
for (const Expr *Init : Inits) {
18191819
// Skip unnamed bitfields.
18201820
while (InitIndex < R->getNumFields() &&
1821-
R->getField(InitIndex)->Decl->isUnnamedBitField())
1821+
R->getField(InitIndex)->isUnnamedBitField())
18221822
++InitIndex;
18231823

18241824
if (std::optional<PrimType> T = classify(Init)) {
@@ -4084,7 +4084,7 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
40844084
assert(R);
40854085
// Fields
40864086
for (const Record::Field &Field : R->fields()) {
4087-
if (Field.Decl->isUnnamedBitField())
4087+
if (Field.isUnnamedBitField())
40884088
continue;
40894089

40904090
const Descriptor *D = Field.Desc;

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,10 @@ IntPointer IntPointer::atOffset(const ASTContext &ASTCtx,
720720

721721
IntPointer IntPointer::baseCast(const ASTContext &ASTCtx,
722722
unsigned BaseOffset) const {
723+
if (!Desc) {
724+
assert(Value == 0);
725+
return *this;
726+
}
723727
const Record *R = Desc->ElemRecord;
724728
const Descriptor *BaseDesc = nullptr;
725729

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,7 @@ void UnwrappedLineParser::parseStructuralElement(
17081708
break;
17091709
}
17101710

1711+
bool SeenEqual = false;
17111712
for (const bool InRequiresExpression =
17121713
OpeningBrace && OpeningBrace->isOneOf(TT_RequiresExpressionLBrace,
17131714
TT_CompoundRequirementLBrace);
@@ -1782,7 +1783,7 @@ void UnwrappedLineParser::parseStructuralElement(
17821783
break;
17831784
case tok::kw_requires: {
17841785
if (IsCpp) {
1785-
bool ParsedClause = parseRequires();
1786+
bool ParsedClause = parseRequires(SeenEqual);
17861787
if (ParsedClause)
17871788
return;
17881789
} else {
@@ -2062,6 +2063,7 @@ void UnwrappedLineParser::parseStructuralElement(
20622063
break;
20632064
}
20642065

2066+
SeenEqual = true;
20652067
nextToken();
20662068
if (FormatTok->is(tok::l_brace)) {
20672069
// Block kind should probably be set to BK_BracedInit for any language.
@@ -3416,7 +3418,7 @@ void UnwrappedLineParser::parseAccessSpecifier() {
34163418
/// \brief Parses a requires, decides if it is a clause or an expression.
34173419
/// \pre The current token has to be the requires keyword.
34183420
/// \returns true if it parsed a clause.
3419-
bool UnwrappedLineParser::parseRequires() {
3421+
bool UnwrappedLineParser::parseRequires(bool SeenEqual) {
34203422
assert(FormatTok->is(tok::kw_requires) && "'requires' expected");
34213423
auto RequiresToken = FormatTok;
34223424

@@ -3472,7 +3474,7 @@ bool UnwrappedLineParser::parseRequires() {
34723474
// We check the one token before that for a const:
34733475
// void member(...) const && requires (C<T> ...
34743476
auto PrevPrev = PreviousNonComment->getPreviousNonComment();
3475-
if (PrevPrev && PrevPrev->is(tok::kw_const)) {
3477+
if ((PrevPrev && PrevPrev->is(tok::kw_const)) || !SeenEqual) {
34763478
parseRequiresClause(RequiresToken);
34773479
return true;
34783480
}

clang/lib/Format/UnwrappedLineParser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class UnwrappedLineParser {
167167
void parseAccessSpecifier();
168168
bool parseEnum();
169169
bool parseStructLike();
170-
bool parseRequires();
170+
bool parseRequires(bool SeenEqual);
171171
void parseRequiresClause(FormatToken *RequiresToken);
172172
void parseRequiresExpression(FormatToken *RequiresToken);
173173
void parseConstraintExpression();

clang/lib/Sema/SemaInit.cpp

Lines changed: 65 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4634,6 +4634,59 @@ static void TryConstructorInitialization(Sema &S,
46344634
IsListInit | IsInitListCopy, AsInitializerList);
46354635
}
46364636

4637+
static void TryOrBuildParenListInitialization(
4638+
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
4639+
ArrayRef<Expr *> Args, InitializationSequence &Sequence, bool VerifyOnly,
4640+
ExprResult *Result = nullptr);
4641+
4642+
/// Attempt to initialize an object of a class type either by
4643+
/// direct-initialization, or by copy-initialization from an
4644+
/// expression of the same or derived class type. This corresponds
4645+
/// to the first two sub-bullets of C++2c [dcl.init.general] p16.6.
4646+
///
4647+
/// \param IsAggrListInit Is this non-list-initialization being done as
4648+
/// part of a list-initialization of an aggregate
4649+
/// from a single expression of the same or
4650+
/// derived class type (C++2c [dcl.init.list] p3.2)?
4651+
static void TryConstructorOrParenListInitialization(
4652+
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
4653+
MultiExprArg Args, QualType DestType, InitializationSequence &Sequence,
4654+
bool IsAggrListInit) {
4655+
// C++2c [dcl.init.general] p16.6:
4656+
// * Otherwise, if the destination type is a class type:
4657+
// * If the initializer expression is a prvalue and
4658+
// the cv-unqualified version of the source type is the same
4659+
// as the destination type, the initializer expression is used
4660+
// to initialize the destination object.
4661+
// * Otherwise, if the initialization is direct-initialization,
4662+
// or if it is copy-initialization where the cv-unqualified
4663+
// version of the source type is the same as or is derived from
4664+
// the class of the destination type, constructors are considered.
4665+
// The applicable constructors are enumerated, and the best one
4666+
// is chosen through overload resolution. Then:
4667+
// * If overload resolution is successful, the selected
4668+
// constructor is called to initialize the object, with
4669+
// the initializer expression or expression-list as its
4670+
// argument(s).
4671+
TryConstructorInitialization(S, Entity, Kind, Args, DestType, DestType,
4672+
Sequence, /*IsListInit=*/false, IsAggrListInit);
4673+
4674+
// * Otherwise, if no constructor is viable, the destination type
4675+
// is an aggregate class, and the initializer is a parenthesized
4676+
// expression-list, the object is initialized as follows. [...]
4677+
// Parenthesized initialization of aggregates is a C++20 feature.
4678+
if (S.getLangOpts().CPlusPlus20 &&
4679+
Kind.getKind() == InitializationKind::IK_Direct && Sequence.Failed() &&
4680+
Sequence.getFailureKind() ==
4681+
InitializationSequence::FK_ConstructorOverloadFailed &&
4682+
Sequence.getFailedOverloadResult() == OR_No_Viable_Function &&
4683+
(IsAggrListInit || DestType->isAggregateType()))
4684+
TryOrBuildParenListInitialization(S, Entity, Kind, Args, Sequence,
4685+
/*VerifyOnly=*/true);
4686+
4687+
// * Otherwise, the initialization is ill-formed.
4688+
}
4689+
46374690
static bool
46384691
ResolveOverloadedFunctionForReferenceBinding(Sema &S,
46394692
Expr *Initializer,
@@ -4847,11 +4900,16 @@ static void TryListInitialization(Sema &S,
48474900
QualType InitType = InitList->getInit(0)->getType();
48484901
if (S.Context.hasSameUnqualifiedType(InitType, DestType) ||
48494902
S.IsDerivedFrom(InitList->getBeginLoc(), InitType, DestType)) {
4903+
InitializationKind SubKind =
4904+
Kind.getKind() == InitializationKind::IK_DirectList
4905+
? InitializationKind::CreateDirect(Kind.getLocation(),
4906+
InitList->getLBraceLoc(),
4907+
InitList->getRBraceLoc())
4908+
: Kind;
48504909
Expr *InitListAsExpr = InitList;
4851-
TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType,
4852-
DestType, Sequence,
4853-
/*InitListSyntax*/false,
4854-
/*IsInitListCopy*/true);
4910+
TryConstructorOrParenListInitialization(
4911+
S, Entity, SubKind, InitListAsExpr, DestType, Sequence,
4912+
/*IsAggrListInit=*/true);
48554913
return;
48564914
}
48574915
}
@@ -5710,7 +5768,7 @@ static void TryDefaultInitialization(Sema &S,
57105768
static void TryOrBuildParenListInitialization(
57115769
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
57125770
ArrayRef<Expr *> Args, InitializationSequence &Sequence, bool VerifyOnly,
5713-
ExprResult *Result = nullptr) {
5771+
ExprResult *Result) {
57145772
unsigned EntityIndexToProcess = 0;
57155773
SmallVector<Expr *, 4> InitExprs;
57165774
QualType ResultType;
@@ -6689,42 +6747,8 @@ void InitializationSequence::InitializeFrom(Sema &S,
66896747
(Context.hasSameUnqualifiedType(SourceType, DestType) ||
66906748
(Initializer && S.IsDerivedFrom(Initializer->getBeginLoc(),
66916749
SourceType, DestType))))) {
6692-
TryConstructorInitialization(S, Entity, Kind, Args, DestType, DestType,
6693-
*this);
6694-
6695-
// We fall back to the "no matching constructor" path if the
6696-
// failed candidate set has functions other than the three default
6697-
// constructors. For example, conversion function.
6698-
if (const auto *RD =
6699-
dyn_cast<CXXRecordDecl>(DestType->getAs<RecordType>()->getDecl());
6700-
// In general, we should call isCompleteType for RD to check its
6701-
// completeness, we don't call it here as it was already called in the
6702-
// above TryConstructorInitialization.
6703-
S.getLangOpts().CPlusPlus20 && RD && RD->hasDefinition() &&
6704-
RD->isAggregate() && Failed() &&
6705-
getFailureKind() == FK_ConstructorOverloadFailed) {
6706-
// Do not attempt paren list initialization if overload resolution
6707-
// resolves to a deleted function .
6708-
//
6709-
// We may reach this condition if we have a union wrapping a class with
6710-
// a non-trivial copy or move constructor and we call one of those two
6711-
// constructors. The union is an aggregate, but the matched constructor
6712-
// is implicitly deleted, so we need to prevent aggregate initialization
6713-
// (otherwise, it'll attempt aggregate initialization by initializing
6714-
// the first element with a reference to the union).
6715-
OverloadCandidateSet::iterator Best;
6716-
OverloadingResult OR = getFailedCandidateSet().BestViableFunction(
6717-
S, Kind.getLocation(), Best);
6718-
if (OR != OverloadingResult::OR_Deleted) {
6719-
// C++20 [dcl.init] 17.6.2.2:
6720-
// - Otherwise, if no constructor is viable, the destination type is
6721-
// an
6722-
// aggregate class, and the initializer is a parenthesized
6723-
// expression-list.
6724-
TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
6725-
/*VerifyOnly=*/true);
6726-
}
6727-
}
6750+
TryConstructorOrParenListInitialization(S, Entity, Kind, Args, DestType,
6751+
*this, /*IsAggrListInit=*/false);
67286752
} else {
67296753
// - Otherwise (i.e., for the remaining copy-initialization cases),
67306754
// user-defined conversion sequences that can convert from the

clang/test/AST/ByteCode/records.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,3 +1771,19 @@ namespace RedeclaredCtor {
17711771
constexpr __sp_mut::__sp_mut(void *p) noexcept : __lx_(p) {}
17721772
constexpr __sp_mut muts = &mut_back[0];
17731773
}
1774+
1775+
namespace IntegralBaseCast {
1776+
class A {};
1777+
class B : public A {};
1778+
struct S {
1779+
B *a;
1780+
};
1781+
1782+
constexpr int f() {
1783+
S s{};
1784+
A *a = s.a;
1785+
return 0;
1786+
}
1787+
1788+
static_assert(f() == 0, "");
1789+
}
Lines changed: 117 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,120 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
22

3-
// If the initializer is (), the object is value-initialized.
4-
5-
// expected-no-diagnostics
63
namespace GH69890 {
7-
struct A {
8-
constexpr A() {}
9-
int x;
10-
};
11-
12-
struct B : A {
13-
int y;
14-
};
15-
16-
static_assert(B().x == 0);
17-
static_assert(B().y == 0);
18-
}
4+
// If the initializer is (), the object is value-initialized.
5+
struct A {
6+
constexpr A() {}
7+
int x;
8+
};
9+
10+
struct B : A {
11+
int y;
12+
};
13+
14+
static_assert(B().x == 0);
15+
static_assert(B().y == 0);
16+
} // namespace GH69890
17+
18+
namespace P0960R3 {
19+
struct A { // expected-note 22 {{candidate constructor}}
20+
int i;
21+
operator int() volatile;
22+
};
23+
volatile A va;
24+
25+
A a1(va);
26+
A a2 = va; // expected-error {{no matching constructor for initialization of 'A'}}
27+
A a3 {va};
28+
A a4 = {va}; // expected-error {{no matching constructor for initialization of 'A'}}
29+
30+
A f() {
31+
return va; // expected-error {{no matching constructor for initialization of 'A'}}
32+
return {va}; // expected-error {{no matching constructor for initialization of 'A'}}
33+
}
34+
35+
int g(A); // expected-note 2 {{passing argument to parameter here}}
36+
int i = g(va); // expected-error {{no matching constructor for initialization of 'A'}}
37+
int j = g({va}); // expected-error {{no matching constructor for initialization of 'A'}}
38+
39+
struct Ambig {
40+
operator const A&(); // expected-note {{candidate function}}
41+
operator A&&(); // expected-note {{candidate function}}
42+
operator int();
43+
};
44+
45+
A a5(Ambig {}); // expected-error {{call to constructor of 'A' is ambiguous}}
46+
A a6 = Ambig {}; // expected-error {{conversion from 'Ambig' to 'A' is ambiguous}}
47+
A a7 {Ambig {}};
48+
A a8 = {Ambig {}};
49+
50+
A a9(1);
51+
A a10 = 1; // expected-error {{no viable conversion from 'int' to 'A'}}
52+
A a11 {1};
53+
A a12 = {1};
54+
55+
56+
struct B { // expected-note 12 {{candidate constructor}}
57+
int i;
58+
virtual operator int() volatile;
59+
};
60+
volatile B vb;
61+
62+
B b1(vb); // expected-error {{no matching constructor for initialization of 'B'}}
63+
B b2 = vb; // expected-error {{no matching constructor for initialization of 'B'}}
64+
B b3 {vb}; // expected-error {{no matching constructor for initialization of 'B'}}
65+
B b4 = {vb}; // expected-error {{no matching constructor for initialization of 'B'}}
66+
67+
68+
struct Immovable {
69+
Immovable();
70+
Immovable(const Immovable&) = delete; // #Imm_copy
71+
};
72+
73+
struct C { // #C
74+
int i;
75+
Immovable j; // #C_j
76+
77+
operator int() volatile;
78+
};
79+
C c;
80+
volatile C vc;
81+
82+
C c1(c); // expected-error {{call to implicitly-deleted copy constructor of 'C'}}
83+
C c2 = c; // expected-error {{call to implicitly-deleted copy constructor of 'C'}}
84+
C c3 {c}; // expected-error {{call to implicitly-deleted copy constructor of 'C'}}
85+
C c4 = {c}; // expected-error {{call to implicitly-deleted copy constructor of 'C'}}
86+
// expected-note@#C_j 4 {{copy constructor of 'C' is implicitly deleted}}
87+
// expected-note@#Imm_copy 4 {{'Immovable' has been explicitly marked deleted here}}
88+
89+
C c5(vc);
90+
C c6 = vc; // expected-error {{no matching constructor for initialization of 'C'}}
91+
C c7 {vc};
92+
C c8 = {vc}; // expected-error {{no matching constructor for initialization of 'C'}}
93+
// expected-note@#C 4 {{candidate constructor}}
94+
95+
C c9(C {});
96+
C c10 = C(123);
97+
C c11 {C {0, Immovable()}};
98+
C c12 = {C()};
99+
100+
101+
struct D { // expected-note 6 {{candidate constructor}}
102+
int i;
103+
};
104+
105+
struct DD : private D { // expected-note 4 {{declared private here}}
106+
virtual operator int() volatile;
107+
};
108+
DD dd;
109+
volatile DD vdd;
110+
111+
D d1(dd); // expected-error {{cannot cast 'const DD' to its private base class 'const D'}}
112+
D d2 = dd; // expected-error {{cannot cast 'const DD' to its private base class 'const D'}}
113+
D d3 {dd}; // expected-error {{cannot cast 'const DD' to its private base class 'const D'}}
114+
D d4 = {dd}; // expected-error {{cannot cast 'const DD' to its private base class 'const D'}}
115+
116+
D d5(vdd);
117+
D d6 = vdd; // expected-error {{no matching constructor for initialization of 'D'}}
118+
D d7 {vdd};
119+
D d8 = {vdd}; // expected-error {{no matching constructor for initialization of 'D'}}
120+
} // namespace P0960R3

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,15 @@ TEST_F(TokenAnnotatorTest, UnderstandsRequiresClausesAndConcepts) {
13991399
ASSERT_EQ(Tokens.size(), 19u) << Tokens;
14001400
EXPECT_TOKEN(Tokens[4], tok::amp, TT_PointerOrReference);
14011401
EXPECT_TOKEN(Tokens[5], tok::kw_requires, TT_RequiresClause);
1402+
1403+
Tokens = annotate("void foo() &&\n"
1404+
" requires(!bar)\n"
1405+
"{\n"
1406+
" baz();\n"
1407+
"}");
1408+
ASSERT_EQ(Tokens.size(), 17u) << Tokens;
1409+
EXPECT_TOKEN(Tokens[4], tok::ampamp, TT_PointerOrReference);
1410+
EXPECT_TOKEN(Tokens[5], tok::kw_requires, TT_RequiresClause);
14021411
}
14031412

14041413
TEST_F(TokenAnnotatorTest, UnderstandsRequiresExpressions) {

0 commit comments

Comments
 (0)