diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2011-08-23 22:24:57 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2011-08-23 22:24:57 +0000 |
commit | f40fd6bbb2684db5efb18627ea355613c235d23f (patch) | |
tree | 1a7183a1cc63808d72184f1de036f0ad56c2e406 | |
parent | 6886a92640f5bffc972f67c0a1f302d6c6e7c322 (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.td | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 21 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 69 | ||||
-rw-r--r-- | test/Sema/flexible-array-init.c | 35 |
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}} +} |