Fix the following redefinition errors submitted by Keith Bauer...

[dylan:~/llvm/tools/clang] admin% cat tentative_decls.c 
// incorrectly generates redefinition error
extern int array[3];
int array[3];

// incorrectly generates a redefinition error
extern void nup(int a[3]);
void nup(int a[3]) {}

It turns out that this exposed a fairly major flaw in the type system,
array types were never getting uniqued! This is because all array types
contained an expression, which aren't unique.

To solve this, we now have 2 array types, ConstantArrayType and
VariableArrayType. ConstantArrayType's are unique, VAT's aren't.

This is a fairly extensive set of fundamental changes. Fortunately,
all the tests pass. Nevertheless, there may be some collateral damage:-)
If so, let me know!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41592 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp
index 9a781b9..f1a6e78 100644
--- a/Sema/SemaDecl.cpp
+++ b/Sema/SemaDecl.cpp
@@ -29,28 +29,38 @@
 // a constant expression of type int with a value greater than zero.
 bool Sema::VerifyConstantArrayType(const ArrayType *Array,
                                    SourceLocation DeclLoc) { 
-  const Expr *Size = Array->getSizeExpr();
-  if (Size == 0) return false;  // incomplete type.
+  if (const VariableArrayType *VLA = dyn_cast<VariableArrayType>(Array)) {
+    Expr *Size = VLA->getSizeExpr();
+    if (Size == 0)
+      return false; // incomplete type.
   
-  if (!Size->getType()->isIntegerType()) {
-    Diag(Size->getLocStart(), diag::err_array_size_non_int, 
-         Size->getType().getAsString(), Size->getSourceRange());
+    if (!Size->getType()->isIntegerType()) {
+      Diag(Size->getLocStart(), diag::err_array_size_non_int, 
+           Size->getType().getAsString(), Size->getSourceRange());
+      return false;
+    }
+    // FIXME: I don't think this is needed. It remains to keep test
+    // builtin_classify_type() happy...will revisit soon (today is 8/29/07:-)
+    SourceLocation Loc;
+    llvm::APSInt SizeVal(32);
+    if (!Size->isIntegerConstantExpr(SizeVal, Context, &Loc)) {
+      // FIXME: This emits the diagnostic to enforce 6.7.2.1p8, but the message
+      // is wrong.  It is also wrong for static variables.
+      // FIXME: This is also wrong for:
+      // int sub1(int i, char *pi) { typedef int foo[i];
+      // struct bar {foo f1; int f2:3; int f3:4} *p; }
+      Diag(DeclLoc, diag::err_typecheck_illegal_vla, Size->getSourceRange());
+      return false;
+    }
     return true;
   }
+  const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Array);  
 
-  // Verify that the size of the array is an integer constant expr.
-  SourceLocation Loc;
-  llvm::APSInt SizeVal(32);
-  if (!Size->isIntegerConstantExpr(SizeVal, Context, &Loc)) {
-    // FIXME: This emits the diagnostic to enforce 6.7.2.1p8, but the message
-    // is wrong.  It is also wrong for static variables.
-    // FIXME: This is also wrong for:
-    // int sub1(int i, char *pi) { typedef int foo[i];
-    // struct bar {foo f1; int f2:3; int f3:4} *p; }
-    Diag(DeclLoc, diag::err_typecheck_illegal_vla, Size->getSourceRange());
-    return true;
-  }
+  assert(CAT && "Sema::VerifyConstantArrayType(): Illegal array type");
   
+  llvm::APSInt SizeVal(32);
+  SizeVal = CAT->getSize();
+
   // We have a constant expression with an integer type, now make sure 
   // value greater than zero (C99 6.7.5.2p1).
   
@@ -61,13 +71,11 @@
     llvm::APSInt Zero(SizeVal.getBitWidth());
     Zero.setIsUnsigned(false);
     if (SizeVal < Zero) {
-      Diag(DeclLoc, diag::err_typecheck_negative_array_size,
-           Size->getSourceRange());
+      Diag(DeclLoc, diag::err_typecheck_negative_array_size);
       return true;
     } else if (SizeVal == 0) {
       // GCC accepts zero sized static arrays.
-      Diag(DeclLoc, diag::err_typecheck_zero_array_size, 
-           Size->getSourceRange());
+      Diag(DeclLoc, diag::err_typecheck_zero_array_size);
     }
   }
   return false;
@@ -252,6 +260,17 @@
     Diag(OldD->getLocation(), diag::err_previous_definition);
     return New;
   }
+  FileVarDecl *OldFSDecl = dyn_cast<FileVarDecl>(Old);
+  FileVarDecl *NewFSDecl = dyn_cast<FileVarDecl>(New);
+  bool OldIsTentative = false;
+  
+  if (OldFSDecl && NewFSDecl) { // C99 6.9.2
+    // Handle C "tentative" external object definitions. FIXME: finish!
+    if (!OldFSDecl->getInit() &&
+        (OldFSDecl->getStorageClass() == VarDecl::None ||
+         OldFSDecl->getStorageClass() == VarDecl::Static))
+      OldIsTentative = true;
+  }
   // Verify the types match.
   if (Old->getCanonicalType() != New->getCanonicalType()) {
     Diag(New->getLocation(), diag::err_redefinition, New->getName());