diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index cc42720a7b91..6de5627f3dea 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1698,9 +1698,30 @@ bool Sema::mergeDeclAttribute(Decl *D, InheritableAttr *Attr) { return false; } +static const Decl *getDefinition(Decl *D) { + if (TagDecl *TD = dyn_cast(D)) + return TD->getDefinition(); + if (VarDecl *VD = dyn_cast(D)) + return VD->getDefinition(); + if (FunctionDecl *FD = dyn_cast(D)) { + const FunctionDecl* Def; + if (FD->hasBody(Def)) + return Def; + } + return NULL; +} + /// mergeDeclAttributes - Copy attributes from the Old decl to the New one. void Sema::mergeDeclAttributes(Decl *New, Decl *Old, bool MergeDeprecation) { + // attributes declared post-definition are currently ignored + const Decl *Def = getDefinition(Old); + if (Def && Def != New && New->hasAttrs()) { + Diag(New->getLocation(), diag::warn_attribute_precede_definition); + Diag(Def->getLocation(), diag::note_previous_definition); + New->dropAttrs(); + } + if (!Old->hasAttrs()) return; @@ -4251,18 +4272,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, CheckMemberSpecialization(NewVD, Previous)) NewVD->setInvalidDecl(); } - - // attributes declared post-definition are currently ignored - // FIXME: This should be handled in attribute merging, not - // here. - if (Previous.isSingleResult()) { - VarDecl *Def = dyn_cast(Previous.getFoundDecl()); - if (Def && (Def = Def->getDefinition()) && - Def != NewVD && D.hasAttributes()) { - Diag(NewVD->getLocation(), diag::warn_attribute_precede_definition); - Diag(Def->getLocation(), diag::note_previous_definition); - } - } // If this is a locally-scoped extern C variable, update the map of // such variables. @@ -5665,17 +5674,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - // attributes declared post-definition are currently ignored - // FIXME: This should happen during attribute merging - if (D.isRedeclaration() && Previous.isSingleResult()) { - const FunctionDecl *Def; - FunctionDecl *PrevFD = dyn_cast(Previous.getFoundDecl()); - if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) { - Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition); - Diag(Def->getLocation(), diag::note_previous_definition); - } - } - AddKnownFunctionAttributes(NewFD); if (NewFD->hasAttr() && diff --git a/clang/test/Sema/attr-decl-after-definition.c b/clang/test/Sema/attr-decl-after-definition.c index 4d32e0028b54..ba6df5906855 100644 --- a/clang/test/Sema/attr-decl-after-definition.c +++ b/clang/test/Sema/attr-decl-after-definition.c @@ -17,3 +17,6 @@ int bar = 0; // expected-note {{previous definition is here}} int bar __attribute__((weak)); // expected-warning {{must precede definition}} int bar; +struct zed { // expected-note {{previous definition is here}} +}; +struct __attribute__((visibility("hidden"))) zed; // expected-warning {{must precede definition}}