Skip to content

Commit 559c9fb

Browse files
committed
This patch fixes multiple issues in clang's designated init builder and
completes support for C1X anonymous struct/union init features: * Indexed anonymous member initializers should not be expanded. Doing so makes little sense and would cause unresolvable semantic ambiguity in valid code (regression introduced by r69153). * Subobject initialization of (possibly nested) anonymous members are now referred to with paths relative to the naming record context, eliminating the synthesis of incorrect implicit InitListExprs that caused CodeGen to assert. * Field lookup was missing a null check in IdentifierInfo comparison which caused lookup for a known (already resolved) field to match the first unnamed data member it encountered leading to silent miscompilation. * Subobject paths are no longer built using the general purpose Sema::BuildAnonymousStructUnionMemberPath(). If any corner cases crop up, we will now assert earlier in Sema instead of passing invalid InitListExprs through to CodeGen. Fixes PR6955, from Alp Toker! llvm-svn: 116098
1 parent 8ed5b77 commit 559c9fb

File tree

3 files changed

+85
-11
lines changed

3 files changed

+85
-11
lines changed

clang/lib/Sema/SemaInit.cpp

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,22 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
11671167
StructuredList, StructuredIndex);
11681168
}
11691169

1170+
/// \brief Similar to Sema::BuildAnonymousStructUnionMemberPath() but builds a
1171+
/// relative path and has strict checks.
1172+
static void BuildRelativeAnonymousStructUnionMemberPath(FieldDecl *Field,
1173+
llvm::SmallVectorImpl<FieldDecl *> &Path,
1174+
DeclContext *BaseDC) {
1175+
Path.push_back(Field);
1176+
for (DeclContext *Ctx = Field->getDeclContext();
1177+
!Ctx->Equals(BaseDC);
1178+
Ctx = Ctx->getParent()) {
1179+
ValueDecl *AnonObject =
1180+
cast<RecordDecl>(Ctx)->getAnonymousStructOrUnionObject();
1181+
FieldDecl *AnonField = cast<FieldDecl>(AnonObject);
1182+
Path.push_back(AnonField);
1183+
}
1184+
}
1185+
11701186
/// \brief Expand a field designator that refers to a member of an
11711187
/// anonymous struct or union into a series of field designators that
11721188
/// refers to the field within the appropriate subobject.
@@ -1178,13 +1194,14 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
11781194
unsigned DesigIdx,
11791195
FieldDecl *Field,
11801196
RecordDecl::field_iterator &FieldIter,
1181-
unsigned &FieldIndex) {
1197+
unsigned &FieldIndex,
1198+
DeclContext *BaseDC) {
11821199
typedef DesignatedInitExpr::Designator Designator;
11831200

11841201
// Build the path from the current object to the member of the
11851202
// anonymous struct/union (backwards).
11861203
llvm::SmallVector<FieldDecl *, 4> Path;
1187-
SemaRef.BuildAnonymousStructUnionMemberPath(Field, Path);
1204+
BuildRelativeAnonymousStructUnionMemberPath(Field, Path, BaseDC);
11881205

11891206
// Build the replacement designators.
11901207
llvm::SmallVector<Designator, 4> Replacements;
@@ -1343,7 +1360,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
13431360
if (Field->isUnnamedBitfield())
13441361
continue;
13451362

1346-
if (KnownField == *Field || Field->getIdentifier() == FieldName)
1363+
if (KnownField && KnownField == *Field)
1364+
break;
1365+
if (FieldName && FieldName == Field->getIdentifier())
13471366
break;
13481367

13491368
++FieldIndex;
@@ -1400,10 +1419,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
14001419
cast<RecordDecl>((ReplacementField)->getDeclContext())
14011420
->isAnonymousStructOrUnion()) {
14021421
// Handle an field designator that refers to a member of an
1403-
// anonymous struct or union.
1422+
// anonymous struct or union. This is a C1X feature.
14041423
ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx,
14051424
ReplacementField,
1406-
Field, FieldIndex);
1425+
Field, FieldIndex, RT->getDecl());
14071426
D = DIE->getDesignator(DesigIdx);
14081427
} else if (!KnownField) {
14091428
// The replacement field comes from typo correction; find it
@@ -1421,12 +1440,6 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
14211440
++FieldIndex;
14221441
}
14231442
}
1424-
} else if (!KnownField &&
1425-
cast<RecordDecl>((*Field)->getDeclContext())
1426-
->isAnonymousStructOrUnion()) {
1427-
ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, *Field,
1428-
Field, FieldIndex);
1429-
D = DIE->getDesignator(DesigIdx);
14301443
}
14311444

14321445
// All of the fields of a union are located at the same place in

clang/test/CodeGen/designated-initializers.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,39 @@ int b[2] = {
1919
[1] = 22
2020
};
2121

22+
// PR6955
23+
24+
struct ds {
25+
struct {
26+
struct {
27+
short a;
28+
};
29+
short b;
30+
struct {
31+
short c;
32+
};
33+
};
34+
};
35+
36+
// Traditional C anonymous member init
37+
struct ds ds0 = { { { .a = 0 } } };
38+
// C1X lookup-based anonymous member init cases
39+
struct ds ds1 = { { .a = 1 } };
40+
struct ds ds2 = { { .b = 1 } };
41+
struct ds ds3 = { .a = 0 };
42+
// CHECK: @ds4 = global %3 { %4 { %struct.anon zeroinitializer, i16 0, %struct.anon { i16 1 } } }
43+
struct ds ds4 = { .c = 1 };
44+
struct ds ds5 = { { { .a = 0 } }, .b = 1 };
45+
struct ds ds6 = { { .a = 0, .b = 1 } };
46+
// CHECK: @ds7 = global %3 { %4 { %struct.anon { i16 2 }, i16 3, %struct.anon zeroinitializer } }
47+
struct ds ds7 = {
48+
{ {
49+
.a = 1
50+
} },
51+
.a = 2,
52+
.b = 3
53+
};
54+
2255
void test1(int argc, char **argv)
2356
{
2457
// CHECK: internal global %struct.foo { i8* null, i32 1024 }

clang/test/Sema/designated-initializers.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,31 @@ struct expr expr0 = {
249249
}
250250
}
251251
};
252+
253+
// PR6955
254+
255+
struct ds {
256+
struct {
257+
struct {
258+
unsigned int a;
259+
};
260+
unsigned int b;
261+
struct {
262+
unsigned int c;
263+
};
264+
};
265+
};
266+
267+
// C1X lookup-based anonymous member init cases
268+
struct ds ds0 = {
269+
{ {
270+
.a = 1 // expected-note{{previous initialization is here}}
271+
} },
272+
.a = 2, // expected-warning{{initializer overrides prior initialization of this subobject}}
273+
.b = 3
274+
};
275+
struct ds ds1 = { .c = 0 };
276+
struct ds ds2 = { { {
277+
.a = 0,
278+
.b = 1 // expected-error{{field designator 'b' does not refer to any field}}
279+
} } };

0 commit comments

Comments
 (0)