Blob Blame History Raw
2008-03-25  Jakub Jelinek  <jakub@redhat.com>

	PR c++/35546
	* pt.c (apply_late_template_attributes): Don't call tsubst on
	first attribute argument if it is IDENTIFIER_NODE.

	* g++.dg/ext/attrib33.C: New test.

--- gcc/cp/pt.c.jj	2008-03-10 17:11:48.000000000 +0100
+++ gcc/cp/pt.c	2008-03-25 21:32:17.000000000 +0100
@@ -6717,9 +6717,29 @@ apply_late_template_attributes (tree *de
 	    {
 	      *p = TREE_CHAIN (t);
 	      TREE_CHAIN (t) = NULL_TREE;
-	      TREE_VALUE (t)
-		= tsubst_expr (TREE_VALUE (t), args, complain, in_decl,
-			       /*integral_constant_expression_p=*/false);
+	      /* If the first attribute argument is an identifier, don't
+		 pass it through tsubst.  Attributes like mode, format,
+		 cleanup and several target specific attributes expect it
+		 unmodified.  */
+	      if (TREE_VALUE (t)
+		  && TREE_CODE (TREE_VALUE (t)) == TREE_LIST
+		  && TREE_VALUE (TREE_VALUE (t))
+		  && (TREE_CODE (TREE_VALUE (TREE_VALUE (t)))
+		      == IDENTIFIER_NODE))
+		{
+		  tree chain
+		    = tsubst_expr (TREE_CHAIN (TREE_VALUE (t)), args, complain,
+				   in_decl,
+				   /*integral_constant_expression_p=*/false);
+		  if (chain != TREE_CHAIN (TREE_VALUE (t)))
+		    TREE_VALUE (t)
+		      = tree_cons (NULL_TREE, TREE_VALUE (TREE_VALUE (t)),
+				   chain);
+		}
+	      else
+		TREE_VALUE (t)
+		  = tsubst_expr (TREE_VALUE (t), args, complain, in_decl,
+				 /*integral_constant_expression_p=*/false);
 	      *q = t;
 	      q = &TREE_CHAIN (t);
 	    }
--- gcc/testsuite/g++.dg/ext/attrib33.C.jj	2008-03-25 23:05:51.000000000 +0100
+++ gcc/testsuite/g++.dg/ext/attrib33.C	2008-03-25 23:06:15.000000000 +0100
@@ -0,0 +1,18 @@
+// PR c++/35546
+// { dg-do compile }
+
+template <int N>
+struct T
+{
+  void foo (char const * ...) __attribute__ ((format (printf,2,3)));
+};
+
+template struct T<3>;
+
+template <typename T>
+struct U
+{
+  typedef T __attribute__((mode (SI))) V;
+};
+
+U<int>::V v;