PR c++/42758

Dodji Seketeli dodji@redhat.com
Thu Jan 21 15:05:00 GMT 2010


On Thu, Jan 21, 2010 at 03:29:30PM +0100, Dodji Seketeli wrote:
> On Tue, Jan 19, 2010 at 03:31:10PM -0500, Jason Merrill wrote:
> > Perhaps rather than try to recreate the information about which
> > arguments were defaulted at formatting time we should just remember
> > it, either by hanging the count off the TREE_VEC somewhere or
> > marking/wrapping the arguments themselves.
> 
> The patch below follows the first choice of storing the count in the
> arguments TREE_VEC.
> 
> I think it fixes a couple of other defaulted template arguments count 
> related PRs and mitigates a little bit PR c++/42336. So I have added 
> testcases of those tangent bugs I noticed in the patch.
> 
> Tested on x86_64-unknown-linux-gnu against trunk.

And now with the patch.

        Dodji

commit b2232a0a7a93bda7b0d841fc5d257e6ca086d0d4
Author: Dodji Seketeli <dodji@redhat.com>
Date:   Mon Jan 18 20:25:31 2010 +0100

    Fix PRs c++/42758, c++/42634, c++/42797
    
    ... and mitigate PR c++/42336
    
    gcc/cp/ChangeLog:
    	PR c++/42758
    	PR c++/42634
    	PR c++/42336
    	PR c++/42797
    	* cp-tree.h (NON_DEFAULT_TEMPLATE_ARGS_COUNT,
    	SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT,
    	GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT): New accessor macros.
    	* pt.c (coerce_template_parms, type_unification_real): Set the non
    	default template args count.
    	* error.c (get_non_default_template_args_count): Renamed
    	count_non_default_template_args into this. Don't calculare the
    	non default template argument count anymore. Use the new
    	accessor macros above to get it.
    	(dump_template_argument_list, dump_type, dump_decl,
    	dump_template_parms): Adjust.
    
    gcc/testsuite/ChangeLog:
    	PR c++/42758
    	PR c++/42634
    	PR c++/42336
    	PR c++/42797
    	* g++.dg/other/crash-5.C: New test.
    	* g++.dg/other/crash-6.C: New test.
    	* g++.dg/other/crash-7.C: New test.
    	* g++.dg/other/crash-8.C: New test.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 531ede1..d4b43b0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2493,6 +2493,19 @@ extern void decl_shadowed_for_var_insert (tree, tree);
 #define TI_TEMPLATE(NODE) TREE_TYPE (TEMPLATE_INFO_CHECK (NODE))
 #define TI_ARGS(NODE) TREE_CHAIN (TEMPLATE_INFO_CHECK (NODE))
 #define TI_PENDING_TEMPLATE_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
+/* For a given TREE_VEC containing a template argument list,
+   this property contains the number of arguments that are not
+   defaulted.  */
+#define NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE) TREE_CHAIN (TREE_VEC_CHECK (NODE))
+/* Below are the setter and getter of the NON_DEFAULT_TEMPLATE_ARGS_COUNT
+   property.  */
+#define SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE, INT_VALUE) \
+  NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE) = build_int_cst (NULL_TREE, INT_VALUE)
+#define GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE) \
+  NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE) \
+  ? int_cst_value (NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE)) \
+  : TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS (NODE))
+
 /* The list of typedefs - used in the template - that need
    access checking at template instantiation time.  */
 #define TI_TYPEDEFS_NEEDING_ACCESS_CHECKING(NODE) \
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index e0e5ae5..3d9f142 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -78,14 +78,12 @@ static void dump_global_iord (tree);
 static void dump_parameters (tree, int);
 static void dump_exception_spec (tree, int);
 static void dump_template_argument (tree, int);
-static void dump_template_argument_list (tree, tree, int);
+static void dump_template_argument_list (tree, int);
 static void dump_template_parameter (tree, int);
 static void dump_template_bindings (tree, tree, VEC(tree,gc) *);
 static void dump_scope (tree, int);
 static void dump_template_parms (tree, int, int);
-
-static int count_non_default_template_args (tree, tree, int);
-
+static int get_non_default_template_args_count (tree, int);
 static const char *function_category (tree);
 static void maybe_print_instantiation_context (diagnostic_context *);
 static void print_instantiation_full_context (diagnostic_context *);
