re PR c++/30112 (pragma redefine_extname fails when namespaces are involved)
authorJason Merrill <jason@redhat.com>
Fri, 22 Jul 2011 19:59:49 +0000 (15:59 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 22 Jul 2011 19:59:49 +0000 (15:59 -0400)
PR c++/30112
gcc/c-family/
* c-common.h: Declare c_linkage_bindings.
* c-pragma.c (handle_pragma_redefine_extname): Use it.
gcc/
* c-decl.c (c_linkage_bindings): Define.
gcc/cp/
* decl.c (cp_finish_decl): Apply pragma redefine_extname in
other namespaces as well.
* name-lookup.c (c_linkage_bindings): Define.
(lookup_extern_c_fun_in_all_ns): Rename from
lookup_extern_c_fun_binding_in_all_ns.  Return tree.
(pushdecl_maybe_friend_1): Adjust.  Copy DECL_ASSEMBLER_NAME.

Co-Authored-By: Mark Glisse <marc.glisse@normalesup.org>
From-SVN: r176650

gcc/ChangeLog
gcc/c-decl.c
gcc/c-family/ChangeLog
gcc/c-family/c-common.h
gcc/c-family/c-pragma.c
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/name-lookup.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/other/pragma-re-1.C

index 718291b5e9a769e938cc0c0d4fe06d5ced930f16..36f4ea1d96831a3649edb8c4e2b38e28b16aa8af 100644 (file)
@@ -1,3 +1,8 @@
+2011-07-22  Jason Merrill  <jason@redhat.com>
+
+       PR c++/30112
+       * c-decl.c (c_linkage_bindings): Define.
+
 2011-07-22  Eric Botcazou  <ebotcazou@adacore.com>
 
        PR debug/49815
index 3ed3c46e64c4d9598c8b0f52456a3ac2b7a6b1f2..33d2615bc229bdb0e8cbd251ce1f3cb64c95c9ca 100644 (file)
@@ -8501,6 +8501,14 @@ identifier_global_value  (tree t)
   return 0;
 }
 
+/* In C, the only C-linkage public declaration is at file scope.  */
+
+tree
+c_linkage_bindings (tree name)
+{
+  return identifier_global_value (name);
+}
+
 /* Record a builtin type for C.  If NAME is non-NULL, it is the name used;
    otherwise the name is found in ridpointers from RID_INDEX.  */
 
index 167ba510c9b8c6aaca8b1075564d3c4bbde54086..990302f17ce1ed7feabcd201ec7ec524b49e29b9 100644 (file)
@@ -1,5 +1,9 @@
 2011-07-22  Jason Merrill  <jason@redhat.com>
 
+       PR c++/30112
+       * c-common.h: Declare c_linkage_bindings.
+       * c-pragma.c (handle_pragma_redefine_extname): Use it.
+
        PR c++/49813
        * c-opts.c (set_std_cxx0x): Set flag_isoc94 and flag_isoc99.
        * c-pretty-print.c (pp_c_cv_qualifiers): Check c_dialect_cxx as well
index 13aae0f3ecc5a92d9e8622b7486fb2c615a0a404..202be02a0f3656f910678c3d8c2b3c409d4926d2 100644 (file)
@@ -710,6 +710,7 @@ extern void c_register_addr_space (const char *str, addr_space_t as);
 extern bool in_late_binary_op;
 extern const char *c_addr_space_name (addr_space_t as);
 extern tree identifier_global_value (tree);
+extern tree c_linkage_bindings (tree);
 extern void record_builtin_type (enum rid, const char *, tree);
 extern tree build_void_list_node (void);
 extern void start_fname_decls (void);
index 93735aa252388d99ab735b601c1942af0e1fce4b..5c8bc1f8ac786c3797c775ed276e166c05cf3303 100644 (file)
@@ -417,8 +417,9 @@ static void handle_pragma_redefine_extname (cpp_reader *);
 static void
 handle_pragma_redefine_extname (cpp_reader * ARG_UNUSED (dummy))
 {
-  tree oldname, newname, decl, x;
+  tree oldname, newname, decls, x;
   enum cpp_ttype t;
+  bool found;
 
   if (pragma_lex (&oldname) != CPP_NAME)
     GCC_BAD ("malformed #pragma redefine_extname, ignored");
@@ -428,26 +429,42 @@ handle_pragma_redefine_extname (cpp_reader * ARG_UNUSED (dummy))
   if (t != CPP_EOF)
     warning (OPT_Wpragmas, "junk at end of %<#pragma redefine_extname%>");
 
-  decl = identifier_global_value (oldname);
-  if (decl
-      && (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl))
-      && (TREE_CODE (decl) == FUNCTION_DECL
-         || TREE_CODE (decl) == VAR_DECL)
-      && has_c_linkage (decl))
+  found = false;
+  for (decls = c_linkage_bindings (oldname);
+       decls; )
     {
-      if (DECL_ASSEMBLER_NAME_SET_P (decl))
+      tree decl;
+      if (TREE_CODE (decls) == TREE_LIST)
        {
-         const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-         name = targetm.strip_name_encoding (name);
-
-         if (strcmp (name, IDENTIFIER_POINTER (newname)))
-           warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to "
-                    "conflict with previous rename");
+         decl = TREE_VALUE (decls);
+         decls = TREE_CHAIN (decls);
        }
       else
