Patchwork C++ PATCH for c++/48138 (losing __attribute ((aligned)) on template argument)

login
register
mail settings
Submitter Jason Merrill
Date June 21, 2011, 2:12 a.m.
Message ID <4DFFFDF9.6040508@redhat.com>
Download mbox | patch
Permalink /patch/101232/
State New
Headers show

Comments

Jason Merrill - June 21, 2011, 2:12 a.m.
On 06/20/2011 10:23 AM, Jason Merrill wrote:
> strip_typedefs needs to propagate DECL_USER_ALIGN as well as attributes
> in the attribute list.

...except that we don't want to retain attributes on template type 
arguments, since they aren't part of mangling, so you could get a class 
template instantiation that is the same type regardless of the alignment 
of the argument, but the effective argument varies depending on which 
alignment was first used to instantiate it.

The PR suggests a warning when we drop the attributes, which makes 
sense.  This patch does not yet provide the warning in the case of 
function templates, but does for class templates.  Warning for function 
templates will wait until after Nathan's patch to improve template 
overloading diagnostics.

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

Patch

commit d4813fc54ee69f5880e588e8b9edf97baa0ad6cc
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 20 14:37:05 2011 -0400

    	PR c++/48138
    	* pt.c (canonicalize_type_argument): New.
    	(convert_template_argument, unify): Use it.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 6f15101..4d2caa8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5916,6 +5916,28 @@  template_template_parm_bindings_ok_p (tree tparms, tree targs)
   return ret;
 }
 
+/* Since type attributes aren't mangled, we need to strip them from
+   template type arguments.  */
+
+static tree
+canonicalize_type_argument (tree arg, tsubst_flags_t complain)
+{
+  tree mv;
+  if (!arg || arg == error_mark_node || arg == TYPE_CANONICAL (arg))
+    return arg;
+  mv = TYPE_MAIN_VARIANT (arg);
+  arg = strip_typedefs (arg);
+  if (TYPE_ALIGN (arg) != TYPE_ALIGN (mv)
+      || TYPE_ATTRIBUTES (arg) != TYPE_ATTRIBUTES (mv))
+    {
+      if (complain & tf_warning)
+	warning (0, "ignoring attributes on template argument %qT", arg);
+      arg = build_aligned_type (arg, TYPE_ALIGN (mv));
+      arg = cp_build_type_attribute_variant (arg, TYPE_ATTRIBUTES (mv));
+    }
+  return arg;
+}
+
 /* Convert the indicated template ARG as necessary to match the
    indicated template PARM.  Returns the converted ARG, or
    error_mark_node if the conversion was unsuccessful.  Error and
@@ -6092,7 +6114,7 @@  convert_template_argument (tree parm,
 	 the typedef, which is confusing if those future uses do not
 	 themselves also use the typedef.  */
       if (TYPE_P (val))
-	val = strip_typedefs (val);
+	val = canonicalize_type_argument (val, complain);
     }
   else
     {
@@ -6136,8 +6158,9 @@  convert_template_argument (tree parm,
       if (TREE_CODE (val) == SCOPE_REF)
 	{
 	  /* Strip typedefs from the SCOPE_REF.  */
-	  tree type = strip_typedefs (TREE_TYPE (val));
-	  tree scope = strip_typedefs (TREE_OPERAND (val, 0));
+	  tree type = canonicalize_type_argument (TREE_TYPE (val), complain);
+	  tree scope = canonicalize_type_argument (TREE_OPERAND (val, 0),
+						   complain);
 	  val = build_qualified_name (type, scope, TREE_OPERAND (val, 1),
 				      QUALIFIED_NAME_IS_TEMPLATE (val));
 	}
@@ -15479,7 +15502,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	    return 1;
 
 	  /* Strip typedefs as in convert_template_argument.  */
-	  arg = strip_typedefs (arg);
+	  arg = canonicalize_type_argument (arg, tf_none);
 	}
 
       /* If ARG is a parameter pack or an expansion, we cannot unify
diff --git a/gcc/testsuite/g++.dg/ext/attr-aligned01.C b/gcc/testsuite/g++.dg/ext/attr-aligned01.C
index a051c6e..c8ec07d 100644
--- a/gcc/testsuite/g++.dg/ext/attr-aligned01.C
+++ b/gcc/testsuite/g++.dg/ext/attr-aligned01.C
@@ -1,20 +1,25 @@ 
 // PR c++/48138
-// { dg-options -std=c++0x }
 
 #define ALIGNED(x) __attribute__((aligned(x)))
-#define SA(X) static_assert ((X),#X)
+#define SA(X) int ar[(X)?1:-1];
 
 template<typename T>
 void type_alignment(const T&) {
   struct { char c; T t; } s;
-  SA((char*)&s.t - (char*)&s.c == 8);
+  SA((char*)&s.t - (char*)&s.c == 1);
 }
 
+template <class T> struct A { char c; T t; };
+
 int main() {
   typedef char unaligned[15];
   typedef char aligned[15] ALIGNED(8);
 
+  A<aligned> a;			// { dg-warning "ignoring attributes" }
+
+  SA((char*)&a.t - (char*)&a.c == 1);
+
   aligned z;
-  type_alignment(z);
-  type_alignment<unaligned ALIGNED(8)>(z);
+  type_alignment(z);		// { dg-warning "ignoring attributes" "" { xfail *-*-* } }
+  type_alignment<unaligned ALIGNED(8)>(z); // { dg-warning "ignoring attributes" "" { xfail *-*-* } }
 }