Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
Gracefully (and correctly) handle init of multiple union members
Browse files Browse the repository at this point in the history
We now emit warnings when doing so and code generation is consistent
with GCC. Note that the C99 spec is unclear as to the precise
behavior.

See also ...
Bug:
  http://llvm.org/bugs/show_bug.cgi?id=16644 and

cfe-dev discussion:
  http://lists.cs.uiuc.edu/pipermail/cfe-dev/2013-September/031918.html



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191890 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Matthew Curtis committed Oct 3, 2013
1 parent 618c285 commit 4e49952
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 2 deletions.
4 changes: 4 additions & 0 deletions include/clang/AST/Expr.h
Expand Up @@ -3824,6 +3824,10 @@ class InitListExpr : public Expr {
return const_cast<InitListExpr *>(this)->getInitializedFieldInUnion();
}
void setInitializedFieldInUnion(FieldDecl *FD) {
assert((FD == 0
|| getInitializedFieldInUnion() == 0
|| getInitializedFieldInUnion() == FD)
&& "Only one field of a union may be initialized at a time!");
ArrayFillerOrUnionFieldInit = FD;
}

Expand Down
23 changes: 22 additions & 1 deletion lib/Sema/SemaInit.cpp
Expand Up @@ -1868,8 +1868,29 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// the initializer list.
if (RT->getDecl()->isUnion()) {
FieldIndex = 0;
if (!VerifyOnly)
if (!VerifyOnly) {
FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion();
if (CurrentField && CurrentField != *Field) {
assert(StructuredList->getNumInits() == 1
&& "A union should never have more than one initializer!");

// we're about to throw away an initializer, emit warning
SemaRef.Diag(D->getFieldLoc(),
diag::warn_initializer_overrides)
<< D->getSourceRange();
Expr *ExistingInit = StructuredList->getInit(0);
SemaRef.Diag(ExistingInit->getLocStart(),
diag::note_previous_initializer)
<< /*FIXME:has side effects=*/0
<< ExistingInit->getSourceRange();

// remove existing initializer
StructuredList->resizeInits(SemaRef.Context, 0);
StructuredList->setInitializedFieldInUnion(0);
}

StructuredList->setInitializedFieldInUnion(*Field);
}
}

// Make sure we can use this declaration.
Expand Down
57 changes: 57 additions & 0 deletions test/CodeGen/designated-initializers.c
Expand Up @@ -81,6 +81,63 @@ struct overwrite_string_struct5 {
// CHECK: [6 x i8] c"foo\00y\00", i32 1


// CHECK: @u1 = {{.*}} { i32 65535 }
union u_FFFF { char c; long l; } u1 = { .l = 0xFFFF };


/// PR16644
typedef union u_16644 {
struct s_16644 {
int zero;
int one;
int two;
int three;
} a;
int b[4];
} union_16644_t;

// CHECK: @union_16644_instance_0 = {{.*}} { i32 0, i32 0, i32 0, i32 3 } }
union_16644_t union_16644_instance_0 =
{
.b[0] = 0,
.a.one = 1,
.b[2] = 2,
.a.three = 3,
};

// CHECK: @union_16644_instance_1 = {{.*}} [i32 10, i32 0, i32 0, i32 0]
union_16644_t union_16644_instance_1 =
{
.a.three = 13,
.b[2] = 12,
.a.one = 11,
.b[0] = 10,
};

// CHECK: @union_16644_instance_2 = {{.*}} [i32 0, i32 20, i32 0, i32 0]
union_16644_t union_16644_instance_2 =
{
.a.one = 21,
.b[1] = 20,
};

// CHECK: @union_16644_instance_3 = {{.*}} { i32 0, i32 31, i32 0, i32 0 }
union_16644_t union_16644_instance_3 =
{
.b[1] = 30,
.a = {
.one = 31
}
};

// CHECK: @union_16644_instance_4 = {{.*}} { i32 5, i32 2, i32 0, i32 0 } {{.*}} [i32 0, i32 4, i32 0, i32 0]
union_16644_t union_16644_instance_4[2] =
{
[0].a.one = 2,
[1].a.zero = 3,
[0].a.zero = 5,
[1].b[1] = 4
};

void test1(int argc, char **argv)
{
Expand Down
50 changes: 49 additions & 1 deletion test/Sema/designated-initializers.c
Expand Up @@ -137,7 +137,6 @@ void test() {
};
}

// FIXME: How do we test that this initializes the long properly?
union { char c; long l; } u1 = { .l = 0xFFFF };

extern float global_float;
Expand Down Expand Up @@ -223,6 +222,55 @@ struct Enigma enigma = {
};


/// PR16644
typedef union {
struct {
int zero;
int one;
int two;
int three;
} a;
int b[4];
} union_16644_t;

union_16644_t union_16644_instance_0 =
{
.b[0] = 0, // expected-note{{previous}}
.a.one = 1, // expected-warning{{overrides}} expected-note{{previous}}
.b[2] = 2, // expected-warning{{overrides}} expected-note{{previous}}
.a.three = 3, // expected-warning{{overrides}}
};

union_16644_t union_16644_instance_1 =
{
.a.three = 13, // expected-note{{previous}}
.b[2] = 12, // expected-warning{{overrides}} expected-note{{previous}}
.a.one = 11, // expected-warning{{overrides}} expected-note{{previous}}
.b[0] = 10, // expected-warning{{overrides}}
};

union_16644_t union_16644_instance_2 =
{
.a.one = 21, // expected-note{{previous}}
.b[1] = 20, // expected-warning{{overrides}}
};

union_16644_t union_16644_instance_3 =
{
.b[1] = 30, // expected-note{{previous}}
.a = { // expected-warning{{overrides}}
.one = 31
}
};

union_16644_t union_16644_instance_4[2] =
{
[0].a.one = 2,
[1].a.zero = 3,// expected-note{{previous}}
[0].a.zero = 5,
[1].b[1] = 4 // expected-warning{{overrides}}
};

/// PR4073
/// Should use evaluate to fold aggressively and emit a warning if not an ice.
extern int crazy_x;
Expand Down

0 comments on commit 4e49952

Please sign in to comment.