r178488 - Only merge down a variable type if the previous declaration was

John McCall rjmccall at apple.com
Mon Apr 1 11:34:28 PDT 2013


Author: rjmccall
Date: Mon Apr  1 13:34:28 2013
New Revision: 178488

URL: http://llvm.org/viewvc/llvm-project?rev=178488&view=rev
Log:
Only merge down a variable type if the previous declaration was
visible.  There's a lot of potential badness in how we're modelling
these things, but getting this much correct is reasonably easy.

rdar://13535367

Added:
    cfe/trunk/test/CXX/basic/basic.link/p6.cpp
Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/Sema/extern-redecl.c

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=178488&r1=178487&r2=178488&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Apr  1 13:34:28 2013
@@ -1759,8 +1759,9 @@ public:
   bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
                                     Scope *S);
   void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old);
-  void MergeVarDecl(VarDecl *New, LookupResult &OldDecls);
-  void MergeVarDeclTypes(VarDecl *New, VarDecl *Old);
+  void MergeVarDecl(VarDecl *New, LookupResult &OldDecls,
+                    bool OldDeclsWereHidden);
+  void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldIsHidden);
   void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
   bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
 

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=178488&r1=178487&r2=178488&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Apr  1 13:34:28 2013
@@ -2773,7 +2773,7 @@ void Sema::mergeObjCMethodDecls(ObjCMeth
 /// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back
 /// to here in AddInitializerToDecl. We can't check them before the initializer
 /// is attached.
-void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
+void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) {
   if (New->isInvalidDecl() || Old->isInvalidDecl())
     return;
 
@@ -2820,7 +2820,11 @@ void Sema::MergeVarDeclTypes(VarDecl *Ne
     Diag(Old->getLocation(), diag::note_previous_definition);
     return New->setInvalidDecl();
   }
-  New->setType(MergedT);
+
+  // Don't actually update the type on the new declaration if the old
+  // declaration was a extern declaration in a different scope.
+  if (!OldWasHidden)
+    New->setType(MergedT);
 }
 
 /// MergeVarDecl - We just parsed a variable 'New' which has the same name
@@ -2831,7 +2835,8 @@ void Sema::MergeVarDeclTypes(VarDecl *Ne
 /// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative
 /// definitions here, since the initializer hasn't been attached.
 ///
-void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
+void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
+                        bool PreviousWasHidden) {
   // If the new decl is already invalid, don't do any other checking.
   if (New->isInvalidDecl())
     return;
@@ -2871,7 +2876,7 @@ void Sema::MergeVarDecl(VarDecl *New, Lo
   }
 
   // Merge the types.
-  MergeVarDeclTypes(New, Old);
+  MergeVarDeclTypes(New, Old, PreviousWasHidden);
   if (New->isInvalidDecl())
     return;
 
@@ -5206,13 +5211,39 @@ bool Sema::CheckVariableDeclaration(VarD
     NewVD->setTypeSourceInfo(FixedTInfo);
   }
 
+  // If we did not find anything by this name, look for a non-visible
+  // extern "C" declaration with the same name.
+  //
+  // Clang has a lot of problems with extern local declarations.
+  // The actual standards text here is:
+  //
+  // C++11 [basic.link]p6:
+  //   The name of a function declared in block scope and the name
+  //   of a variable declared by a block scope extern declaration
+  //   have linkage. If there is a visible declaration of an entity
+  //   with linkage having the same name and type, ignoring entities
+  //   declared outside the innermost enclosing namespace scope, the
+  //   block scope declaration declares that same entity and
+  //   receives the linkage of the previous declaration.
+  //
+  // C11 6.2.7p4:
+  //   For an identifier with internal or external linkage declared
+  //   in a scope in which a prior declaration of that identifier is
+  //   visible, if the prior declaration specifies internal or
+  //   external linkage, the type of the identifier at the later
+  //   declaration becomes the composite type.
+  //
+  // The most important point here is that we're not allowed to
+  // update our understanding of the type according to declarations
+  // not in scope.
+  bool PreviousWasHidden = false;
   if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) {
-    // Since we did not find anything by this name, look for a non-visible
-    // extern "C" declaration with the same name.
     llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
       = findLocallyScopedExternCDecl(NewVD->getDeclName());
-    if (Pos != LocallyScopedExternCDecls.end())
+    if (Pos != LocallyScopedExternCDecls.end()) {
       Previous.addDecl(Pos->second);
+      PreviousWasHidden = true;
+    }
   }
 
   // Filter out any non-conflicting previous declarations.
@@ -5245,7 +5276,7 @@ bool Sema::CheckVariableDeclaration(VarD
   }
 
   if (!Previous.empty()) {
-    MergeVarDecl(NewVD, Previous);
+    MergeVarDecl(NewVD, Previous, PreviousWasHidden);
     return true;
   }
   return false;
@@ -7277,7 +7308,7 @@ void Sema::AddInitializerToDecl(Decl *Re
     // If this is a redeclaration, check that the type we just deduced matches
     // the previously declared type.
     if (VarDecl *Old = VDecl->getPreviousDecl())
-      MergeVarDeclTypes(VDecl, Old);
+      MergeVarDeclTypes(VDecl, Old, /*OldWasHidden*/ false);
   }
 
   if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) {

Added: cfe/trunk/test/CXX/basic/basic.link/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.link/p6.cpp?rev=178488&view=auto
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.link/p6.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.link/p6.cpp Mon Apr  1 13:34:28 2013
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// C++11 [basic.link]p6:
+//   The name of a function declared in block scope and the name
+//   of a variable declared by a block scope extern declaration
+//   have linkage. If there is a visible declaration of an entity
+//   with linkage having the same name and type, ignoring entities
+//   declared outside the innermost enclosing namespace scope, the
+//   block scope declaration declares that same entity and
+//   receives the linkage of the previous declaration.
+
+// rdar://13535367
+namespace test0 {
+  extern "C" int test0_array[];
+  void declare() { extern int test0_array[100]; }
+  extern "C" int test0_array[];
+  int value = sizeof(test0_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
+
+namespace test1 {
+  extern "C" int test1_array[];
+  void test() {
+    { extern int test1_array[100]; }
+    extern int test1_array[];
+    int x = sizeof(test1_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+  }
+}
+
+namespace test2 {
+  void declare() { extern int test2_array[100]; }
+  extern int test2_array[];
+  int value = sizeof(test2_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
+
+namespace test3 {
+  void test() {
+    { extern int test3_array[100]; }
+    extern int test3_array[];
+    int x = sizeof(test3_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+  }
+}
+
+

Modified: cfe/trunk/test/Sema/extern-redecl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/extern-redecl.c?rev=178488&r1=178487&r2=178488&view=diff
==============================================================================
--- cfe/trunk/test/Sema/extern-redecl.c (original)
+++ cfe/trunk/test/Sema/extern-redecl.c Mon Apr  1 13:34:28 2013
@@ -22,3 +22,14 @@ int PR10013(void) {
 
 static int test1_a[]; // expected-warning {{tentative array definition assumed to have one element}}
 extern int test1_a[];
+
+// rdar://13535367
+void test2declarer() { extern int test2_array[100]; }
+extern int test2_array[];
+int test2v = sizeof(test2_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+
+void test3declarer() {
+  { extern int test3_array[100]; }
+  extern int test3_array[];
+  int x = sizeof(test3_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}





More information about the cfe-commits mailing list