[cfe-commits] r65385 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp test/Sema/var-redecl.c test/Sema/vla.c

Douglas Gregor dgregor at apple.com
Tue Feb 24 11:23:27 PST 2009


Author: dgregor
Date: Tue Feb 24 13:23:27 2009
New Revision: 65385

URL: http://llvm.org/viewvc/llvm-project?rev=65385&view=rev
Log:
Extend the implicit declaration and checking against out-of-scope
external declarations to also support external variable
declarations. Unified the code for these two cases into two new
subroutines.

Note that we fail to diagnose cases like the one Neil pointed
out, where a visible non-external declaration hides an external
declaration by the same name. That will require some reshuffling of
name lookup.


Added:
    cfe/trunk/test/Sema/var-redecl.c
Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/Sema/vla.c

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=65385&r1=65384&r2=65385&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Feb 24 13:23:27 2009
@@ -259,9 +259,10 @@
                                     QualType R, Decl* LastDeclarator,
                                     Decl* PrevDecl, bool& InvalidDecl,
                                     bool &Redeclaration);
+  void InjectLocallyScopedExternalDeclaration(ValueDecl *VD);
   NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                                      QualType R, Decl* LastDeclarator,
-                                     Decl* PrevDecl, bool& InvalidDecl,
+                                     NamedDecl* PrevDecl, bool& InvalidDecl,
                                      bool &Redeclaration);
   NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                                      QualType R, Decl *LastDeclarator,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=65385&r1=65384&r2=65385&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Feb 24 13:23:27 2009
@@ -1535,10 +1535,137 @@
   return NewTD;
 }
 
+/// \brief Determines whether the given declaration is an out-of-scope
+/// previous declaration.
+///
+/// This routine should be invoked when name lookup has found a
+/// previous declaration (PrevDecl) that is not in the scope where a
+/// new declaration by the same name is being introduced. If the new
+/// declaration occurs in a local scope, previous declarations with
+/// linkage may still be considered previous declarations (C99
+/// 6.2.2p4-5, C++ [basic.link]p6).
+///
+/// \param PrevDecl the previous declaration found by name
+/// lookup
+/// 
+/// \param DC the context in which the new declaration is being
+/// declared.
+///
+/// \returns true if PrevDecl is an out-of-scope previous declaration
+/// for a new delcaration with the same name.
+static bool 
+isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
+                                ASTContext &Context) {
+  if (!PrevDecl)
+    return 0;
+
+  // FIXME: PrevDecl could be an OverloadedFunctionDecl, in which
+  // case we need to check each of the overloaded functions.
+
+  if (Context.getLangOptions().CPlusPlus) {
+    // C++ [basic.link]p6:
+    //   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.
+    DeclContext *OuterContext = DC->getLookupContext();
+    if (!OuterContext->isFunctionOrMethod())
+      // This rule only applies to block-scope declarations.
+      return false;
+    else {
+      DeclContext *PrevOuterContext = PrevDecl->getDeclContext();
+      if (PrevOuterContext->isRecord())
+        // We found a member function: ignore it.
+        return false;
+      else {
+        // Find the innermost enclosing namespace for the new and
+        // previous declarations.
+        while (!OuterContext->isFileContext())
+          OuterContext = OuterContext->getParent();
+        while (!PrevOuterContext->isFileContext())
+          PrevOuterContext = PrevOuterContext->getParent();
+          
+        // The previous declaration is in a different namespace, so it
+        // isn't the same function.
+        if (OuterContext->getPrimaryContext() != 
+            PrevOuterContext->getPrimaryContext())
+          return false;
+      }
+    }
+  }
+
+  // If the declaration we've found has no linkage, ignore it. 
+  if (VarDecl *VD = dyn_cast<VarDecl>(PrevDecl)) {
+    if (!VD->hasGlobalStorage())
+      return false;
+  } else if (!isa<FunctionDecl>(PrevDecl))
+    return false;
+
+  return true;
+}
+
+/// \brief Inject a locally-scoped declaration with external linkage
+/// into the appropriate namespace scope.
+///
+/// Given a declaration of an entity with linkage that occurs within a
+/// local scope, this routine inject that declaration into top-level
+/// scope so that it will be visible for later uses and declarations
+/// of the same entity.
+void Sema::InjectLocallyScopedExternalDeclaration(ValueDecl *VD) {
+  // FIXME: We don't do this in C++ because, although we would like
+  // to get the extra checking that this operation implies, 
+  // the declaration itself is not visible according to C++'s rules.
+  assert(!getLangOptions().CPlusPlus && 
+         "Can't inject locally-scoped declarations in C++");
+  IdentifierResolver::iterator I = IdResolver.begin(VD->getDeclName()),
+                            IEnd = IdResolver.end();
+  NamedDecl *PrevDecl = 0;
+  while (I != IEnd && !isa<TranslationUnitDecl>((*I)->getDeclContext())) {
+    PrevDecl = *I;
+    ++I;
+  }
+
+  if (I == IEnd) {
+    // No name with this identifier has been declared at translation
+    // unit scope. Add this name into the appropriate scope.
+    if (PrevDecl)
+      IdResolver.AddShadowedDecl(VD, PrevDecl);
+    else
+      IdResolver.AddDecl(VD);
+    TUScope->AddDecl(VD);
+    return;
+  }
+
+  if (isa<TagDecl>(*I)) {
+    // The first thing we found was a tag declaration, so insert
+    // this function so that it will be found before the tag
+    // declaration.
+    if (PrevDecl)
+      IdResolver.AddShadowedDecl(VD, PrevDecl);
+    else
+      IdResolver.AddDecl(VD);
+    TUScope->AddDecl(VD);
+    return;
+  } 
+
+  if (VD->declarationReplaces(*I)) {
+    // We found a previous declaration of the same entity. Replace
+    // that declaration with this one.
+    TUScope->RemoveDecl(*I);
+    TUScope->AddDecl(VD);
+    IdResolver.RemoveDecl(*I);
+    if (PrevDecl)
+      IdResolver.AddShadowedDecl(VD, PrevDecl);
+    else
+      IdResolver.AddDecl(VD);
+  }
+}
+
 NamedDecl*
 Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                               QualType R, Decl* LastDeclarator,
