Patchwork C++ PATCH for c++/52973 (wrong visibility with template base)

login
register
mail settings
Submitter Jason Merrill
Date June 2, 2012, 3:59 a.m.
Message ID <4FC98FB5.10308@redhat.com>
Download mbox | patch
Permalink /patch/162398/
State New
Headers show

Comments

Jason Merrill - June 2, 2012, 3:59 a.m.
The change in 4.7 to properly restrict visibility of a class based on 
its template arguments exposed this bug: we were waiting until after the 
base list is parsed to apply attributes, so if a class is used as a 
template argument in its own base list, it has the wrong visibility in 
that context.  Fixed by applying infix attributes before parsing the 
base list.  Happily, this also allows us to stop passing attributes 
around so much.

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

Patch

commit c9c80ae94d625b4bddb767441a90543db077127f
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jun 1 23:24:36 2012 -0400

    	PR c++/52973
    	* parser.c (cp_parser_class_head): Apply attributes here.
    	* semantics.c (begin_class_definition): Not here.
    	* cp-tree.h: Adjust.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 626c61f..d21c2bf 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5585,7 +5585,7 @@  extern tree finish_fname			(tree);
 extern void finish_translation_unit		(void);
 extern tree finish_template_type_parm		(tree, tree);
 extern tree finish_template_template_parm       (tree, tree);
-extern tree begin_class_definition		(tree, tree);
+extern tree begin_class_definition		(tree);
 extern void finish_template_decl		(tree);
 extern tree finish_template_type		(tree, tree, int);
 extern tree finish_base_specifier		(tree, tree, bool);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 7f9a94b..16139d6 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2008,7 +2008,7 @@  static tree cp_parser_class_name
 static tree cp_parser_class_specifier
   (cp_parser *);
 static tree cp_parser_class_head
-  (cp_parser *, bool *, tree *, tree *);
+  (cp_parser *, bool *, tree *);
 static enum tag_types cp_parser_class_key
   (cp_parser *);
 static void cp_parser_member_specification_opt
@@ -17908,7 +17908,6 @@  cp_parser_class_specifier_1 (cp_parser* parser)
   /* Parse the class-head.  */
   type = cp_parser_class_head (parser,
 			       &nested_name_specifier_p,
-			       &attributes,
 			       &bases);
   /* If the class-head was a semantic disaster, skip the entire body
      of the class.  */
@@ -17967,7 +17966,7 @@  cp_parser_class_specifier_1 (cp_parser* parser)
       scope = CP_DECL_CONTEXT (TYPE_MAIN_DECL (type));
       old_scope = push_inner_scope (scope);
     }
-  type = begin_class_definition (type, attributes);
+  type = begin_class_definition (type);
 
   if (type == error_mark_node)
     /* If the type is erroneous, skip the entire body of the class.  */
@@ -18224,7 +18223,6 @@  cp_parser_class_specifier (cp_parser* parser)
 static tree
 cp_parser_class_head (cp_parser* parser,
 		      bool* nested_name_specifier_p,
-		      tree *attributes_p,
 		      tree *bases)
 {
   tree nested_name_specifier;
@@ -18592,6 +18590,14 @@  cp_parser_class_head (cp_parser* parser,
   else if (type == error_mark_node)
     type = NULL_TREE;
 
+  if (type)
+    {
+      /* Apply attributes now, before any use of the class as a template
+	 argument in its base list.  */
+      cplus_decl_attributes (&type, attributes, (int)ATTR_FLAG_TYPE_IN_PLACE);
+      fixup_attribute_variants (type);
+    }
+
   /* We will have entered the scope containing the class; the names of
      base classes should be looked up in that context.  For example:
 
@@ -18618,7 +18624,6 @@  cp_parser_class_head (cp_parser* parser,
 
   if (type)
     DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location;
-  *attributes_p = attributes;
   if (type && (virt_specifiers & VIRT_SPEC_FINAL))
     CLASSTYPE_FINAL (type) = 1;
  out:
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 263ebc2..8fefce0 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2516,7 +2516,7 @@  check_template_template_default_arg (tree argument)
 /* Begin a class definition, as indicated by T.  */
 
 tree
-begin_class_definition (tree t, tree attributes)
+begin_class_definition (tree t)
 {
   if (error_operand_p (t) || error_operand_p (TYPE_MAIN_DECL (t)))
     return error_mark_node;
@@ -2573,9 +2573,6 @@  begin_class_definition (tree t, tree attributes)
   pushclass (t);
   TYPE_BEING_DEFINED (t) = 1;
 
-  cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
-  fixup_attribute_variants (t);
-
   if (flag_pack_struct)
     {
       tree v;
@@ -8696,7 +8693,7 @@  begin_lambda_type (tree lambda)
   xref_basetypes (type, /*bases=*/NULL_TREE);
 
   /* Start the class.  */
-  type = begin_class_definition (type, /*attributes=*/NULL_TREE);
+  type = begin_class_definition (type);
   if (type == error_mark_node)
     return error_mark_node;
 
diff --git a/gcc/objcp/objcp-decl.c b/gcc/objcp/objcp-decl.c
index ecc2b2b..8040469 100644
--- a/gcc/objcp/objcp-decl.c
+++ b/gcc/objcp/objcp-decl.c
@@ -49,7 +49,7 @@  objcp_start_struct (location_t loc ATTRIBUTE_UNUSED,
   CLASSTYPE_DECLARED_CLASS (s) = 0;  /* this is a 'struct', not a 'class'.  */
   xref_basetypes (s, NULL_TREE);     /* no base classes here!  */
 
-  return begin_class_definition (s, NULL_TREE);
+  return begin_class_definition (s);
 }
 
 tree 
diff --git a/gcc/testsuite/g++.dg/ext/attrib14.C b/gcc/testsuite/g++.dg/ext/attrib14.C
index c7e5f7a..ebe0456 100644
--- a/gcc/testsuite/g++.dg/ext/attrib14.C
+++ b/gcc/testsuite/g++.dg/ext/attrib14.C
@@ -2,8 +2,8 @@ 
 // The bogus attribute is ignored, but was in TYPE_ATTRIBUTES during
 // parsing of the class, causing some variants to have it and some not.
 
-struct __attribute__((bogus)) A
-{				// { dg-warning "ignored" "" }
+struct __attribute__((bogus)) A	// { dg-warning "ignored" "" }
+{
     virtual ~A();
     void foo(const A&);
     void bar(const A&);
diff --git a/gcc/testsuite/g++.dg/ext/visibility/template12.C b/gcc/testsuite/g++.dg/ext/visibility/template12.C
new file mode 100644
index 0000000..b9219d5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/visibility/template12.C
@@ -0,0 +1,13 @@ 
+// { dg-require-visibility "" }
+// { dg-options "-fvisibility=hidden" }
+// { dg-final { scan-not-hidden "_ZN1aI1bE1cE" } }
+
+template <class T> class __attribute__((visibility("default"))) a
+{
+public:
+  /* A */ static int c;
+};
+
+class __attribute__((visibility("default"))) b : a <b> {};
+
+template<> /* B */ int a<b>::c = 0;