Patchwork C++ PATCH for c++/45984 (canonical type ice with attributes)

login
register
mail settings
Submitter Jason Merrill
Date Oct. 14, 2010, 1:20 a.m.
Message ID <4CB65ADC.2030105@redhat.com>
Download mbox | patch
Permalink /patch/67764/
State New
Headers show

Comments

Jason Merrill - Oct. 14, 2010, 1:20 a.m.
The problem in this testcase was that when we see an 
elaborated-type-specifier for a class, and use it to form variants, then 
define the class with attributes, and use one of the same variants 
within the definition of the class, check_qualified_type didn't reuse 
the variant we had previously created because the attributes (and 
alignment) didn't match.  Fixed by propagating those two fields 
immediately after applying attributes.

Tested x86_64-pc-linux-gnu, applied to trunk.

Patch

commit e587ccbae647308fa483818592889c47e0924c03
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Oct 13 10:37:47 2010 -0400

    	PR c++/45984
    	* class.c (fixup_attribute_variants): New fn.
    	* cp-tree.h: Declare it.
    	* pt.c (instantiate_class_template): Call it.
    	* semantics.c (begin_class_definition): Call it.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index b093ce0..f76c2be 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1515,12 +1515,31 @@  fixup_type_variants (tree t)
       TYPE_VFIELD (variants) = TYPE_VFIELD (t);
       TYPE_METHODS (variants) = TYPE_METHODS (t);
       TYPE_FIELDS (variants) = TYPE_FIELDS (t);
+    }
+}
 
-      /* All variants of a class have the same attributes.  */
+/* Early variant fixups: we apply attributes at the beginning of the class
+   definition, and we need to fix up any variants that have already been
+   made via elaborated-type-specifier so that check_qualified_type works.  */
+
+void
+fixup_attribute_variants (tree t)
+{
+  tree variants;
+
+  if (!t)
+    return;
+
+  for (variants = TYPE_NEXT_VARIANT (t);
+       variants;
+       variants = TYPE_NEXT_VARIANT (variants))
+    {
+      /* These are the two fields that check_qualified_type looks at and
+	 are affected by attributes.  */
       TYPE_ATTRIBUTES (variants) = TYPE_ATTRIBUTES (t);
+      TYPE_ALIGN (variants) = TYPE_ALIGN (t);
     }
 }
-
 
 /* Set memoizing fields and bits of T (and its variants) for later
    use.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index bfc6fd3..29a4bdb 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4711,6 +4711,7 @@  extern bool type_has_move_assign		(tree);
 extern void defaulted_late_check		(tree);
 extern bool defaultable_fn_check		(tree);
 extern void fixup_type_variants			(tree);
+extern void fixup_attribute_variants		(tree);
 extern tree* decl_cloned_function_p		(const_tree, bool);
 extern void clone_function_decl			(tree, int);
 extern void adjust_clone_args			(tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 84901d3..9ddb4fd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7943,6 +7943,7 @@  instantiate_class_template (tree type)
   apply_late_template_attributes (&type, TYPE_ATTRIBUTES (pattern),
 				  (int) ATTR_FLAG_TYPE_IN_PLACE,
 				  args, tf_error, NULL_TREE);
+  fixup_attribute_variants (type);
 
   /* Now that our base classes are set up, enter the scope of the
      class, so that name lookups into base classes, etc. will work
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index b73dffb..787c72c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2391,6 +2391,7 @@  begin_class_definition (tree t, tree attributes)
   TYPE_BEING_DEFINED (t) = 1;
 
   cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
+  fixup_attribute_variants (t);
 
   if (flag_pack_struct)
     {
diff --git a/gcc/testsuite/g++.dg/template/canon-type-8.C b/gcc/testsuite/g++.dg/template/canon-type-8.C
new file mode 100644
index 0000000..fd1fe3c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/canon-type-8.C
@@ -0,0 +1,38 @@ 
+// PR c++/45984
+// We were getting different canonical types for matching types because
+// TYPE_ALIGN wasn't propagated to all the variants fast enough.
+// { dg-options "" }
+
+typedef __SIZE_TYPE__ size_t;
+enum { chunk_size = 16 };
+typedef float __m128 __attribute__ ((__vector_size__ (16), __may_alias__));
+typedef float __v4sf __attribute__ ((__vector_size__ (16)));
+struct __attribute__((aligned((16)))) float4_t {
+    typedef float scalar_t;
+    typedef __m128 type_t;
+    typedef float4_t return_type_t;
+    type_t m;
+    inline __attribute__((artificial, gnu_inline, always_inline)) explicit
+    float4_t(scalar_t a) : m(((__m128) (__v4sf) { (a), (a), (a), (a) })) { }
+    inline __attribute__((artificial, gnu_inline, always_inline, pure)) friend
+    return_type_t operator+(float4_t lhs, float4_t rhs) { }
+};
+template<size_t NumChans>  class __attribute__((aligned((16)))) chunk_array_t {
+public:
+    typedef float4_t value_type_t;
+    typedef value_type_t value_array_t[chunk_size/4];
+    enum { num_scalars = chunk_size,    num_values = num_scalars/4  };
+    const value_array_t &chan(size_t c) const { }
+    value_type_t operator[](size_t i) const { }
+};
+typedef chunk_array_t<1> chunk_array_mono_t;
+typedef chunk_array_t<2> chunk_array_stereo_t;
+class freeverb_stereo_t {
+    void process(const chunk_array_stereo_t & __restrict__ src,
+                 chunk_array_stereo_t & __restrict__ dst) {
+        enum { chunk_size = chunk_array_t<1>::num_values };
+        chunk_array_mono_t mix;
+        for (size_t i=0; i<chunk_size; ++i)
+          mix[i] = src.chan(0)[i] + src.chan(1)[i];
+    }
+};