This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH for c++/67164 (error with variadic templates)


When we instantiate an element of a pack expansion, we replace the argument pack in the template argument vec with an ARGUMENT_PACK_SELECT which indicates the desired element of the vec. If the args have been used to instantiate other templates as well, the args of those instances get modified as well, which can lead to strange results when we run into ARGUMENT_PACK_SELECT in inappropriate places. This patch fixes this issue by making a copy of the template args before we start messing with them.

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

commit e32e331a8f6ada0c20ff13240bac030020f627bf
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Mar 2 09:17:20 2016 -0500

    	PR c++/67164
    
    	* pt.c (copy_template_args): New.
    	(tsubst_pack_expansion): Use it.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b3681be..c5b9201 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -178,6 +178,7 @@ static int check_cv_quals_for_unify (int, tree, tree);
 static void template_parm_level_and_index (tree, int*, int*);
 static int unify_pack_expansion (tree, tree, tree,
 				 tree, unification_kind_t, bool, bool);
+static tree copy_template_args (tree);
 static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
@@ -11037,11 +11038,12 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
   /* For each argument in each argument pack, substitute into the
      pattern.  */
   result = make_tree_vec (len);
+  tree elem_args = copy_template_args (args);
   for (i = 0; i < len; ++i)
     {
       t = gen_elem_of_pack_expansion_instantiation (pattern, packs,
 						    i,
-						    args, complain,
+						    elem_args, complain,
 						    in_decl);
       TREE_VEC_ELT (result, i) = t;
       if (t == error_mark_node)
@@ -11136,6 +11138,32 @@ make_argument_pack (tree vec)
   return pack;
 }
 
+/* Return an exact copy of template args T that can be modified
+   independently.  */
+
+static tree
+copy_template_args (tree t)
+{
+  if (t == error_mark_node)
+    return t;
+
+  int len = TREE_VEC_LENGTH (t);
+  tree new_vec = make_tree_vec (len);
+
+  for (int i = 0; i < len; ++i)
+    {
+      tree elt = TREE_VEC_ELT (t, i);
+      if (elt && TREE_CODE (elt) == TREE_VEC)
+	elt = copy_template_args (elt);
+      TREE_VEC_ELT (new_vec, i) = elt;
+    }
+
+  NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_vec)
+    = NON_DEFAULT_TEMPLATE_ARGS_COUNT (t);
+
+  return new_vec;
+}
+
 /* Substitute ARGS into the vector or list of template arguments T.  */
 
 static tree
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-tuple2.C b/gcc/testsuite/g++.dg/cpp0x/variadic-tuple2.C
new file mode 100644
index 0000000..43c00e9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-tuple2.C
@@ -0,0 +1,29 @@
+// PR c++/67164
+// { dg-do compile { target c++11 } }
+
+#include <type_traits>
+
+namespace detail {
+    template <bool ...b>
+    struct fast_and
+        : std::is_same<fast_and<b...>, fast_and<(b, true)...>>
+    { };
+}
+
+template <typename ...Xn>
+struct tuple {
+    tuple() { }
+
+    template <typename ...Yn, typename = typename std::enable_if<
+        detail::fast_and<std::is_constructible<Xn, Yn&&>::value...>::value
+    >::type>
+    tuple(Yn&& ...yn) { }
+
+    template <typename ...Yn, typename = typename std::enable_if<
+        detail::fast_and<std::is_constructible<Xn, Yn const&>::value...>::value
+    >::type>
+    tuple(tuple<Yn...> const& other) { }
+};
+
+tuple<tuple<>> t{};
+tuple<tuple<>> copy = t;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]