Implement semantic analysis for the GNU flexible array initialization

extension. The interaction with designated initializers is a
bit... interesting... but we follow GNU's lead and don't permit too
much crazy code in this area.

Also, make the "excess initializers" error message a bit more
informative.

Addresses PR2561: http://llvm.org/bugs/show_bug.cgi?id=2561

llvm-svn: 63785
This commit is contained in:
Douglas Gregor 2009-02-04 22:46:25 +00:00
parent 82f071faa7
commit fc4f8a1834
6 changed files with 186 additions and 39 deletions

View File

@ -60,6 +60,10 @@ DIAG(warn_initializer_overrides, WARNING,
"initializer overrides prior initialization of this subobject")
DIAG(note_previous_initializer, NOTE,
"previous initialization %select{|with side effects }0is here%select{| (side effects may not occur at run time)}0")
DIAG(err_designator_into_flexible_array_member, ERROR,
"designator into flexible array member subobject")
DIAG(note_flexible_array_member, NOTE,
"initialized flexible array member %0 is here")
// Declarations.
DIAG(ext_vla, EXTENSION,
@ -547,7 +551,7 @@ DIAG(err_variable_object_no_init, ERROR,
DIAG(err_array_init_list_required, ERROR,
"initialization with '{...}' expected for array")
DIAG(err_excess_initializers, ERROR,
"excess elements in array initializer")
"excess elements in %select{array|vector|scalar|union|struct}0 initializer")
DIAG(err_excess_initializers_in_char_array_initializer, ERROR,
"excess elements in char array initializer")
DIAG(warn_initializer_string_for_char_array_too_long, WARNING,
@ -593,6 +597,10 @@ DIAG(ext_flexible_array_in_struct, EXTENSION,
"%0 may not be nested in a struct due to flexible array member")
DIAG(err_flexible_array_in_array, ERROR,
"%0 may not be used as an array element due to flexible array member")
DIAG(err_flexible_array_init_nonempty, ERROR,
"non-empty initialization of flexible array member inside subobject")
DIAG(err_flexible_array_init_needs_braces, ERROR,
"flexible array requires brace-enclosed initializer")
DIAG(err_illegal_decl_array_of_functions, ERROR,
"'%0' declared as array of functions")
DIAG(err_illegal_decl_array_incomplete_type, ERROR,

View File

@ -50,11 +50,13 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
"Invalid modifier for DeclarationName argument");
} else {
assert(Kind == Diagnostic::ak_nameddecl);
assert(ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0 &&
if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString();
else {
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for NamedDecl* argument");
S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString();
S = reinterpret_cast<NamedDecl*>(Val)->getNameAsString();
}
}
Output.append(S.begin(), S.end());
}

View File

@ -56,15 +56,18 @@ class InitListChecker {
void CheckImplicitInitList(InitListExpr *ParentIList, QualType T,
unsigned &Index, InitListExpr *StructuredList,
unsigned &StructuredIndex);
unsigned &StructuredIndex,
bool TopLevelObject = false);
void CheckExplicitInitList(InitListExpr *IList, QualType &T,
unsigned &Index, InitListExpr *StructuredList,
unsigned &StructuredIndex);
unsigned &StructuredIndex,
bool TopLevelObject = false);
void CheckListElementTypes(InitListExpr *IList, QualType &DeclType,
bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
unsigned &StructuredIndex,
bool TopLevelObject = false);
void CheckSubElementType(InitListExpr *IList, QualType ElemType,
unsigned &Index,
InitListExpr *StructuredList,
@ -84,7 +87,8 @@ class InitListChecker {
RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
unsigned &StructuredIndex,
bool TopLevelObject = false);
void CheckArrayType(InitListExpr *IList, QualType &DeclType,
llvm::APSInt elementIndex,
bool SubobjectIsDesignatorContext, unsigned &Index,
@ -98,7 +102,8 @@ class InitListChecker {
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool FinishSubobjectInit = true);
bool FinishSubobjectInit,
bool TopLevelObject);
InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
QualType CurrentObjectType,
InitListExpr *StructuredList,
@ -220,7 +225,8 @@ InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) {
unsigned newStructuredIndex = 0;
FullyStructuredList
= getStructuredSubobjectInit(IL, newIndex, T, 0, 0, SourceRange());
CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex);
CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex,
/*TopLevelObject=*/true);
if (!hadError)
FillInValueInitializations(FullyStructuredList);
@ -253,7 +259,8 @@ int InitListChecker::numStructUnionElements(QualType DeclType) {
void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
QualType T, unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
unsigned &StructuredIndex,
bool TopLevelObject) {
int maxElements = 0;
if (T->isArrayType())
@ -284,7 +291,8 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
unsigned StartIndex = Index;
CheckListElementTypes(ParentIList, T, false, Index,
StructuredSubobjectInitList,
StructuredSubobjectInitIndex);
StructuredSubobjectInitIndex,
TopLevelObject);
unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
// Update the structured sub-object initialize so that it's ending
@ -299,12 +307,13 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
unsigned &StructuredIndex,
bool TopLevelObject) {
assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
SyntacticToSemantic[IList] = StructuredList;
StructuredList->setSyntacticForm(IList);
CheckListElementTypes(IList, T, true, Index, StructuredList,
StructuredIndex);
StructuredIndex, TopLevelObject);
IList->setType(T);
StructuredList->setType(T);
if (hadError)
@ -322,9 +331,16 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
} else if (!T->isIncompleteType()) {
// Don't complain for incomplete types, since we'll get an error
// elsewhere
QualType CurrentObjectType = StructuredList->getType();
int initKind =
CurrentObjectType->isArrayType()? 0 :
CurrentObjectType->isVectorType()? 1 :
CurrentObjectType->isScalarType()? 2 :
CurrentObjectType->isUnionType()? 3 :
4;
SemaRef->Diag(IList->getInit(Index)->getLocStart(),
diag::err_excess_initializers)
<< IList->getInit(Index)->getSourceRange();
<< initKind << IList->getInit(Index)->getSourceRange();
}
}
@ -338,7 +354,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
unsigned &StructuredIndex,
bool TopLevelObject) {
if (DeclType->isScalarType()) {
CheckScalarType(IList, DeclType, Index, StructuredList, StructuredIndex);
} else if (DeclType->isVectorType()) {
@ -348,7 +365,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
CheckStructUnionTypes(IList, DeclType, RD->field_begin(),
SubobjectIsDesignatorContext, Index,
StructuredList, StructuredIndex);
StructuredList, StructuredIndex,
TopLevelObject);
} else if (DeclType->isArrayType()) {
llvm::APSInt Zero(
SemaRef->Context.getTypeSize(SemaRef->Context.getSizeType()),
@ -643,7 +661,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
// updated to be the next array element we'll initialize.
if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(),
DeclType, 0, &elementIndex, Index,
StructuredList, StructuredIndex)) {
StructuredList, StructuredIndex, true,
false)) {
hadError = true;
continue;
}
@ -699,7 +718,8 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
bool SubobjectIsDesignatorContext,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
unsigned &StructuredIndex,
bool TopLevelObject) {
RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
// If the record is invalid, some of it's members are invalid. To avoid
@ -744,7 +764,8 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
// the next field that we'll be initializing.
if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(),
DeclType, &Field, 0, Index,
StructuredList, StructuredIndex))
StructuredList, StructuredIndex,
true, TopLevelObject))
hadError = true;
// Abort early for unions: the designator handled the
@ -782,9 +803,24 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
++Field;
}
// FIXME: Implement flexible array initialization GCC extension (it's a
// really messy extension to implement, unfortunately...the necessary
// information isn't actually even here!)
if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() ||
Index >= IList->getNumInits() ||
!isa<InitListExpr>(IList->getInit(Index)))
return;
// Handle GNU flexible array initializers.
if (!TopLevelObject &&
cast<InitListExpr>(IList->getInit(Index))->getNumInits() > 0) {
SemaRef->Diag(IList->getInit(Index)->getSourceRange().getBegin(),
diag::err_flexible_array_init_nonempty)
<< IList->getInit(Index)->getSourceRange().getBegin();
SemaRef->Diag(Field->getLocation(), diag::note_flexible_array_member)
<< *Field;
hadError = true;
}
CheckSubElementType(IList, Field->getType(), Index, StructuredList,
StructuredIndex);
}
/// @brief Check the well-formedness of a C99 designated initializer.
@ -831,7 +867,8 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex,
bool FinishSubobjectInit) {
bool FinishSubobjectInit,
bool TopLevelObject) {
if (D == DIE->designators_end()) {
// Check the actual initialization for the designated object type.
bool prevHadError = hadError;
@ -949,12 +986,74 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
if (FieldIndex >= StructuredList->getNumInits())
StructuredList->resizeInits(SemaRef->Context, FieldIndex + 1);
// Recurse to check later designated subobjects.
QualType FieldType = (*Field)->getType();
unsigned newStructuredIndex = FieldIndex;
if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index,
StructuredList, newStructuredIndex))
return true;
// This designator names a flexible array member.
if (Field->getType()->isIncompleteArrayType()) {
bool Invalid = false;
DesignatedInitExpr::designators_iterator NextD = D;
++NextD;
if (NextD != DIE->designators_end()) {
// We can't designate an object within the flexible array
// member (because GCC doesn't allow it).
SemaRef->Diag(NextD->getStartLocation(),
diag::err_designator_into_flexible_array_member)
<< SourceRange(NextD->getStartLocation(),
DIE->getSourceRange().getEnd());
SemaRef->Diag(Field->getLocation(), diag::note_flexible_array_member)
<< *Field;
Invalid = true;
}
if (!hadError && !isa<InitListExpr>(DIE->getInit())) {
// The initializer is not an initializer list.
SemaRef->Diag(DIE->getInit()->getSourceRange().getBegin(),
diag::err_flexible_array_init_needs_braces)
<< DIE->getInit()->getSourceRange();
SemaRef->Diag(Field->getLocation(), diag::note_flexible_array_member)
<< *Field;
Invalid = true;
}
// Handle GNU flexible array initializers.
if (!Invalid && !TopLevelObject &&
cast<InitListExpr>(DIE->getInit())->getNumInits() > 0) {
SemaRef->Diag(DIE->getSourceRange().getBegin(),
diag::err_flexible_array_init_nonempty)
<< DIE->getSourceRange().getBegin();
SemaRef->Diag(Field->getLocation(), diag::note_flexible_array_member)
<< *Field;
Invalid = true;
}
if (Invalid) {
++Index;
return true;
}
// Initialize the array.
bool prevHadError = hadError;
unsigned newStructuredIndex = FieldIndex;
unsigned OldIndex = Index;
IList->setInit(Index, DIE->getInit());
CheckSubElementType(IList, Field->getType(), Index,
StructuredList, newStructuredIndex);
IList->setInit(OldIndex, DIE);
if (hadError && !prevHadError) {
++Field;
++FieldIndex;
if (NextField)
*NextField = Field;
StructuredIndex = FieldIndex;
return true;
}
} else {
// Recurse to check later designated subobjects.
QualType FieldType = (*Field)->getType();
unsigned newStructuredIndex = FieldIndex;
if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index,
StructuredList, newStructuredIndex,
true, false))
return true;
}
// Find the position of the next field to be initialized in this
// subobject.
@ -1075,7 +1174,8 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
Index = OldIndex;
if (CheckDesignatedInitializer(IList, DIE, D, ElementType, 0, 0, Index,
StructuredList, ElementIndex,
(DesignatedStartIndex == DesignatedEndIndex)))
(DesignatedStartIndex == DesignatedEndIndex),
false))
return true;
// Move to the next index in the array that we'll be initializing.

