aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Friedman <eli.friedman@gmail.com>2011-08-23 22:24:57 +0000
committerEli Friedman <eli.friedman@gmail.com>2011-08-23 22:24:57 +0000
commitf40fd6bbb2684db5efb18627ea355613c235d23f (patch)
tree1a7183a1cc63808d72184f1de036f0ad56c2e406
parent6886a92640f5bffc972f67c0a1f302d6c6e7c322 (diff)
Refactor and fix checking for initialization of flexible array members. The old version had the checks scattered across the code, missed some checks, and had a couple nasty bugs in existing checks.
Fixes PR10648 and another similar accepts-invalid bug. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138398 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--lib/Sema/SemaDecl.cpp21
-rw-r--r--lib/Sema/SemaInit.cpp69
-rw-r--r--test/Sema/flexible-array-init.c35
4 files changed, 70 insertions, 59 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 0ded2fb3e4..3d8fbd37c1 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2716,8 +2716,8 @@ def ext_flexible_array_in_struct : Extension<
"%0 may not be nested in a struct due to flexible array member">;
def ext_flexible_array_in_array : Extension<
"%0 may not be used as an array element due to flexible array member">;
-def err_flexible_array_init_nonempty : Error<
- "non-empty initialization of flexible array member inside subobject">;
+def err_flexible_array_init : Error<
+ "initialization of flexible array member is not allowed">;
def ext_flexible_array_empty_aggregate_ms : Extension<
"flexible array member %0 in otherwise empty %select{struct|class}1 "
"is a Microsoft extension">, InGroup<Microsoft>;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 62032e8b65..9f43aa2f05 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -5740,27 +5740,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setType(DclT);
Init->setType(DclT);
}
-
-
- // If this variable is a local declaration with record type, make sure it
- // doesn't have a flexible member initialization. We only support this as a
- // global/static definition.
- if (VDecl->hasLocalStorage())
- if (const RecordType *RT = VDecl->getType()->getAs<RecordType>())
- if (RT->getDecl()->hasFlexibleArrayMember()) {
- // Check whether the initializer tries to initialize the flexible
- // array member itself to anything other than an empty initializer list.
- if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
- unsigned Index = std::distance(RT->getDecl()->field_begin(),
- RT->getDecl()->field_end()) - 1;
- if (Index < ILE->getNumInits() &&
- !(isa<InitListExpr>(ILE->getInit(Index)) &&
- cast<InitListExpr>(ILE->getInit(Index))->getNumInits() == 0)) {
- Diag(VDecl->getLocation(), diag::err_nonstatic_flexible_variable);
- VDecl->setInvalidDecl();
- }
- }
- }
// Check any implicit conversions within the expression.
CheckImplicitConversions(Init, VDecl->getLocation());
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index a61b1d11fc..2d47cda0e0 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -249,6 +249,9 @@ class InitListChecker {
InitListExpr *ILE, bool &RequiresSecondPass);
void FillInValueInitializations(const InitializedEntity &Entity,
InitListExpr *ILE, bool &RequiresSecondPass);
+ bool CheckFlexibleArrayInit(const InitializedEntity &Entity,
+ Expr *InitExpr, FieldDecl *Field,
+ bool TopLevelObject);
public:
InitListChecker(Sema &S, const InitializedEntity &Entity,
InitListExpr *IL, QualType &T);
@@ -1113,6 +1116,43 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
}
}
+bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity,
+ Expr *InitExpr,
+ FieldDecl *Field,
+ bool TopLevelObject) {
+ // Handle GNU flexible array initializers.
+ unsigned FlexArrayDiag;
+ if (isa<InitListExpr>(InitExpr) &&
+ cast<InitListExpr>(InitExpr)->getNumInits() == 0) {
+ // Empty flexible array init always allowed as an extension
+ FlexArrayDiag = diag::ext_flexible_array_init;
+ } else if (SemaRef.getLangOptions().CPlusPlus) {
+ // Disallow flexible array init in C++; it is not required for gcc
+ // compatibility, and it needs work to IRGen correctly in general.
+ FlexArrayDiag = diag::err_flexible_array_init;
+ } else if (!TopLevelObject) {
+ // Disallow flexible array init on non-top-level object
+ FlexArrayDiag = diag::err_flexible_array_init;
+ } else if (Entity.getKind() != InitializedEntity::EK_Variable) {
+ // Disallow flexible array init on anything which is not a variable.
+ FlexArrayDiag = diag::err_flexible_array_init;
+ } else if (cast<VarDecl>(Entity.getDecl())->hasLocalStorage()) {
+ // Disallow flexible array init on local variables.
+ FlexArrayDiag = diag::err_flexible_array_init;
+ } else {
+ // Allow other cases.
+ FlexArrayDiag = diag::ext_flexible_array_init;
+ }
+
+ SemaRef.Diag(InitExpr->getSourceRange().getBegin(),
+ FlexArrayDiag)
+ << InitExpr->getSourceRange().getBegin();
+ SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
+ << Field;
+
+ return FlexArrayDiag != diag::ext_flexible_array_init;
+}
+
void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
InitListExpr *IList,
QualType DeclType,
@@ -1239,24 +1279,11 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
Index >= IList->getNumInits())
return;
- // Handle GNU flexible array initializers.
- if (!TopLevelObject &&
- (!isa<InitListExpr>(IList->getInit(Index)) ||
- 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;
+ if (CheckFlexibleArrayInit(Entity, IList->getInit(Index), *Field,
+ TopLevelObject)) {
hadError = true;
++Index;
return;
- } else {
- SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(),
- diag::ext_flexible_array_init)
- << IList->getInit(Index)->getSourceRange().getBegin();
- SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
- << *Field;
}
InitializedEntity MemberEntity =
@@ -1567,16 +1594,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
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;
+ // Check GNU flexible array initializer.
+ if (!Invalid && CheckFlexibleArrayInit(Entity, DIE->getInit(), *Field,
+ TopLevelObject))
Invalid = true;
- }
if (Invalid) {
++Index;
diff --git a/test/Sema/flexible-array-init.c b/test/Sema/flexible-array-init.c
index 12f5d4f5d6..78fc7c5e0d 100644
--- a/test/Sema/flexible-array-init.c
+++ b/test/Sema/flexible-array-init.c
@@ -7,9 +7,7 @@ struct one {
struct one x2 = { 5, 1, 2, 3 }; // expected-warning{{flexible array initialization is a GNU extension}}
void test() {
- struct one x3 = {5, {1, 2, 3}}; // \
- // expected-warning{{flexible array initialization is a GNU extension}} \
- // expected-error {{non-static initialization of a variable with flexible array member}}
+ struct one x3 = {5, {1, 2, 3}}; // expected-error{{initialization of flexible array member is not allowed}}
struct one x3a = { 5 };
struct one x3b = { .a = 5 };
struct one x3c = { 5, {} }; // expected-warning{{use of GNU empty initializer extension}} \
@@ -19,22 +17,23 @@ void test() {
struct foo {
int x;
- int y[]; // expected-note 6 {{initialized flexible array member 'y' is here}}
+ int y[]; // expected-note 8 {{initialized flexible array member 'y' is here}}
};
struct bar { struct foo z; }; // expected-warning {{'z' may not be nested in a struct due to flexible array member}}
struct foo a = { 1, { 2, 3, 4 } }; // expected-warning{{flexible array initialization is a GNU extension}}
-struct bar b = { { 1, { 2, 3, 4 } } }; // expected-error{{non-empty initialization of flexible array member inside subobject}}
+struct bar b = { { 1, { 2, 3, 4 } } }; // expected-error{{initialization of flexible array member is not allowed}}
struct bar c = { { 1, { } } }; // // expected-warning{{flexible array initialization is a GNU extension}} \
// expected-warning{{use of GNU empty initializer extension}} \
// expected-warning{{zero size arrays are an extension}}
struct foo d[1] = { { 1, { 2, 3, 4 } } }; // expected-warning{{'struct foo' may not be used as an array element due to flexible array member}} \
- // expected-error{{non-empty initialization of flexible array member inside subobject}}
+ // expected-error{{initialization of flexible array member is not allowed}}
-struct foo desig_foo = { .y = {2, 3, 4} };
+struct foo desig_foo = { .y = {2, 3, 4} }; // expected-warning{{flexible array initialization is a GNU extension}}
struct bar desig_bar = { .z.y = { } }; // expected-warning{{use of GNU empty initializer extension}} \
- // expected-warning{{zero size arrays are an extension}}
-struct bar desig_bar2 = { .z.y = { 2, 3, 4} }; // expected-error{{non-empty initialization of flexible array member inside subobject}}
+ // expected-warning{{zero size arrays are an extension}} \
+ // expected-warning{{flexible array initialization is a GNU extension}}
+struct bar desig_bar2 = { .z.y = { 2, 3, 4} }; // expected-error{{initialization of flexible array member is not allowed}}
struct foo design_foo2 = { .y = 2 }; // expected-error{{flexible array requires brace-enclosed initializer}}
struct point {
@@ -68,13 +67,25 @@ struct Y {
// PR8217
struct PR8217a {
int i;
- char v[];
+ char v[]; // expected-note 2 {{initialized flexible array member 'v' is here}}
};
void PR8217() {
- struct PR8217a foo1 = { .i = 0, .v = "foo" }; // expected-error {{non-static initialization of a variable with flexible array member}}
+ struct PR8217a foo1 = { .i = 0, .v = "foo" }; // expected-error {{initialization of flexible array member is not allowed}}
struct PR8217a foo2 = { .i = 0 };
- struct PR8217a foo3 = { .i = 0, .v = { 'b', 'a', 'r', '\0' } }; // expected-error {{non-static initialization of a variable with flexible array member}}
+ struct PR8217a foo3 = { .i = 0, .v = { 'b', 'a', 'r', '\0' } }; // expected-error {{initialization of flexible array member is not allowed}}
struct PR8217a bar;
}
+typedef struct PR10648 {
+ unsigned long n;
+ int v[]; // expected-note {{initialized flexible array member 'v' is here}}
+} PR10648;
+int f10648() {
+ return (PR10648){2, {3, 4}}.v[1]; // expected-error {{initialization of flexible array member is not allowed}}
+}
+
+struct FlexWithUnnamedBitfield { int : 10; int x; int y[]; }; // expected-note {{initialized flexible array member 'y' is here}}
+void TestFlexWithUnnamedBitfield() {
+ struct FlexWithUnnamedBitfield x = {10, {3}}; // expected-error {{initialization of flexible array member is not allowed}}
+}