Add type checking for tentative definitions at the end of the
translation unit.

Thread the various declarations of variables via
VarDecl::getPreviousDeclaration.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66601 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c5768fd..35573bb 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -776,56 +776,6 @@
   return false;
 }
 
-/// Predicate for C "tentative" external object definitions (C99 6.9.2).
-static bool isTentativeDefinition(VarDecl *VD) {
-  if (VD->isFileVarDecl())
-    return (!VD->getInit() &&
-            (VD->getStorageClass() == VarDecl::None ||
-             VD->getStorageClass() == VarDecl::Static));
-  return false;
-}
-
-/// CheckForFileScopedRedefinitions - Make sure we forgo redefinition errors
-/// when dealing with C "tentative" external object definitions (C99 6.9.2).
-void Sema::CheckForFileScopedRedefinitions(Scope *S, VarDecl *VD) {
-  bool VDIsTentative = isTentativeDefinition(VD);
-  bool VDIsIncompleteArray = VD->getType()->isIncompleteArrayType();
-  
-  // FIXME: I don't think this will actually see all of the
-  // redefinitions. Can't we check this property on-the-fly?
-  for (IdentifierResolver::iterator I = IdResolver.begin(VD->getIdentifier()), 
-                                    E = IdResolver.end(); 
-       I != E; ++I) {
-    if (*I != VD && isDeclInScope(*I, VD->getDeclContext(), S)) {
-      VarDecl *OldDecl = dyn_cast<VarDecl>(*I);
-      
-      // Handle the following case:
-      //   int a[10];
-      //   int a[];   - the code below makes sure we set the correct type. 
-      //   int a[11]; - this is an error, size isn't 10.
-      if (OldDecl && VDIsTentative && VDIsIncompleteArray && 
-          OldDecl->getType()->isConstantArrayType())
-        VD->setType(OldDecl->getType());
-      
-      // Check for "tentative" definitions. We can't accomplish this in 
-      // MergeVarDecl since the initializer hasn't been attached.
-      if (!OldDecl || isTentativeDefinition(OldDecl) || VDIsTentative)
-        continue;
-  
-      // Handle __private_extern__ just like extern.
-      if (OldDecl->getStorageClass() != VarDecl::Extern &&
-          OldDecl->getStorageClass() != VarDecl::PrivateExtern &&
-          VD->getStorageClass() != VarDecl::Extern &&
-          VD->getStorageClass() != VarDecl::PrivateExtern) {
-        Diag(VD->getLocation(), diag::err_redefinition) << VD->getDeclName();
-        Diag(OldDecl->getLocation(), diag::note_previous_definition);
-        // One redefinition error is enough.
-        break;
-      }
-    }
-  }
-}
-
 /// MergeVarDecl - We just parsed a variable 'New' which has the same name
 /// and scope as a previous declaration 'Old'.  Figure out how to resolve this
 /// situation, merging decls or emitting diagnostics as appropriate.
@@ -876,6 +826,10 @@
     Diag(Old->getLocation(), diag::note_previous_definition);
     return true;
   }
+
+  // Keep a chain of previous declarations.
+  New->setPreviousDeclaration(Old);
+
   return false;
 }
 
@@ -2168,6 +2122,15 @@
     return;
   }
 
+  const VarDecl *Def = 0;
+  if (VDecl->getDefinition(Def)) {
+    Diag(VDecl->getLocation(), diag::err_redefinition) 
+      << VDecl->getDeclName();
+    Diag(Def->getLocation(), diag::note_previous_definition);
+    VDecl->setInvalidDecl();
+    return;
+  }
+
   // Take ownership of the expression, now that we're sure we have somewhere
   // to put it.
   Expr *Init = static_cast<Expr *>(init.release());
@@ -2349,7 +2312,7 @@
     // storage-class specifier or with the storage-class specifier "static",
     // constitutes a tentative definition. Note: A tentative definition with
     // external linkage is valid (C99 6.2.2p5).
-    if (!getLangOptions().CPlusPlus && isTentativeDefinition(IDecl)) {
+    if (IDecl->isTentativeDefinition(Context)) {
       QualType CheckType = T;
       unsigned DiagID = diag::err_typecheck_decl_incomplete_type;
 
@@ -2369,8 +2332,6 @@
         IDecl->setInvalidDecl();
       }
     }
-    if (IDecl->isFileVarDecl())
-      CheckForFileScopedRedefinitions(S, IDecl);
   }
   return NewGroup;
 }