-                              Decl* PrevDecl, bool& InvalidDecl,
+                              NamedDecl* PrevDecl, bool& InvalidDecl,
                               bool &Redeclaration) {
   DeclarationName Name = GetNameForDeclarator(D);
 
@@ -1624,9 +1751,18 @@
     Diag(D.getIdentifierLoc(), diag::warn_attribute_weak_on_local);
   }
 
-  // Merge the decl with the existing one if appropriate. If the decl is
-  // in an outer scope, it isn't the same thing.
-  if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) {
+  // If name lookup finds a previous declaration that is not in the
+  // same scope as the new declaration, this may still be an
+  // acceptable redeclaration.
+  if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) &&
+      !((NewVD->hasExternalStorage() ||
+         (NewVD->isFileVarDecl() && 
+          NewVD->getStorageClass() != VarDecl::Static)) &&
+        isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
+    PrevDecl = 0;     
+
+  // Merge the decl with the existing one if appropriate.
+  if (PrevDecl) {
     if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) {
       // The user tried to define a non-static data member
       // out-of-line (C++ [dcl.meaning]p1).
@@ -1647,6 +1783,14 @@
       InvalidDecl = true;
     }
   }
+
+  // If this is a locally-scoped extern variable in C, inject a
+  // declaration into translation unit scope so that all external
+  // declarations are visible.
+  if (!getLangOptions().CPlusPlus && CurContext->isFunctionOrMethod() &&
+      NewVD->hasExternalStorage())
+    InjectLocallyScopedExternalDeclaration(NewVD);
+
   return NewVD;
 }
 
