Centralize the handling of the "attribute declaration must precede definition"
authorRafael Espindola <rafael.espindola@gmail.com>
Fri, 18 May 2012 01:47:00 +0000 (01:47 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Fri, 18 May 2012 01:47:00 +0000 (01:47 +0000)
warning. This also makes us warn on tags, which, ironically, is the only case
gcc warns on.

llvm-svn: 157039

clang/lib/Sema/SemaDecl.cpp
clang/test/Sema/attr-decl-after-definition.c

index cc42720..6de5627 100644 (file)
@@ -1698,9 +1698,30 @@ bool Sema::mergeDeclAttribute(Decl *D, InheritableAttr *Attr) {
   return false;
 }
 
+static const Decl *getDefinition(Decl *D) {
+  if (TagDecl *TD = dyn_cast<TagDecl>(D))
+    return TD->getDefinition();
+  if (VarDecl *VD = dyn_cast<VarDecl>(D))
+    return VD->getDefinition();
+  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(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<VarDecl>(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<FunctionDecl>(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<OverloadableAttr>() && 
index 4d32e00..ba6df59 100644 (file)
@@ -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}}