View File

@ -20,7 +20,7 @@ void func() {
int x3[x] = { 1, 2 }; // expected-error{{variable-sized object may not be initialized}}
int x4 = { 1, 2 }; // expected-warning{{braces around scalar initializer}} expected-error{{excess elements in array initializer}}
int x4 = { 1, 2 }; // expected-warning{{braces around scalar initializer}} expected-error{{excess elements in scalar initializer}}
int y[4][3] = {
{ 1, 3, 5 },
@ -53,7 +53,7 @@ void func() {
void test() {
int y1[3] = {
{ 1, 2, 3 } // expected-warning{{braces around scalar initializer}} expected-error{{excess elements in array initializer}}
{ 1, 2, 3 } // expected-warning{{braces around scalar initializer}} expected-error{{excess elements in scalar initializer}}
};
int y3[4][3] = {
{ 1, 3, 5 },
@ -201,14 +201,13 @@ int bar (void) {
return z.z;
}
struct s3 {void (*a)(void);} t5 = {autoStructTest};
// FIXME: GCC extension; flexible array init. Once this is implemented, the warning should be removed.
// Note that clang objc implementation depends on this extension.
struct {int a; int b[];} t6 = {1, {1, 2, 3}}; //expected-error{{excess elements in array initializer}}
struct {int a; int b[];} t6 = {1, {1, 2, 3}};
union {char a; int b;} t7[] = {1, 2, 3};
int t8[sizeof t7 == (3*sizeof(int)) ? 1 : -1];
struct bittest{int : 31, a, :21, :12, b;};
struct bittest bittestvar = {1, 2, 3, 4}; //expected-error{{excess elements in array initializer}}
struct bittest bittestvar = {1, 2, 3, 4}; //expected-error{{excess elements in struct initializer}}
// Not completely sure what should happen here...
int u1 = {}; //expected-warning{{use of GNU empty initializer extension}} expected-error{{scalar initializer cannot be empty}}
@ -243,7 +242,7 @@ struct soft_segment_descriptor gdt_segs[] = {
};
static void sppp_ipv6cp_up();
const struct {} ipcp = { sppp_ipv6cp_up }; //expected-warning{{empty struct extension}} expected-error{{excess elements in array initializer}}
const struct {} ipcp = { sppp_ipv6cp_up }; //expected-warning{{empty struct extension}} expected-error{{excess elements in struct initializer}}
struct _Matrix { union { float m[4][4]; }; }; //expected-warning{{anonymous unions are a GNU extension in C}}
typedef struct _Matrix Matrix;

View File

@ -0,0 +1,38 @@
// RUN: clang -fsyntax-only -verify %s
struct one {
int a;
int values[];
} x = {5, {1, 2, 3}};
struct one x2 = { 5, 1, 2, 3 }; // expected-error{{excess elements in struct initializer}}
void test() {
struct one x3 = {5, {1, 2, 3}};
}
struct foo {
int x;
int y[]; // expected-note{{initialized flexible array member 'y' is here}}
};
struct bar { struct foo z; };
struct foo a = { 1, { 2, 3, 4 } }; // Valid.
struct bar b = { { 1, { 2, 3, 4 } } }; // expected-error{{non-empty initialization of flexible array member inside subobject}}
struct bar c = { { 1, { } } }; // Valid.
struct foo d[1] = { { 1, { 2, 3, 4 } } }; // expected-error{{'struct foo' may not be used as an array element due to flexible array member}}
struct foo desig_foo = { .y = {2, 3, 4} };
struct bar desig_bar = { .z.y = { } };
struct bar desig_bar2 = { .z.y = { 2, 3, 4} }; // expected-error{{non-empty initialization of flexible array member inside subobject}}
struct foo design_foo2 = { .y = 2 }; // expected-error{{flexible array requires brace-enclosed initializer}}
struct point {
int x, y;
};
struct polygon {
int numpoints;
struct point points[]; // expected-note{{initialized flexible array member 'points' is here}}
};
struct polygon poly = {
.points[2] = { 1, 2} }; // expected-error{{designator into flexible array member subobject}}

View File

@ -118,5 +118,5 @@ union u { int a; char* b; };
u u1 = { 1 };
u u2 = u1;
u u3 = 1; // expected-error{{cannot initialize 'u3' with an rvalue of type 'int'}}
u u4 = { 0, "asdf" }; // expected-error{{excess elements in array initializer}}
u u4 = { 0, "asdf" }; // expected-error{{excess elements in union initializer}}
u u5 = { "asdf" }; // expected-error{{incompatible type initializing 'char const [5]', expected 'int'}}