-       change_decl_assembler_name (decl, newname);
+       {
+         decl = decls;
+         decls = NULL_TREE;
+       }
+
+      if ((TREE_PUBLIC (decl) || DECL_EXTERNAL (decl))
+         && (TREE_CODE (decl) == FUNCTION_DECL
+             || TREE_CODE (decl) == VAR_DECL))
+       {
+         found = true;
+         if (DECL_ASSEMBLER_NAME_SET_P (decl))
+           {
+             const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+             name = targetm.strip_name_encoding (name);
+
+             if (strcmp (name, IDENTIFIER_POINTER (newname)))
+               warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to "
+                        "conflict with previous rename");
+           }
+         else
+           change_decl_assembler_name (decl, newname);
+       }
     }
-  else
+
+  if (!found)
     /* We have to add this to the rename list even if there's already
        a global value that doesn't meet the above criteria, because in
        C++ "struct foo {...};" puts "foo" in the current namespace but
index e314ae2a6149975dc4fae8fb52f888e1cba95c2f..49faf152ae3c8f16882421fa43fcf8a84d6fadbe 100644 (file)
@@ -1,3 +1,14 @@
+2011-07-22  Jason Merrill  <jason@redhat.com>
+           Mark Glisse  <marc.glisse@normalesup.org>
+
+       PR c++/30112
+       * decl.c (cp_finish_decl): Apply pragma redefine_extname in
+       other namespaces as well.
+       * name-lookup.c (c_linkage_bindings): Define.
+       (lookup_extern_c_fun_in_all_ns): Rename from
+       lookup_extern_c_fun_binding_in_all_ns.  Return tree.
+       (pushdecl_maybe_friend_1): Adjust.  Copy DECL_ASSEMBLER_NAME.
+
 2011-07-20  Jason Merrill  <jason@redhat.com>
 
        * parser.c (cp_parser_initializer_list): Handle C99 .id= and [N]=
index 067930375a8d0066fadad75bea64960476d34701..2000bd4a79d632872cba12e29d5872747611c136 100644 (file)
@@ -5919,7 +5919,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
   cleanup = NULL_TREE;
 
   /* If a name was specified, get the string.  */
-  if (global_scope_p (current_binding_level))
+  if (at_namespace_scope_p ())
     asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree);
   if (asmspec_tree && asmspec_tree != error_mark_node)
     asmspec = TREE_STRING_POINTER (asmspec_tree);
index 00d21d2e904f040458e292c9480f0e6686c0eafd..1afd9edffec795dd2248a742fc53fd3cabfde38b 100644 (file)
@@ -52,7 +52,7 @@ static bool qualified_lookup_using_namespace (tree, tree,
                                              struct scope_binding *, int);
 static tree lookup_type_current_level (tree);
 static tree push_using_directive (tree);
-static cxx_binding* lookup_extern_c_fun_binding_in_all_ns (tree);
+static tree lookup_extern_c_fun_in_all_ns (tree);
 
 /* The :: namespace.  */
 
@@ -768,18 +768,12 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
          && !DECL_ARTIFICIAL (x)
          && !DECL_IN_SYSTEM_HEADER (x))
        {
-         cxx_binding *function_binding =
-             lookup_extern_c_fun_binding_in_all_ns (x);
-         tree previous = (function_binding
-                          ? function_binding->value
-                          : NULL_TREE);
+         tree previous = lookup_extern_c_fun_in_all_ns (x);
          if (previous
              && !DECL_ARTIFICIAL (previous)
               && !DECL_IN_SYSTEM_HEADER (previous)
              && DECL_CONTEXT (previous) != DECL_CONTEXT (x))
            {
-             tree previous = function_binding->value;
-
              /* In case either x or previous is declared to throw an exception,
                 make sure both exception specifications are equal.  */
              if (decls_match (x, previous))
@@ -805,6 +799,9 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
                                "due to different exception specifications");
                      return error_mark_node;
                    }
