]> granicus.if.org Git - clang/commitdiff
Many refinements to Sema::MergeVarDecl(). This routine still needs some re-work to...
authorSteve Naroff <snaroff@apple.com>
Wed, 30 Jan 2008 00:44:01 +0000 (00:44 +0000)
committerSteve Naroff <snaroff@apple.com>
Wed, 30 Jan 2008 00:44:01 +0000 (00:44 +0000)
This includes a fix to bz1908.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46540 91177308-0d34-0410-b5e6-96231b3b80d8

Sema/SemaDecl.cpp
include/clang/Basic/DiagnosticKinds.def
test/Sema/tentative-decls.c [new file with mode: 0644]

index 9dd306944d742dab5ddd0fcd78f3db6ef9544000..68177e03c8b8aedc920f4a9ab150575c7439e949 100644 (file)
@@ -319,26 +319,56 @@ VarDecl *Sema::MergeVarDecl(VarDecl *New, ScopedDecl *OldD) {
     Diag(OldD->getLocation(), diag::err_previous_definition);
     return New;
   }
+  // Verify the types match.
+  if (Old->getCanonicalType() != New->getCanonicalType() && 
+      !areEquivalentArrayTypes(New->getCanonicalType(), Old->getCanonicalType())) {
+    Diag(New->getLocation(), diag::err_redefinition, New->getName());
+    Diag(Old->getLocation(), diag::err_previous_definition);
+    return New;
+  }
+  // C99 6.2.2p4: Check if we have a static decl followed by a non-static.
+  if (New->getStorageClass() == VarDecl::Static &&
+      (Old->getStorageClass() == VarDecl::None ||
+       Old->getStorageClass() == VarDecl::Extern)) {
+    Diag(New->getLocation(), diag::err_static_non_static, New->getName());
+    Diag(Old->getLocation(), diag::err_previous_definition);
+    return New;
+  }
+  // C99 6.2.2p4: Check if we have a non-static decl followed by a static.
+  if (New->getStorageClass() != VarDecl::Static &&
+      Old->getStorageClass() == VarDecl::Static) {
+    Diag(New->getLocation(), diag::err_non_static_static, New->getName());
+    Diag(Old->getLocation(), diag::err_previous_definition);
+    return New;
+  }
+  // We've verified the types match, now handle "tentative" definitions.
   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 && NewFSDecl) {
+    // Handle C "tentative" external object definitions (C99 6.9.2).
+    bool OldIsTentative = false;
+    bool NewIsTentative = false;
+    
     if (!OldFSDecl->getInit() &&
         (OldFSDecl->getStorageClass() == VarDecl::None ||
          OldFSDecl->getStorageClass() == VarDecl::Static))
       OldIsTentative = true;
+      
+    // FIXME: this check doesn't work (since the initializer hasn't been
+    // attached yet). This check should be moved to FinalizeDeclaratorGroup.
+    // Unfortunately, by the time we get to FinializeDeclaratorGroup, we've 
+    // thrown out the old decl.
+    if (!NewFSDecl->getInit() &&
+        (NewFSDecl->getStorageClass() == VarDecl::None ||
+         NewFSDecl->getStorageClass() == VarDecl::Static))
+      ; // change to NewIsTentative = true; once the code is moved.
+    
+    if (NewIsTentative || OldIsTentative)
+      return New;
   }
-  // Verify the types match.
-  if (Old->getCanonicalType() != New->getCanonicalType() && 
-      !areEquivalentArrayTypes(New->getCanonicalType(), Old->getCanonicalType())) {
-    Diag(New->getLocation(), diag::err_redefinition, New->getName());
-    Diag(Old->getLocation(), diag::err_previous_definition);
-    return New;
-  }
-  // We've verified the types match, now check if Old is "extern".
-  if (Old->getStorageClass() != VarDecl::Extern) {
+  if (Old->getStorageClass() != VarDecl::Extern &&
+      New->getStorageClass() != VarDecl::Extern) {
     Diag(New->getLocation(), diag::err_redefinition, New->getName());
     Diag(Old->getLocation(), diag::err_previous_definition);
   }
index ad628af24f5f8d036953a7ce6f0a06a15f191586..83e9e84dce1bf52e08894ba5f9ecce69a8907389 100644 (file)
@@ -602,6 +602,10 @@ DIAG(err_undeclared_var_use, ERROR,
      "use of undeclared identifier '%0'")
 DIAG(err_redefinition, ERROR,
      "redefinition of '%0'")
+DIAG(err_static_non_static, ERROR,
+     "static declaration of '%0' follows non-static declaration")
+DIAG(err_non_static_static, ERROR,
+     "non-static declaration of '%0' follows static declaration")
 DIAG(err_redefinition_different_kind, ERROR,
      "redefinition of '%0' as different kind of symbol")
 DIAG(err_conflicting_types, ERROR,
diff --git a/test/Sema/tentative-decls.c b/test/Sema/tentative-decls.c
new file mode 100644 (file)
index 0000000..0c390fe
--- /dev/null
@@ -0,0 +1,24 @@
+// RUN: clang %s -verify -fsyntax-only
+
+const int a [1] = {1};
+extern const int a[];
+
+extern const int b[];
+const int b [1] = {1};
+
+extern const int c[] = {1}; // expected-warning{{'extern' variable has an initializer}}
+const int c[];
+
+int i1 = 1; // expected-error{{previous definition is here}}
+int i1 = 2; // expected-error{{redefinition of 'i1'}} // expected-error{{previous definition is here}}
+// FIXME: the following should not be an error (see related FIXME in Sema::MergeVarDecl). 
+int i1; // expected-error{{redefinition of 'i1'}}
+int i1;
+extern int i1; // expected-error{{previous definition is here}}
+static int i1; // expected-error{{static declaration of 'i1' follows non-static declaration}} expected-error{{previous definition is here}}
+int i1 = 3; // expected-error{{non-static declaration of 'i1' follows static declaration}}
+
+void func() {
+  extern int i1; // expected-error{{previous definition is here}}
+  static int i1; // expected-error{{static declaration of 'i1' follows non-static declaration}}
+}