decl.c (pushdecl): Matching decls for local externs are found in the current level.
authorJason Merrill <jason@redhat.com>
Mon, 28 Aug 2000 01:16:08 +0000 (21:16 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 28 Aug 2000 01:16:08 +0000 (21:16 -0400)
        * decl.c (pushdecl): Matching decls for local externs are found in
        the current level.  Propagate linkage information from previous
        declarations.

From-SVN: r36011

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/g++.old-deja/g++.other/scope1.C [new file with mode: 0644]

index 1c263e5b0d6df1711650c078286e0e6e451fbce2..507edd876a01b2fefe41d4d461c3d090e51c60d1 100644 (file)
@@ -1,3 +1,9 @@
+2000-08-27  Jason Merrill  <jason@redhat.com>
+
+       * decl.c (pushdecl): Matching decls for local externs are found in
+       the current level.  Propagate linkage information from previous
+       declarations.
+
 2000-08-26  Gabriel Dos Reis  <gdr@codesourcery.com>
 
        * ir.texi (Expressions): Fix typo.
index 613c44e9a0c1087bb485c4d63cbf4710d1b7997b..552070b6e1d098995fd8d20a4827aac41084fcb9 100644 (file)
@@ -3852,7 +3852,7 @@ pushdecl (x)
              nesting.  */
          && !(TREE_CODE (x) == FUNCTION_DECL && !DECL_INITIAL (x))
          /* A local declaration for an `extern' variable is in the
-            scoped of the current namespace, not the current
+            scope of the current namespace, not the current
             function.  */
          && !(TREE_CODE (x) == VAR_DECL && DECL_EXTERNAL (x))
          && !DECL_CONTEXT (x))
@@ -3871,20 +3871,40 @@ pushdecl (x)
   name = DECL_NAME (x);
   if (name)
     {
-#if 0
-      /* Not needed...see below.  */
-      char *file;
-      int line;
-#endif
+      int different_binding_level = 0;
+
       if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
        name = TREE_OPERAND (name, 0);
 
-      /* Namespace-scoped variables are not found in the current level. */
-      if (TREE_CODE (x) == VAR_DECL && DECL_NAMESPACE_SCOPE_P (x))
+      /* In case this decl was explicitly namespace-qualified, look it
+        up in its namespace context.  */
+      if (TREE_CODE (x) == VAR_DECL && DECL_NAMESPACE_SCOPE_P (x)
+         && namespace_bindings_p ())
        t = namespace_binding (name, DECL_CONTEXT (x));
       else
        t = lookup_name_current_level (name);
 
+      /* [basic.link] 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.  */
+      if (! t && current_function_decl && x != current_function_decl
+         && (TREE_CODE (x) == FUNCTION_DECL || TREE_CODE (x) == VAR_DECL)
+         && DECL_EXTERNAL (x))
+       {
+         /* Look in block scope.  */
+         t = IDENTIFIER_VALUE (name);
+         /* Or in the innermost namespace.  */
+         if (! t)
+           t = namespace_binding (name, DECL_CONTEXT (x));
+         /* Does it have linkage?  */
+         if (t && ! (TREE_STATIC (t) || DECL_EXTERNAL (t)))
+           t = NULL_TREE;
+         if (t)
+           different_binding_level = 1;
+       }
+
       /* If we are declaring a function, and the result of name-lookup
         was an OVERLOAD, look for an overloaded instance that is
         actually the same as the function we are declaring.  (If
@@ -3919,7 +3939,16 @@ pushdecl (x)
        }
       else if (t != NULL_TREE)
        {
-         if (TREE_CODE (t) == PARM_DECL)
+         if (different_binding_level)
+           {
+             if (decls_match (x, t))
+               /* The standard only says that the local extern
+                  inherits linkage from the previous decl; in
+                  particular, default args are not shared.  It would
+                  be nice to propagate inlining info, though.  FIXME.  */
+               TREE_PUBLIC (x) = TREE_PUBLIC (t);
+           }
+         else if (TREE_CODE (t) == PARM_DECL)
            {
              if (DECL_CONTEXT (t) == NULL_TREE)
                fatal ("parse errors have confused me too much");
diff --git a/gcc/testsuite/g++.old-deja/g++.other/scope1.C b/gcc/testsuite/g++.old-deja/g++.other/scope1.C
new file mode 100644 (file)
index 0000000..8b6354c
--- /dev/null
@@ -0,0 +1,12 @@
+// Testcase for proper scoping of local externs.
+
+int x = 1;
+
+int main()
+{   
+  int x = 2;
+  {
+    extern int x;
+    return (x != 1);
+  }
+}