+                 if (DECL_ASSEMBLER_NAME_SET_P (previous))
+                   SET_DECL_ASSEMBLER_NAME (x,
+                                            DECL_ASSEMBLER_NAME (previous));
                }
              else
                {
@@ -1996,14 +1993,14 @@ binding_for_name (cp_binding_level *scope, tree name)
 }
 
 /* Walk through the bindings associated to the name of FUNCTION,
-   and return the first binding that declares a function with a
+   and return the first declaration of a function with a
    "C" linkage specification, a.k.a 'extern "C"'.
    This function looks for the binding, regardless of which scope it
    has been defined in. It basically looks in all the known scopes.
    Note that this function does not lookup for bindings of builtin functions
    or for functions declared in system headers.  */
-static cxx_binding*
-lookup_extern_c_fun_binding_in_all_ns (tree function)
+static tree
+lookup_extern_c_fun_in_all_ns (tree function)
 {
   tree name;
   cxx_binding *iter;
@@ -2017,17 +2014,52 @@ lookup_extern_c_fun_binding_in_all_ns (tree function)
        iter;
        iter = iter->previous)
     {
-      if (iter->value
-         && TREE_CODE (iter->value) == FUNCTION_DECL
-         && DECL_EXTERN_C_P (iter->value)
-         && !DECL_ARTIFICIAL (iter->value))
+      tree ovl;
+      for (ovl = iter->value; ovl; ovl = OVL_NEXT (ovl))
        {
-         return iter;
+         tree decl = OVL_CURRENT (ovl);
+         if (decl
+             && TREE_CODE (decl) == FUNCTION_DECL
+             && DECL_EXTERN_C_P (decl)
+             && !DECL_ARTIFICIAL (decl))
+           {
+             return decl;
+           }
        }
     }
   return NULL;
 }
 
+/* Returns a list of C-linkage decls with the name NAME.  */
+
+tree
+c_linkage_bindings (tree name)
+{
+  tree decls = NULL_TREE;
+  cxx_binding *iter;
+
+  for (iter = IDENTIFIER_NAMESPACE_BINDINGS (name);
+       iter;
+       iter = iter->previous)
+    {
+      tree ovl;
+      for (ovl = iter->value; ovl; ovl = OVL_NEXT (ovl))
+       {
+         tree decl = OVL_CURRENT (ovl);
+         if (decl
+             && DECL_EXTERN_C_P (decl)
+             && !DECL_ARTIFICIAL (decl))
+           {
+             if (decls == NULL_TREE)
+               decls = decl;
+             else
+               decls = tree_cons (NULL_TREE, decl, decls);
+           }
+       }
+    }
+  return decls;
+}
+
 /* Insert another USING_DECL into the current binding level, returning
    this declaration. If this is a redeclaration, do nothing, and
    return NULL_TREE if this not in namespace scope (in namespace
index edb8c7205a6cfaa4125fa07b21ee3fd26fd499ed..5bf85f5b2e1d232472ce004a9e79bcb3a5915b51 100644 (file)
@@ -1,4 +1,8 @@
 2011-07-22  Jason Merrill  <jason@redhat.com>
+           Mark Glisse  <marc.glisse@normalesup.org>
+
+       PR c++/30112
+       * g++.dg/other/pragma-re-1.C: Add namespace cases.
 
        PR c++/49813
        * g++.dg/opt/builtins2.C: New.
index 35ffab1a82c1f67896e35c14baafd450d52edae2..6a94c5d68a7e77020c001a93fc1a42f57d6f57b6 100644 (file)
@@ -2,6 +2,12 @@
 /* { dg-final { scan-assembler-not "foo" } } */
 /* { dg-final { scan-assembler "_Z3bazv" } } */
 /* { dg-final { scan-assembler-not "baq" } } */
+/* { dg-final { scan-assembler "tut" } } */
+/* { dg-final { scan-assembler-not "gee" } } */
+/* { dg-final { scan-assembler "bang" } } */
+/* { dg-final { scan-assembler-not "whiz" } } */
+/* { dg-final { scan-assembler "eek" } } */
+/* { dg-final { scan-assembler-not "boo" } } */
 
 #ifndef __PRAGMA_REDEFINE_EXTNAME
 #error 
@@ -17,3 +23,35 @@ int (*p)(void) = foo;
 #pragma redefine_extname baz baq
 extern int baz(void);
 int (*q)(void) = baz;
+
+// PR c++/30112
+// These are expected to work.
+#pragma redefine_extname gee tut
+namespace somewhere {
+  extern "C" int gee(void);
+  int (*r)(void) = gee;
+
+  extern "C" int whiz(void);
+  int whiz(int);
+}
+#pragma redefine_extname whiz bang
+int (*s)() = somewhere::whiz;
+
+namespace elsewhere {
+  extern "C" int whiz(void);
+}
+int (*t)() = elsewhere::whiz;
+
+namespace A
+{
+  extern "C" int boo(void);
+}
+
+namespace B
+{
+  extern "C" int boo(void);
+}
+#pragma redefine_extname boo eek
+
+int (*u)() = A::boo;
+int (*v)() = B::boo;