diff mbox

C++ PATCH for c++/69958 (wrong sizeof...)

Message ID 56D0AD60.5030106@redhat.com
State New
Headers show

Commit Message

Jason Merrill Feb. 26, 2016, 7:54 p.m. UTC
alias templates are supposed to be transparent, so when we see

template <typename T, typename...Ts>
using wrapped2 = list<T, size_for<Ts..., T>>;

the size_for<Ts..., T> needs to be expanded into sizeof...(something). 
There is no way to write this "something" in C++, but it's simple enough 
to leave it as an *_ARGUMENT_PACK within the compiler.

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

Patch

commit 772d7b6f7c13119525da6e470c8729f14f35152f
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Feb 26 13:53:08 2016 -0500

    	PR c++/69958
    	* pt.c (make_argument_pack): New.
    	(tsubst_copy) [SIZEOF_EXPR]: Handle partial expansion.
    	(tsubst_copy_and_build): Likewise.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index cd3eb67..b5855a8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11117,6 +11117,25 @@  get_pattern_parm (tree parm, tree tmpl)
   return patparm;
 }
 
+/* Make an argument pack out of the TREE_VEC VEC.  */
+
+static tree
+make_argument_pack (tree vec)
+{
+  tree pack;
+  tree elt = TREE_VEC_ELT (vec, 0);
+  if (TYPE_P (elt))
+    pack = cxx_make_type (TYPE_ARGUMENT_PACK);
+  else
+    {
+      pack = make_node (NONTYPE_ARGUMENT_PACK);
+      TREE_TYPE (pack) = TREE_TYPE (elt);
+      TREE_CONSTANT (pack) = 1;
+    }
+  SET_ARGUMENT_PACK_ARGS (pack, vec);
+  return pack;
+}
+
 /* Substitute ARGS into the vector or list of template arguments T.  */
 
 static tree
@@ -14066,7 +14085,8 @@  tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       }
 
     case SIZEOF_EXPR:
-      if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+      if (PACK_EXPANSION_P (TREE_OPERAND (t, 0))
+	  || ARGUMENT_PACK_P (TREE_OPERAND (t, 0)))
         {
           tree expanded, op = TREE_OPERAND (t, 0);
 	  int len = 0;
@@ -14077,7 +14097,11 @@  tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	  ++cp_unevaluated_operand;
 	  ++c_inhibit_evaluation_warnings;
 	  /* We only want to compute the number of arguments.  */
-	  expanded = tsubst_pack_expansion (op, args, complain, in_decl);
+	  if (PACK_EXPANSION_P (op))
+	    expanded = tsubst_pack_expansion (op, args, complain, in_decl);
+	  else
+	    expanded = tsubst_template_args (ARGUMENT_PACK_ARGS (op),
+					     args, complain, in_decl);
 	  --cp_unevaluated_operand;
 	  --c_inhibit_evaluation_warnings;
 
@@ -14093,13 +14117,15 @@  tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    return error_mark_node;
 	  else if (PACK_EXPANSION_P (expanded)
 		   || (TREE_CODE (expanded) == TREE_VEC
-		       && len > 0
-		       && PACK_EXPANSION_P (TREE_VEC_ELT (expanded, len-1))))
+		       && pack_expansion_args_count (expanded)))
+
 	    {
-	      if (TREE_CODE (expanded) == TREE_VEC)
-		expanded = TREE_VEC_ELT (expanded, len - 1);
+	      if (PACK_EXPANSION_P (expanded))
+		/* OK.  */;
+	      else if (TREE_VEC_LENGTH (expanded) == 1)
+		expanded = TREE_VEC_ELT (expanded, 0);
 	      else
-		PACK_EXPANSION_SIZEOF_P (expanded) = true;
+		expanded = make_argument_pack (expanded);
 
 	      if (TYPE_P (expanded))
 		return cxx_sizeof_or_alignof_type (expanded, SIZEOF_EXPR, 
@@ -16162,7 +16188,8 @@  tsubst_copy_and_build (tree t,
 					  length, stride, TREE_TYPE (op1)));
       }
     case SIZEOF_EXPR:
-      if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+      if (PACK_EXPANSION_P (TREE_OPERAND (t, 0))
+	  || ARGUMENT_PACK_P (TREE_OPERAND (t, 0)))
 	RETURN (tsubst_copy (t, args, complain, in_decl));
       /* Fall through */
       
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-sizeof4.C b/gcc/testsuite/g++.dg/cpp0x/variadic-sizeof4.C
new file mode 100644
index 0000000..1187429
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-sizeof4.C
@@ -0,0 +1,33 @@ 
+// PR c++/69958
+// { dg-do compile { target c++11 } }
+
+typedef decltype(sizeof(int)) size_t;
+
+template <typename...Ts>
+struct list { };
+
+template <size_t N>
+struct size {  };
+
+template <typename...Ts>
+using size_for = size<sizeof...(Ts)>;
+
+template<class T, class U> struct assert_same;
+template<class T> struct assert_same<T,T> {};
+
+template <typename T, typename...Ts>
+using wrapped = list<T, size_for<T, Ts...>>;
+
+// This assertion fails (produces size<4>)
+assert_same<
+    list<float, size<5>>,
+    wrapped<float, int, double, char, unsigned>> a3;
+
+
+template <typename T, typename...Ts>
+using wrapped2 = list<T, size_for<Ts..., T>>;
+
+// This assertion fails (produces size<2>)
+assert_same<
+    list<float, size<5>>,
+    wrapped2<float, int, double, char, unsigned>> a4;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-sizeof4a.C b/gcc/testsuite/g++.dg/cpp0x/variadic-sizeof4a.C
new file mode 100644
index 0000000..0e8096d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-sizeof4a.C
@@ -0,0 +1,33 @@ 
+// PR c++/69958
+// { dg-do compile { target c++11 } }
+
+typedef decltype(sizeof(int)) size_t;
+
+template <typename...Ts>
+struct list { };
+
+template <size_t N>
+struct size {  };
+
+template <unsigned...Ts>
+using size_for = size<sizeof...(Ts)>;
+
+template<class T, class U> struct assert_same;
+template<class T> struct assert_same<T,T> {};
+
+template <typename T, unsigned...Ts>
+using wrapped = list<T, size_for<0, Ts...>>;
+
+// This assertion fails (produces size<4>)
+assert_same<
+    list<float, size<5>>,
+  wrapped<float,2,3,4,5>> a3;
+
+
+template <typename T, unsigned...Ts>
+using wrapped2 = list<T, size_for<Ts..., 0>>;
+
+// This assertion fails (produces size<2>)
+assert_same<
+    list<float, size<5>>,
+  wrapped2<float,2,3,4,5>> a4;