Patchwork C++ PATCH for c++/55877 (wrong linkage for nested classes)

login
register
mail settings
Submitter Jason Merrill
Date Jan. 4, 2013, 4:48 p.m.
Message ID <50E707F0.5030704@redhat.com>
Download mbox | patch
Permalink /patch/209490/
State New
Headers show

Comments

Jason Merrill - Jan. 4, 2013, 4:48 p.m.
When an anonymous class gets a linkage name from a typedef, we 
recalculate its visibility; anonymous types have internal linkage, but 
types with linkage names have external linkage and therefore can have 
visibility.  But we were forgetting to also recalculate the visibility 
of any nested types, which were also affected by the former anonymity of 
the enclosing class.

Tested x86_64-pc-linux-gnu, applying to trunk, 4.7, 4.6.

Patch

commit 28beb0d493a46f126f23d15216d4ae9279223514
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 4 10:50:46 2013 -0500

    	PR c++/55877
    	* decl.c (reset_type_linkage, bt_reset_linkage): New.
    	(grokdeclarator): Use reset_type_linkage.
    	* name-lookup.c (binding_table_foreach): Handle null table.
    	* tree.c (decl_anon_ns_mem_p): Check TYPE_MAIN_DECL, not TYPE_NAME.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 5c268b1..9640824 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8513,6 +8513,23 @@  check_var_type (tree identifier, tree type)
   return type;
 }
 
+/* Functions for adjusting the visibility of a tagged type and its nested
+   types when it gets a name for linkage purposes from a typedef.  */
+
+static void bt_reset_linkage (binding_entry, void *);
+static void
+reset_type_linkage (tree type)
+{
+  set_linkage_according_to_type (type, TYPE_MAIN_DECL (type));
+  if (CLASS_TYPE_P (type))
+    binding_table_foreach (CLASSTYPE_NESTED_UTDS (type), bt_reset_linkage, NULL);
+}
+static void
+bt_reset_linkage (binding_entry b, void */*data*/)
+{
+  reset_type_linkage (b->type);
+}
+
 /* Given declspecs and a declarator (abstract or otherwise), determine
    the name and type of the object declared and construct a DECL node
    for it.
@@ -10053,8 +10070,7 @@  grokdeclarator (const cp_declarator *declarator,
 	      = TYPE_IDENTIFIER (type);
 
 	  /* Adjust linkage now that we aren't anonymous anymore.  */
-	  set_linkage_according_to_type (type, TYPE_MAIN_DECL (type));
-	  determine_visibility (TYPE_MAIN_DECL (type));
+	  reset_type_linkage (type);
 
 	  /* FIXME remangle member functions; member functions of a
 	     type with external linkage have external linkage.  */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 87b1f51..754e830 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -251,9 +251,13 @@  binding_table_find (binding_table table, tree name)
 void
 binding_table_foreach (binding_table table, bt_foreach_proc proc, void *data)
 {
-  const size_t chain_count = table->chain_count;
+  size_t chain_count;
   size_t i;
 
+  if (!table)
+    return;
+
+  chain_count = table->chain_count;
   for (i = 0; i < chain_count; ++i)
     {
       binding_entry entry = table->chain[i];
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index c658582..fcab1a4 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2404,7 +2404,7 @@  decl_anon_ns_mem_p (const_tree decl)
       /* Classes and namespaces inside anonymous namespaces have
          TREE_PUBLIC == 0, so we can shortcut the search.  */
       else if (TYPE_P (decl))
-	return (TREE_PUBLIC (TYPE_NAME (decl)) == 0);
+	return (TREE_PUBLIC (TYPE_MAIN_DECL (decl)) == 0);
       else if (TREE_CODE (decl) == NAMESPACE_DECL)
 	return (TREE_PUBLIC (decl) == 0);
       else
diff --git a/gcc/testsuite/g++.dg/ext/visibility/anon11.C b/gcc/testsuite/g++.dg/ext/visibility/anon11.C
new file mode 100644
index 0000000..dfb4f12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/visibility/anon11.C
@@ -0,0 +1,13 @@ 
+// PR c++/55877
+// { dg-final { scan-assembler-not "\\.local" } }
+
+typedef struct {
+  typedef enum { X, Y } A;
+  typedef struct { } B;
+  struct C { };
+} D;
+
+D d;
+D::A a;
+D::B b;
+D::C c;