diff options
author | David Majnemer <david.majnemer@gmail.com> | 2014-08-11 07:29:54 +0000 |
---|---|---|
committer | David Majnemer <david.majnemer@gmail.com> | 2014-08-11 07:29:54 +0000 |
commit | 8f0ed914902f2d108ca2bd0b64b32c876bf24e5c (patch) | |
tree | ddd509dc55c077e6d546b74efd9aa59b59d38fa1 | |
parent | 69f3528c6abc83efd48977ba9c67150b93f15580 (diff) | |
download | bcm5719-llvm-8f0ed914902f2d108ca2bd0b64b32c876bf24e5c.tar.gz bcm5719-llvm-8f0ed914902f2d108ca2bd0b64b32c876bf24e5c.zip |
Sema: Handle declspecs without declarators in records properly in C mode
We had two bugs:
- We wouldn't properly warn when a struct/union/enum was mentioned
inside of a record definition if no declarator was provided. We
should have mentioned that this declaration declares nothing.
- We didn't properly support Microsoft's extension where certain
declspecs without declarators would act as anonymous structs/unions.
* We completely ignored the case where such a declspec could be a
union.
* We didn't properly handle the case where a record was defined inside
another record:
struct X {
int a;
struct Y {
int b;
};
};
llvm-svn: 215347
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 44 | ||||
-rw-r--r-- | clang/test/Parser/declarators.c | 1 | ||||
-rw-r--r-- | clang/test/Sema/MicrosoftExtensions.c | 15 | ||||
-rw-r--r-- | clang/test/Sema/anonymous-struct-union.c | 2 | ||||
-rw-r--r-- | clang/test/SemaObjC/ivar-lookup.m | 4 |
6 files changed, 50 insertions, 21 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 624555c8076..ca37b076fe5 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6149,8 +6149,9 @@ def err_anonymous_record_bad_member : Error< def err_anonymous_record_nonpublic_member : Error< "anonymous %select{struct|union}0 cannot contain a " "%select{private|protected}1 data member">; -def ext_ms_anonymous_struct : ExtWarn< - "anonymous structs are a Microsoft extension">, InGroup<Microsoft>; +def ext_ms_anonymous_record : ExtWarn< + "anonymous %select{structs|unions}0 are a Microsoft extension">, + InGroup<Microsoft>; // C++ local classes def err_reference_to_local_var_in_enclosing_function : Error< diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 85c88a3f576..53a647149a8 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3444,21 +3444,36 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } } - // Check for Microsoft C extension: anonymous struct member. - if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus && - CurContext->isRecord() && + // C11 6.7.2.1p2: + // A struct-declaration that does not declare an anonymous structure or + // anonymous union shall contain a struct-declarator-list. + if (!getLangOpts().CPlusPlus && CurContext->isRecord() && DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) { - // Handle 2 kinds of anonymous struct: + // Check for Microsoft C extension: anonymous struct/union member. + // Handle 2 kinds of anonymous struct/union: // struct STRUCT; + // union UNION; // and // STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct. - RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag); - if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) || - (DS.getTypeSpecType() == DeclSpec::TST_typename && - DS.getRepAsType().get()->isStructureType())) { - Diag(DS.getLocStart(), diag::ext_ms_anonymous_struct) - << DS.getSourceRange(); - return BuildMicrosoftCAnonymousStruct(S, DS, Record); + // UNION_TYPE; <- where UNION_TYPE is a typedef union. + if ((Tag && Tag->getDeclName()) || + DS.getTypeSpecType() == DeclSpec::TST_typename) { + RecordDecl *Record = nullptr; + if (Tag) + Record = dyn_cast<RecordDecl>(Tag); + else if (const RecordType *RT = + DS.getRepAsType().get()->getAsStructureType()) + Record = RT->getDecl(); + else if (const RecordType *UT = DS.getRepAsType().get()->getAsUnionType()) + Record = UT->getDecl(); + + if (Record && getLangOpts().MicrosoftExt) { + Diag(DS.getLocStart(), diag::ext_ms_anonymous_record) + << Record->isUnion() << DS.getSourceRange(); + return BuildMicrosoftCAnonymousStruct(S, DS, Record); + } + + DeclaresAnything = false; } } @@ -3999,15 +4014,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, /// /// void foo() { /// B var; -/// var.a = 3; +/// var.a = 3; /// } /// Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record) { - - // If there is no Record, get the record via the typedef. - if (!Record) - Record = DS.getRepAsType().get()->getAsStructureType()->getDecl(); + assert(Record && "expected a record!"); // Mock up a declarator. Declarator Dc(DS, Declarator::TypeNameContext); diff --git a/clang/test/Parser/declarators.c b/clang/test/Parser/declarators.c index c424d697353..e3024206e4f 100644 --- a/clang/test/Parser/declarators.c +++ b/clang/test/Parser/declarators.c @@ -113,6 +113,7 @@ enum E1 { e1 }: // expected-error {{expected ';'}} struct EnumBitfield { // expected-warning {{struct without named members is a GNU extension}} enum E2 { e2 } : 4; // ok struct S { int n; }: // expected-error {{expected ';'}} + // expected-warning@-1 {{declaration does not declare anything}} }; diff --git a/clang/test/Sema/MicrosoftExtensions.c b/clang/test/Sema/MicrosoftExtensions.c index 429dd943a74..f64012098b2 100644 --- a/clang/test/Sema/MicrosoftExtensions.c +++ b/clang/test/Sema/MicrosoftExtensions.c @@ -39,9 +39,24 @@ struct nested2 { NESTED1; // expected-warning {{anonymous structs are a Microsoft extension}} }; +struct nested3 { + long d; + struct nested4 { // expected-warning {{anonymous structs are a Microsoft extension}} + long e; + }; + union nested5 { // expected-warning {{anonymous unions are a Microsoft extension}} + long f; + }; +}; + +typedef union nested6 { + long f; +} NESTED6; + struct test { int c; struct nested2; // expected-warning {{anonymous structs are a Microsoft extension}} + NESTED6; // expected-warning {{anonymous unions are a Microsoft extension}} }; void foo() diff --git a/clang/test/Sema/anonymous-struct-union.c b/clang/test/Sema/anonymous-struct-union.c index 35d31754162..26dbeb87f5f 100644 --- a/clang/test/Sema/anonymous-struct-union.c +++ b/clang/test/Sema/anonymous-struct-union.c @@ -37,7 +37,7 @@ void test_unqual_references(struct X x, const struct X xc) { struct Redecl { int x; // expected-note{{previous declaration is here}} - struct y { }; + struct y { }; // expected-warning{{declaration does not declare anything}} union { int x; // expected-error{{member of anonymous union redeclares 'x'}} diff --git a/clang/test/SemaObjC/ivar-lookup.m b/clang/test/SemaObjC/ivar-lookup.m index 938c8eb189a..57f432c717a 100644 --- a/clang/test/SemaObjC/ivar-lookup.m +++ b/clang/test/SemaObjC/ivar-lookup.m @@ -99,9 +99,9 @@ extern struct foo x; }; struct S { __typeof(myStatus) __in; // fails. - struct S1 { + struct S1 { // expected-warning {{declaration does not declare anything}} __typeof(myStatus) __in; // fails. - struct S { + struct S { // expected-warning {{declaration does not declare anything}} __typeof(myStatus) __in; // fails. }; }; |