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:
parent
82f071faa7
commit
fc4f8a1834
|
@ -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,
|
||||
|
|
|
@ -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 &&
|
||||
"Invalid modifier for NamedDecl* argument");
|
||||
|
||||
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)->getNameAsString();
|
||||
}
|
||||
}
|
||||
Output.append(S.begin(), S.end());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
// 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))
|
||||
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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}}
|
|
@ -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'}}
|
||||
|
|
Loading…
Reference in New Issue