@@ -147,7 +145,7 @@ static void
 dump_template_argument (tree arg, int flags)
 {
   if (ARGUMENT_PACK_P (arg))
-    dump_template_argument_list (ARGUMENT_PACK_ARGS (arg), NULL_TREE, flags);
+    dump_template_argument_list (ARGUMENT_PACK_ARGS (arg), flags);
   else if (TYPE_P (arg) || TREE_CODE (arg) == TEMPLATE_DECL)
     dump_type (arg, flags & ~TFF_CLASS_KEY_OR_ENUM);
   else
@@ -163,52 +161,29 @@ dump_template_argument (tree arg, int flags)
    match the (optional) default template parameter in PARAMS  */
 
 static int
-count_non_default_template_args (tree args, tree params, int flags)
+get_non_default_template_args_count (tree args, int flags)
 {
-  tree inner_args = INNERMOST_TEMPLATE_ARGS (args);
-  int n = TREE_VEC_LENGTH (inner_args);
-  int last;
+  int n = TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS (args));
 
-  if (params == NULL_TREE
-      /* We use this flag when generating debug information.  We don't
+  if (/* We use this flag when generating debug information.  We don't
 	 want to expand templates at this point, for this may generate
 	 new decls, which gets decl counts out of sync, which may in
 	 turn cause codegen differences between compilations with and
 	 without -g.  */
-      || (flags & TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS) != 0
+      (flags & TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS) != 0
       || !flag_pretty_templates)
     return n;
 
-  for (last = n - 1; last >= 0; --last)
-    {
-      tree param = TREE_VEC_ELT (params, last);
-      tree def = TREE_PURPOSE (param);
-
-      if (!def)
-        break;
-      if (uses_template_parms (def))
-	{
-	  ++processing_template_decl;
-	  /* This speculative substitution must not cause any classes to be
-	     instantiated that otherwise wouldn't be.  */
-	  def = tsubst_copy_and_build (def, args, tf_no_class_instantiations,
-				       NULL_TREE, false, true);
-	  --processing_template_decl;
-	}
-      if (!cp_tree_equal (TREE_VEC_ELT (inner_args, last), def))
-        break;
-    }
-
-  return last + 1;
+  return GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (INNERMOST_TEMPLATE_ARGS (args));
 }
 
 /* Dump a template-argument-list ARGS (always a TREE_VEC) under control
    of FLAGS.  */
 
 static void
-dump_template_argument_list (tree args, tree parms, int flags)
+dump_template_argument_list (tree args, int flags)
 {
-  int n = count_non_default_template_args (args, parms, flags);
+  int n = get_non_default_template_args_count (args, flags);
   int need_comma = 0;
   int i;
 
@@ -422,7 +397,7 @@ dump_type (tree t, int flags)
 	pp_cxx_cv_qualifier_seq (cxx_pp, t);
 	pp_cxx_tree_identifier (cxx_pp, TYPE_IDENTIFIER (t));
 	pp_cxx_begin_template_argument_list (cxx_pp);
-	dump_template_argument_list (args, NULL_TREE, flags);
+	dump_template_argument_list (args, flags);
 	pp_cxx_end_template_argument_list (cxx_pp);
       }
       break;
@@ -1041,7 +1016,7 @@ dump_decl (tree t, int flags)
 	dump_decl (name, flags);
 	pp_cxx_begin_template_argument_list (cxx_pp);
 	if (TREE_OPERAND (t, 1))
-	  dump_template_argument_list (TREE_OPERAND (t, 1), NULL_TREE, flags);
+	  dump_template_argument_list (TREE_OPERAND (t, 1), flags);
 	pp_cxx_end_template_argument_list (cxx_pp);
       }
       break;
@@ -1487,12 +1462,7 @@ dump_template_parms (tree info, int primary, int flags)
   if (args && !primary)
     {
       int len, ix;
-      /* We don't know the parms for a friend template specialization.  */
-      tree params = (TREE_CODE (TI_TEMPLATE (info)) == TEMPLATE_DECL
-		     ? DECL_INNERMOST_TEMPLATE_PARMS (TI_TEMPLATE (info))
-		     : NULL_TREE);
-
-      len = count_non_default_template_args (args, params, flags);
+      len = get_non_default_template_args_count (args, flags);
 
       args = INNERMOST_TEMPLATE_ARGS (args);
       for (ix = 0; ix != len; ix++)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f27b931..3be9fcc 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5889,9 +5889,16 @@ coerce_template_parms (tree parms,
             }
         }
       else if (require_all_args)