@@ -1858,55 +2002,14 @@
       CheckOverloadedOperatorDeclaration(NewFD))
     NewFD->setInvalidDecl();
     
-  if (PrevDecl && !isDeclInScope(PrevDecl, DC, S)) {
-    // Name lookup has found a previous declaration that is not in the
-    // same scope as the new declaration. However, these two
-    // declarations might still declare the same thing (C99 6.2.2p3-4,
-    // C++ [basic.link]p6).
-
-    // FIXME: PrevDecl could be an OverloadedFunctionDecl, in which
-    // case we need to check each of the overloaded functions.
-
-    if (getLangOptions().CPlusPlus) {
-      // C++ [basic.link]p6:
-      //   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.
-      DeclContext *OuterContext = DC->getLookupContext();
-      if (!OuterContext->isFunctionOrMethod())
-        // This rule only applies to block-scope declarations.
-        PrevDecl = 0;
-      else {
-        DeclContext *PrevOuterContext = PrevDecl->getDeclContext();
-        if (PrevOuterContext->isRecord())
-          // We found a member function: ignore it.
-          PrevDecl = 0;
-        else {
-          // Find the innermost enclosing namespace for the new and
-          // previous declarations.
-          while (!OuterContext->isFileContext())
-            OuterContext = OuterContext->getParent();
-          while (!PrevOuterContext->isFileContext())
-            PrevOuterContext = PrevOuterContext->getParent();
-          
-          // The previous declaration is in a different namespace, so it
-          // isn't the same function.
-          if (OuterContext->getPrimaryContext() != 
-              PrevOuterContext->getPrimaryContext())
-            PrevDecl = 0;
-        }
-      }
-    }
-
-    // If the declaration we've found has no linkage, ignore it. 
-    if (VarDecl *VD = dyn_cast_or_null<VarDecl>(PrevDecl)) {
-      if (!VD->hasGlobalStorage())
-        PrevDecl = 0;
-    } else if (PrevDecl && !isa<FunctionDecl>(PrevDecl))
-      PrevDecl = 0;
-  }
+  // If name lookup finds a previous declaration that is not in the
+  // same scope as the new declaration, this may still be an
+  // acceptable redeclaration.
+  if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) &&
+      (isa<CXXMethodDecl>(NewFD) ||
+       NewFD->getStorageClass() == FunctionDecl::Static ||
+       !isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
+    PrevDecl = 0;
 
   // Merge or overload the declaration with an existing declaration of
   // the same name, if appropriate.
@@ -2034,56 +2137,11 @@
     }
   }
 
-  if (!getLangOptions().CPlusPlus && CurContext->isFunctionOrMethod()) {
-    // If this is a function declaration in local scope, inject its
-    // name into the top-level scope so that it will be visible to
-    // later uses and declarations of the same function, since the
-    // function is external.
-    // FIXME: We don't do this in C++ because, although we would like
-    // to get the extra checking that this operation implies, 
-    // the declaration itself is not visible according to C++'s rules.
-    IdentifierResolver::iterator I = IdResolver.begin(Name),
-                              IEnd = IdResolver.end();
-    NamedDecl *PrevIdDecl = 0;
-    while (I != IEnd && !isa<TranslationUnitDecl>((*I)->getDeclContext())) {
-      PrevIdDecl = *I;
-      ++I;
-    }
-
-    if (I == IEnd) {
-      // No name with this identifier has been declared at translation
-      // unit scope. Add this name into the appropriate scope.
-      if (PrevIdDecl)
-        IdResolver.AddShadowedDecl(NewFD, PrevIdDecl);
-      else
-        IdResolver.AddDecl(NewFD);
-      TUScope->AddDecl(NewFD);
-      return NewFD;      
-    }
-
-    if (isa<TagDecl>(*I)) {
-      // The first thing we found was a tag declaration, so insert
-      // this function so that it will be found before the tag
-      // declaration.
-      if (PrevIdDecl)
-        IdResolver.AddShadowedDecl(NewFD, PrevIdDecl);
-      else
-        IdResolver.AddDecl(NewFD);
-      TUScope->AddDecl(NewFD);
-    } else if (isa<FunctionDecl>(*I) && NewFD->declarationReplaces(*I)) {
-      // We found a previous declaration of the same function. Replace
-      // that declaration with this one.
-      TUScope->RemoveDecl(*I);
-      TUScope->AddDecl(NewFD);
-      IdResolver.RemoveDecl(*I);
-      if (PrevIdDecl)
-        IdResolver.AddShadowedDecl(NewFD, PrevIdDecl);
-      else
-        IdResolver.AddDecl(NewFD);
-    }
-
-    return NewFD;
-  }
+  // If this is a locally-scoped function in C, inject a declaration
+  // into translation unit scope so that all external declarations are
+  // visible.
+  if (!getLangOptions().CPlusPlus && CurContext->isFunctionOrMethod())
+    InjectLocallyScopedExternalDeclaration(NewFD);
 
   return NewFD;
 }

