diff options
-rw-r--r-- | Driver/clang.cpp | 3 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 6 | ||||
-rw-r--r-- | lib/Parse/DeclSpec.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 51 | ||||
-rw-r--r-- | test/Parser/cxx-class.cpp | 2 | ||||
-rw-r--r-- | test/Sema/anonymous-struct-union.c | 82 | ||||
-rw-r--r-- | test/SemaCXX/anonymous-union.cpp | 3 | ||||
-rw-r--r-- | test/SemaObjC/property-9.m | 4 |
9 files changed, 126 insertions, 32 deletions
diff --git a/Driver/clang.cpp b/Driver/clang.cpp index 6b3507e3a6..51b1335f9c 100644 --- a/Driver/clang.cpp +++ b/Driver/clang.cpp @@ -714,9 +714,6 @@ static void InitializeDiagnostics(Diagnostic &Diags) { Diags.setDiagnosticMapping(diag::warn_implicit_function_decl, diag::MAP_IGNORE); - if (MSExtensions) // MS allows unnamed struct/union fields. - Diags.setDiagnosticMapping(diag::w_no_declarators, diag::MAP_IGNORE); - // If -pedantic-errors is set, turn extensions that warn by default into // errors. if (ErrorOnExtensions) { diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index bac6f242e0..ee0cad4d13 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -270,8 +270,6 @@ DIAG(err_pp_I_dash_not_supported, ERROR, // Parser Diagnostics //===----------------------------------------------------------------------===// -DIAG(w_no_declarators, WARNING, - "declaration does not declare anything") DIAG(w_asm_qualifier_ignored, WARNING, "ignored %0 qualifier on asm") @@ -1496,7 +1494,9 @@ DIAG(err_anonymous_union_not_static, ERROR, DIAG(err_anonymous_union_with_storage_spec, ERROR, "anonymous union at class scope must not have a storage specifier") DIAG(err_anonymous_struct_not_member, ERROR, - "anonymous structs and classes must be class members") + "anonymous %select{structs|structs and classes}0 must be %select{struct or union|class}0 members") +DIAG(err_anonymous_union_not_member, ERROR, + "anonymous unions must be struct or union members") DIAG(err_anonymous_union_member_redecl, ERROR, "member of anonymous union redeclares %0") DIAG(err_anonymous_struct_member_redecl, ERROR, diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 258dc87c44..4459c804f3 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -319,5 +319,5 @@ bool DeclSpec::isMissingDeclaratorOk() { || tst == TST_struct || tst == TST_class || tst == TST_enum - ) && getTypeRep() != 0; + ) && getTypeRep() != 0 && StorageClassSpec != DeclSpec::SCS_typedef; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 3ec1764612..8d4705a7bf 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -888,9 +888,10 @@ ParseStructDeclaration(DeclSpec &DS, SourceLocation DSStart = Tok.getLocation(); ParseSpecifierQualifierList(DS); - // If there are no declarators, issue a warning. + // If there are no declarators, this is a free-standing declaration + // specifier. Let the actions module cope with it. if (Tok.is(tok::semi)) { - Diag(DSStart, diag::w_no_declarators); + Actions.ParsedFreeStandingDeclSpec(CurScope, DS); return; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f3f0a08bee..6aeda8bc0b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -861,7 +861,20 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { - // FIXME: Isn't that more of a parser diagnostic than a sema diagnostic? + TagDecl *Tag + = dyn_cast_or_null<TagDecl>(static_cast<Decl *>(DS.getTypeRep())); + if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { + if (!Record->getDeclName() && Record->isDefinition() && + DS.getStorageClassSpec() != DeclSpec::SCS_typedef) + return BuildAnonymousStructOrUnion(S, DS, Record); + + // Microsoft allows unnamed struct/union fields. Don't complain + // about them. + // FIXME: Should we support Microsoft's extensions in this area? + if (Record->getDeclName() && getLangOptions().Microsoft) + return Tag; + } + if (!DS.isMissingDeclaratorOk()) { // FIXME: This diagnostic is emitted even when various previous // errors occurred (see e.g. test/Sema/decl-invalid.c). However, @@ -872,14 +885,6 @@ Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { return 0; } - TagDecl *Tag - = dyn_cast_or_null<TagDecl>(static_cast<Decl *>(DS.getTypeRep())); - if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { - if (!Record->getDeclName() && Record->isDefinition() && - !Record->isInvalidDecl()) - return BuildAnonymousStructOrUnion(S, DS, Record); - } - return Tag; } @@ -1031,10 +1036,16 @@ Sema::DeclTy *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, } } else { // FIXME: Check GNU C semantics + if (Record->isUnion() && !Owner->isRecord()) { + Diag(Record->getLocation(), diag::err_anonymous_union_not_member) + << (int)getLangOptions().CPlusPlus; + Invalid = true; + } } if (!Record->isUnion() && !Owner->isRecord()) { - Diag(Record->getLocation(), diag::err_anonymous_struct_not_member); + Diag(Record->getLocation(), diag::err_anonymous_struct_not_member) + << (int)getLangOptions().CPlusPlus; Invalid = true; } @@ -1084,7 +1095,8 @@ Sema::DeclTy *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. - Invalid = Invalid || InjectAnonymousStructOrUnionMembers(S, Owner, Record); + if (InjectAnonymousStructOrUnionMembers(S, Owner, Record)) + Invalid = true; // Mark this as an anonymous struct/union type. Note that we do not // do this until after we have already checked and injected the @@ -2890,6 +2902,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, case DeclSpec::TST_enum: Kind = TagDecl::TK_enum; break; } + DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; DeclContext *LexicalContext = CurContext; ScopedDecl *PrevDecl = 0; @@ -2924,8 +2937,8 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, // with C structs, unions, and enums when looking for a matching // tag declaration or definition. See the similar lookup tweak // in Sema::LookupDecl; is there a better way to deal with this? - while (isa<RecordDecl>(DC) || isa<EnumDecl>(DC)) - DC = DC->getParent(); + while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC)) + SearchDC = SearchDC->getParent(); } } @@ -2943,7 +2956,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or // rementions the tag), reuse the decl. - if (TK == TK_Reference || isDeclInScope(PrevDecl, DC, S)) { + if (TK == TK_Reference || isDeclInScope(PrevDecl, SearchDC, S)) { // Make sure that this wasn't declared as an enum and now used as a // struct or something similar. if (PrevTagDecl->getTagKind() != Kind) { @@ -2991,7 +3004,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, // PrevDecl. If it's NULL, we have a new definition. } else { // PrevDecl is a namespace. - if (isDeclInScope(PrevDecl, DC, S)) { + if (isDeclInScope(PrevDecl, SearchDC, S)) { // The tag name clashes with a namespace name, issue an error and // recover by making this tag be anonymous. Diag(NameLoc, diag::err_redefinition_different_kind) << Name; @@ -3024,6 +3037,8 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, // C structs and unions. // Find the context where we'll be declaring the tag. + // FIXME: We would like to maintain the current DeclContext as the + // lexical context, while (DC->isRecord()) DC = DC->getParent(); LexicalContext = DC; @@ -3110,11 +3125,7 @@ CreateNewDecl: CurContext = OldContext; } else PushOnScopeChains(New, S); - } else if (getLangOptions().CPlusPlus) { - // FIXME: We also want to do this for C, but if this tag is - // defined within a structure CurContext will point to the context - // enclosing the structure, and we would end up inserting the tag - // type into the wrong place. + } else { LexicalContext->addDecl(Context, New); } diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp index 39b787fc8d..7ad63446ab 100644 --- a/test/Parser/cxx-class.cpp +++ b/test/Parser/cxx-class.cpp @@ -8,7 +8,7 @@ protected: struct S {}; enum {}; - int; // expected-error {{error: declaration does not declare anything}} + int; // expected-error {{declaration does not declare anything}} int : 1, : 2; public: diff --git a/test/Sema/anonymous-struct-union.c b/test/Sema/anonymous-struct-union.c new file mode 100644 index 0000000000..72790c9abb --- /dev/null +++ b/test/Sema/anonymous-struct-union.c @@ -0,0 +1,82 @@ +// RUN: clang -fsyntax-only -verify %s +struct X { + union { + float f3; + double d2; + } named; + + union { + int i; + float f; + + union { + float f2; + double d; + }; + }; + + struct { + int a; + float b; + }; +}; + +void test_unqual_references(struct X x, const struct X xc) { + x.i = 0; + x.f = 0.0; + x.f2 = x.f; + x.d = x.f; + x.f3 = 0; // expected-error{{no member named 'f3'}} + x.a = 0; + + xc.d = 0.0; // expected-error{{read-only variable is not assignable}} + xc.f = 0; // expected-error{{read-only variable is not assignable}} + xc.a = 0; // expected-error{{read-only variable is not assignable}} +} + + +struct Redecl { + int x; // expected-note{{previous declaration is here}} + struct y { }; + + union { + int x; // expected-error{{member of anonymous union redeclares 'x'}} + float y; + double z; // expected-note{{previous declaration is here}} + double zz; // expected-note{{previous declaration is here}} + }; + + int z; // expected-error{{duplicate member 'z'}} + void zz(); // expected-error{{duplicate member 'zz'}} \ + // expected-error{{field 'zz' declared as a function}} +}; + +union { // expected-error{{anonymous unions must be struct or union members}} + int int_val; + float float_val; +}; + +static union { // expected-error{{anonymous unions must be struct or union members}} + int int_val2; + float float_val2; +}; + +void f() { + int_val2 = 0; // expected-error{{use of undeclared identifier}} + float_val2 = 0.0; // expected-error{{use of undeclared identifier}} +} + +void g() { + union { // expected-error{{anonymous unions must be struct or union members}} + int i; + float f2; + }; + i = 0; // expected-error{{use of undeclared identifier}} + f2 = 0.0; // expected-error{{use of undeclared identifier}} +} + +// <rdar://problem/6483159> +struct s0 { union { int f0; }; }; + +// <rdar://problem/6481130> +typedef struct { }; // expected-error{{declaration does not declare anything}} diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp index 872c45c468..5860ed4af7 100644 --- a/test/SemaCXX/anonymous-union.cpp +++ b/test/SemaCXX/anonymous-union.cpp @@ -108,3 +108,6 @@ struct BadMembers { protected: float x2; // expected-error{{anonymous union cannot contain a protected data member}} }; }; + +// <rdar://problem/6481130> +typedef union { }; // expected-error{{declaration does not declare anything}} diff --git a/test/SemaObjC/property-9.m b/test/SemaObjC/property-9.m index 9275b51d25..9aafcc9ef6 100644 --- a/test/SemaObjC/property-9.m +++ b/test/SemaObjC/property-9.m @@ -43,9 +43,9 @@ typedef signed char BOOL; int _awesome; } -@property (readonly) int; // expected-warning {{declaration does not declare anything}} +@property (readonly) int; // expected-error {{declaration does not declare anything}} @property (readonly) ; // expected-error {{type name requires a specifier or qualifier}} \ - expected-warning {{declaration does not declare anything}} + expected-error {{declaration does not declare anything}} @property (readonly) int : 4; // expected-error {{property requires fields to be named}} |