-        /* There must be a default arg in this case.  */
-        arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
-                                   complain, in_decl);
+	{
+	  /* There must be a default arg in this case.  */
+	  arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
+				     complain, in_decl);
+	  /* The position of the first default template argument,
+	     is also the number of non-defaulted arguments in NEW_INNER_ARGS.
+	     Record that.  */
+	  if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args))
+	    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_inner_args, arg_idx);
+	}
       else
 	break;
 
@@ -13245,6 +13252,10 @@ type_unification_real (tree tparms,
   gcc_assert (xparms == NULL_TREE || TREE_CODE (xparms) == TREE_LIST);
   gcc_assert (ntparms > 0);
 
+  /* Reset the number of non-defaulted template arguments contained
+     in in TARGS.  */
+  NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs) = NULL_TREE;
+
   switch (strict)
     {
     case DEDUCE_CALL:
@@ -13423,6 +13434,11 @@ type_unification_real (tree tparms,
               else
                 {
                   TREE_VEC_ELT (targs, i) = arg;
+		  /* The position of the first default template argument,
+		     is also the number of non-defaulted arguments in TARGS.
+		     Record that.  */
+		  if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
+		    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, i);
                   continue;
                 }
             }
diff --git a/gcc/testsuite/g++.dg/other/crash-5.C b/gcc/testsuite/g++.dg/other/crash-5.C
new file mode 100644
index 0000000..4205a33
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/crash-5.C
@@ -0,0 +1,19 @@
+// Origin: PR c++/42758
+// { dg-do compile }
+
+#include <cassert>
+#include <set>
+
+namespace spot
+{
+  struct int_less_than
+  {
+    bool operator()(int, int) const { return 0; }
+  };
+
+  int f(const std::set<int, int_less_than>&)
+  {
+    ((0) ? static_cast<void> (0) : __assert_fail ("0", "bug.cc", 13, __PRETTY_FUNCTION__));
+    return 1;
+  }
+}
diff --git a/gcc/testsuite/g++.dg/other/crash-6.C b/gcc/testsuite/g++.dg/other/crash-6.C
new file mode 100644
index 0000000..2220675
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/crash-6.C
@@ -0,0 +1,34 @@
+// Origin: PR c++/42634
+// { dg-options "-g -std=c++0x" }
+// { dg-do compile }
+
+template<typename T> T declval();
+
+template<typename T, typename... Args> struct is_constructible {
+    template<typename T1, typename... Args1> static decltype(T1(declval<Args1>()...), char()) test();
+    static const bool value = sizeof(test<T, Args...>()) == 1;
+};
+template<bool> struct enable_if {
+        typedef void type;
+};
+template<class T1, class T2> struct pair {
+    template<class U2,
+             class = typename enable_if<is_constructible<T2,U2&&>::value>::type
+             >
+    pair(const T1&, U2&&) { }
+};
+struct string {
+  string() : p(0) {}
+  char* p;
+};
+
+struct Foo {
+  string s;
+  int i;
+};
+
+void f()
+{
+  pair<int, Foo>(1, Foo());
+}
+
diff --git a/gcc/testsuite/g++.dg/other/crash-7.C b/gcc/testsuite/g++.dg/other/crash-7.C
new file mode 100644
index 0000000..db10490
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/crash-7.C
@@ -0,0 +1,19 @@
+// Origin: PR c++/42336
+// { dg-options "-O2 -g" }
+// { dg-do compile }
+
+struct X {
+      void func() {}
+};
+
+template<typename T, void (X::*P)() = &T::func>
+void b(T) {}
+
+int main() {
+      b(X()); /* line 9 */
+        X().func();
+
+          return 0;
+}
+
+
diff --git a/gcc/testsuite/g++.dg/other/crash-8.C b/gcc/testsuite/g++.dg/other/crash-8.C
new file mode 100644
index 0000000..497b46c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/crash-8.C
@@ -0,0 +1,18 @@
+// Origin: PR c++/42797
+// { dg-options "-g -02 -std=c++0x" }
+
+#include <vector>
+#include <map>
+struct Foo {
+    Foo() {}
+
+    template<typename Tp>
+    Foo(Tp *p) {}
+};
+
+void foo() {
+    std::map <int, std::vector<Foo>> the_map;
+
+    the_map[1] = std::vector<Foo>();
+}
+



More information about the Gcc-patches mailing list