Added: cfe/trunk/test/Sema/var-redecl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/var-redecl.c?rev=65385&view=auto

==============================================================================
--- cfe/trunk/test/Sema/var-redecl.c (added)
+++ cfe/trunk/test/Sema/var-redecl.c Tue Feb 24 13:23:27 2009
@@ -0,0 +1,30 @@
+// RUN: clang -fsyntax-only -verify %s
+
+int outer1; // expected-note{{previous definition is here}}
+extern int outer2; // expected-note{{previous definition is here}}
+int outer4;
+int outer4; // expected-note{{previous definition is here}}
+int outer5;
+int outer6(float); // expected-note{{previous definition is here}}
+int outer7(float);
+
+void outer_test() {
+  extern float outer1; // expected-error{{redefinition of 'outer1' with a different type}}
+  extern float outer2; // expected-error{{redefinition of 'outer2' with a different type}}
+  extern float outer3; // expected-note{{previous definition is here}}
+  double outer4;
+  extern int outer5; // expected-note{{previous definition is here}}
+  extern int outer6; // expected-error{{redefinition of 'outer6' as different kind of symbol}}
+  int outer7;
+  extern int outer8; // expected-note{{previous definition is here}}
+  extern int outer9;
+  {
+    extern int outer9; // expected-note{{previous definition is here}}
+  }
+}
+
+int outer3; // expected-error{{redefinition of 'outer3' with a different type}}
+float outer4; // expected-error{{redefinition of 'outer4' with a different type}}
+float outer5;  // expected-error{{redefinition of 'outer5' with a different type}}
+int outer8(int); // expected-error{{redefinition of 'outer8' as different kind of symbol}}
+float outer9; // expected-error{{redefinition of 'outer9' with a different type}}

Modified: cfe/trunk/test/Sema/vla.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/vla.c?rev=65385&r1=65384&r2=65385&view=diff

==============================================================================
--- cfe/trunk/test/Sema/vla.c (original)
+++ cfe/trunk/test/Sema/vla.c Tue Feb 24 13:23:27 2009
@@ -19,9 +19,9 @@
 // PR2352
 void f2(unsigned int m)
 {
-  extern int e[2][m]; // expected-error {{variable length array declaration can not have 'extern' linkage}}
+  extern int e1[2][m]; // expected-error {{variable length array declaration can not have 'extern' linkage}}
 
-  e[0][0] = 0;
+  e1[0][0] = 0;
   
 }
 
@@ -37,7 +37,7 @@
   static int a[i]; // expected-error {{variable length array declaration can not have 'static' storage duration}}
   extern int b[i]; // expected-error {{variable length array declaration can not have 'extern' linkage}}
 
-  extern int (*c)[i]; // expected-error {{variably modified type declaration can not have 'extern' linkage}}
+  extern int (*c1)[i]; // expected-error {{variably modified type declaration can not have 'extern' linkage}}
   static int (*d)[i];
 }
 





More information about the cfe-commits mailing list