From: John McCall Date: Tue, 22 Mar 2011 23:00:04 +0000 (+0000) Subject: Warn about unused declaration-specifiers on tag declarations. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ac4df2454d5462c3bf5f369d65c3ad651100fa40;p=clang Warn about unused declaration-specifiers on tag declarations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128118 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index ef0c0d46ee..41feb7e019 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2535,6 +2535,7 @@ def err_typecheck_sclass_fscope : Error< "illegal storage class on file-scoped variable">; def err_unsupported_global_register : Error< "global register variables are not supported">; +def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">; def err_typecheck_sclass_func : Error<"illegal storage class on function">; def err_static_block_func : Error< "function declared in block scope cannot have 'static' storage class">; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e4058d2c6e..544d1ae1e7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1764,12 +1764,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, - DeclSpec &DS) { - // FIXME: Error on inline/virtual/explicit - // FIXME: Warn on useless __thread - // FIXME: Warn on useless const/volatile - // FIXME: Warn on useless static/extern/typedef/private_extern/mutable - // FIXME: Warn on useless attributes + DeclSpec &DS) { Decl *TagD = 0; TagDecl *Tag = 0; if (DS.getTypeSpecType() == DeclSpec::TST_class || @@ -1803,6 +1798,10 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, return 0; return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0)); } + + // Track whether we warned about the fact that there aren't any + // declarators. + bool emittedWarning = false; if (RecordDecl *Record = dyn_cast_or_null(Tag)) { ProcessDeclAttributeList(S, Record, DS.getAttributes().getList()); @@ -1815,6 +1814,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); + emittedWarning = true; } } @@ -1840,12 +1840,16 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DS.getStorageClassSpec() != DeclSpec::SCS_typedef) if (EnumDecl *Enum = dyn_cast_or_null(Tag)) if (Enum->enumerator_begin() == Enum->enumerator_end() && - !Enum->getIdentifier() && !Enum->isInvalidDecl()) + !Enum->getIdentifier() && !Enum->isInvalidDecl()) { Diag(Enum->getLocation(), diag::ext_no_declarators) << DS.getSourceRange(); + emittedWarning = true; + } + + // Skip all the checks below if we have a type error. + if (DS.getTypeSpecType() == DeclSpec::TST_error) return TagD; - if (!DS.isMissingDeclaratorOk() && - DS.getTypeSpecType() != DeclSpec::TST_error) { + if (!DS.isMissingDeclaratorOk()) { // Warn about typedefs of enums without names, since this is an // extension in both Microsoft and GNU. if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef && @@ -1857,7 +1861,35 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); - } + emittedWarning = true; + } + + // We're going to complain about a bunch of spurious specifiers; + // only do this if we're declaring a tag, because otherwise we + // should be getting diag::ext_no_declarators. + if (emittedWarning || (TagD && TagD->isInvalidDecl())) + return TagD; + + if (DeclSpec::SCS scs = DS.getStorageClassSpec()) + Diag(DS.getStorageClassSpecLoc(), diag::warn_standalone_specifier) + << DeclSpec::getSpecifierName(scs); + if (DS.isThreadSpecified()) + Diag(DS.getThreadSpecLoc(), diag::warn_standalone_specifier) << "__thread"; + if (DS.getTypeQualifiers()) { + if (DS.getTypeQualifiers() & DeclSpec::TQ_const) + Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "const"; + if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) + Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "volatile"; + // Restrict is covered above. + } + if (DS.isInlineSpecified()) + Diag(DS.getInlineSpecLoc(), diag::warn_standalone_specifier) << "inline"; + if (DS.isVirtualSpecified()) + Diag(DS.getVirtualSpecLoc(), diag::warn_standalone_specifier) << "virtual"; + if (DS.isExplicitSpecified()) + Diag(DS.getExplicitSpecLoc(), diag::warn_standalone_specifier) <<"explicit"; + + // FIXME: Warn on useless attributes return TagD; } diff --git a/test/Sema/struct-decl.c b/test/Sema/struct-decl.c index 3639d2479b..e1c7073e01 100644 --- a/test/Sema/struct-decl.c +++ b/test/Sema/struct-decl.c @@ -46,3 +46,14 @@ struct s0 f0(void) {} struct x0 { unsigned int x1; }; + +// rdar://problem/9150338 +static struct test1 { // expected-warning {{'static' ignored on this declaration}} + int x; +}; +const struct test2 { // expected-warning {{'const' ignored on this declaration}} + int x; +}; +inline struct test3 { // expected-warning {{'inline' ignored on this declaration}} + int x; +};