From: Serge Pavlov Date: Sat, 8 Jun 2013 13:29:58 +0000 (+0000) Subject: Recognition of empty structures and unions is moved to semantic stage X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=122e601886ae527d6e7100c589339c05190a168a;p=clang Recognition of empty structures and unions is moved to semantic stage Differential Revision: http://llvm-reviews.chandlerc.com/D586 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183609 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 74b94d3413..44d3acfc17 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -57,10 +57,6 @@ def ext_integer_complex : Extension< "complex integer types are a GNU extension">, InGroup; def ext_thread_before : Extension<"'__thread' before '%0'">; -def ext_empty_struct_union : Extension< - "empty %select{struct|union}0 is a GNU extension">, InGroup; -def warn_empty_struct_union_compat : Warning<"empty %select{struct|union}0 " - "has size 0 in C, size 1 in C++">, InGroup, DefaultIgnore; def error_empty_enum : Error<"use of empty enum">; def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">; def err_invalid_short_spec : Error<"'short %0' is invalid">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 40ef1ac75a..f79233e52e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5464,6 +5464,15 @@ def err_expected_ident_or_lparen : Error<"expected identifier or '('">; def err_typecheck_cond_incompatible_operands_null : Error< "non-pointer operand type %0 incompatible with %select{NULL|nullptr}1">; +def ext_empty_struct_union : Extension< + "empty %select{struct|union}0 is a GNU extension">, InGroup; +def ext_no_named_members_in_struct_union : Extension< + "%select{struct|union}0 without named members is a GNU extension">, InGroup; +def warn_empty_struct_union_compat : Warning<"empty %select{struct|union}0 " + "has size 0 in C, size 1 in C++">, InGroup, DefaultIgnore; +def warn_zero_size_struct_union_compat : Warning<"%select{struct|union}0 " + "with only bit-fields of width 0 has size 0 in C, size 1 in C++">, + InGroup, DefaultIgnore; } // End of general sema category. // inline asm. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 03e4879db6..b3e8412dcf 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3216,12 +3216,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); - // Empty structs are an extension in C (C99 6.7.2.1p7). - if (Tok.is(tok::r_brace)) { - Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union); - Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union); - } - SmallVector FieldDecls; // While we still have something to read, read the declarations in the struct. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 7be376e60f..e6a89461b4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -11235,6 +11235,41 @@ void Sema::ActOnFields(Scope* S, if (Record->hasAttrs()) CheckAlignasUnderalignment(Record); + + // Check if the structure/union declaration is a language extension. + if (!getLangOpts().CPlusPlus) { + bool ZeroSize = true; + bool UnnamedOnly = true; + unsigned UnnamedCnt = 0; + for (RecordDecl::field_iterator I = Record->field_begin(), + E = Record->field_end(); UnnamedOnly && I != E; ++I) { + if (I->isUnnamedBitfield()) { + UnnamedCnt++; + if (I->getBitWidthValue(Context) > 0) + ZeroSize = false; + } else { + UnnamedOnly = ZeroSize = false; + } + } + + // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in + // C++. + if (ZeroSize) { + if (UnnamedCnt == 0) + Diag(RecLoc, diag::warn_empty_struct_union_compat) << Record->isUnion(); + else + Diag(RecLoc, diag::warn_zero_size_struct_union_compat) << Record->isUnion(); + } + + // Structs without named members are extension in C (C99 6.7.2.1p7), but + // are accepted by GCC. + if (UnnamedOnly) { + if (UnnamedCnt == 0) + Diag(RecLoc, diag::ext_empty_struct_union) << Record->isUnion(); + else + Diag(RecLoc, diag::ext_no_named_members_in_struct_union) << Record->isUnion(); + } + } } else { ObjCIvarDecl **ClsFields = reinterpret_cast(RecFields.data()); diff --git a/test/Parser/declarators.c b/test/Parser/declarators.c index f63b59f7ca..210a8e2bef 100644 --- a/test/Parser/declarators.c +++ b/test/Parser/declarators.c @@ -108,7 +108,8 @@ void test18() { } enum E1 { e1 }: // expected-error {{expected ';'}} -struct EnumBitfield { +struct EnumBitfield { // expected-warning {{struct without named members is a GNU extension}} enum E2 { e2 } : 4; // ok struct S { int n; }: // expected-error {{expected ';'}} + }; diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c index f92852f341..ae2c742566 100644 --- a/test/Sema/array-init.c +++ b/test/Sema/array-init.c @@ -226,7 +226,8 @@ void emptyInit() {struct {} x[] = {6};} //expected-warning{{empty struct is a GN // expected-error{{initializer for aggregate with no elements}} void noNamedInit() { - struct {int:5;} x[] = {6}; //expected-error{{initializer for aggregate with no elements}} + struct {int:5;} x[] = {6}; //expected-error{{initializer for aggregate with no elements}} \ +// expected-warning {{struct without named members is a GNU extension}} } struct {int a; int:5;} noNamedImplicit[] = {1,2,3}; int noNamedImplicitCheck[sizeof(noNamedImplicit) == 3 * sizeof(*noNamedImplicit) ? 1 : -1]; diff --git a/test/Sema/empty1.c b/test/Sema/empty1.c new file mode 100644 index 0000000000..cd4aca8e47 --- /dev/null +++ b/test/Sema/empty1.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify -Wc++-compat + +struct emp_1 { // expected-warning {{empty struct has size 0 in C, size 1 in C++}} +}; + +union emp_2 { // expected-warning {{empty union has size 0 in C, size 1 in C++}} +}; + +struct emp_3 { // expected-warning {{struct with only bit-fields of width 0 has size 0 in C, size 1 in C++}} + int : 0; +}; + +union emp_4 { // expected-warning {{union with only bit-fields of width 0 has size 0 in C, size 1 in C++}} + int : 0; +}; + +struct emp_5 { // expected-warning {{struct with only bit-fields of width 0 has size 0 in C, size 1 in C++}} + int : 0; + int : 0; +}; + +union emp_6 { // expected-warning {{union with only bit-fields of width 0 has size 0 in C, size 1 in C++}} + int : 0; + int : 0; +}; diff --git a/test/Sema/empty2.c b/test/Sema/empty2.c new file mode 100644 index 0000000000..68da5a8ee8 --- /dev/null +++ b/test/Sema/empty2.c @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic + +struct emp_1 { // expected-warning {{empty struct is a GNU extension}} +}; + +union emp_2 { // expected-warning {{empty union is a GNU extension}} +}; + +struct emp_3 { // expected-warning {{struct without named members is a GNU extension}} + int : 0; +}; + +union emp_4 { // expected-warning {{union without named members is a GNU extension}} + int : 0; +}; + +struct emp_5 { // expected-warning {{struct without named members is a GNU extension}} + int : 0; + int : 0; +}; + +union emp_6 { // expected-warning {{union without named members is a GNU extension}} + int : 0; + int : 0; +}; + +struct nonamed_1 { // expected-warning {{struct without named members is a GNU extension}} + int : 4; +}; + +union nonamed_2 { // expected-warning {{union without named members is a GNU extension}} + int : 4; +}; + +struct nonamed_3 { // expected-warning {{struct without named members is a GNU extension}} + int : 4; + unsigned int : 4; +}; + +union nonamed_4 { // expected-warning {{union without named members is a GNU extension}} + int : 4; + unsigned int : 4; +};