[C++ PATCH] Fix ICE on new with value dependent args (PR c++/34336)

Jakub Jelinek jakub@redhat.com
Wed Dec 5 20:14:00 GMT 2007


Hi!

When building new with processing_template_decl, where neither args, placement
nor type are type dependent, but something is value dependent, build_new
might create NON_DEPENDENT_EXPRs:
  if (processing_template_decl)
    {
      if (dependent_type_p (type)
          || any_type_dependent_arguments_p (placement)
          || (nelts && type_dependent_expression_p (nelts))
          || (init != void_zero_node
              && any_type_dependent_arguments_p (init)))
        return build_raw_new_expr (placement, type, nelts, init,
                                   use_global_new);
      placement = build_non_dependent_args (placement);
      if (nelts)
        nelts = build_non_dependent_expr (nelts);
      if (init != void_zero_node)
        init = build_non_dependent_args (init);
    }
and call build_new_1 with that.  But stabilize_expr doesn't really like
to be called with NON_DEPENDENT_EXPR with side effects, e.g. get_target_expr
on it won't return a TARGET_EXPR, and there is really no point in
stabilizing expressions in templates, all we care about is issue proper
diagnostic and then throw everything away and just build_raw_new_expr
from the original arguments. 

Attached are 2 possible approaches, one modifies stabilize_call and
stabilize_init to return immediately if processing_template_decl
(similarly e.g. to how cp_save_expr returns immediately), the other
modifies the caller (build_new_1) not to call these when
processing_template_decl.  stabilize_call is only called by stabilize_init
and build_new_1, stabilize_init is only called by build_new_1 and
build_throw (but the later only if !processing_template_decl).
So both patches are functionally equivalent.  I've regtested both with
make check-g++ and will throw the first one in the bootstrap/full regtest
I'm about to start.

Ok for trunk?  Which one?

	Jakub
-------------- next part --------------
2007-12-05  Jakub Jelinek  <jakub@redhat.com>

	PR c++/34336
	* tree.c (stabilize_call, stabilize_init): Do nothing if
	processing_template_decl.

	* g++.dg/template/new8.C: New test.

--- gcc/cp/tree.c.jj	2007-11-29 19:38:34.000000000 +0100
+++ gcc/cp/tree.c	2007-12-05 17:57:06.000000000 +0100
@@ -2602,8 +2602,11 @@ stabilize_call (tree call, tree *initp)
   int i;
   int nargs = call_expr_nargs (call);
 
-  if (call == error_mark_node)
-    return;
+  if (call == error_mark_node || processing_template_decl)
+    {
+      *initp = NULL_TREE;
+      return;
+    }
 
   gcc_assert (TREE_CODE (call) == CALL_EXPR);
 
@@ -2662,7 +2665,7 @@ stabilize_init (tree init, tree *initp)
 
   *initp = NULL_TREE;
 
-  if (t == error_mark_node)
+  if (t == error_mark_node || processing_template_decl)
     return true;
 
   if (TREE_CODE (t) == INIT_EXPR
--- gcc/testsuite/g++.dg/template/new8.C.jj	2007-12-05 18:02:04.000000000 +0100
+++ gcc/testsuite/g++.dg/template/new8.C	2007-12-05 18:01:30.000000000 +0100
@@ -0,0 +1,29 @@
+// PR c++/34336
+// { dg-do compile }
+
+struct A;
+
+template <class T>
+struct S
+{
+  T *m;
+  T &operator* () { return *m; }
+};
+
+struct B
+{
+  B (const A &);
+};
+
+template <class T>
+struct C
+{
+  C ();
+  S<A> c;
+};
+
+template <class T>
+C<T>::C ()
+{
+  B *b = new B (*c);
+}
-------------- next part --------------
2007-12-05  Jakub Jelinek  <jakub@redhat.com>

	PR c++/34336
	* init.c (build_new_1): Don't call stabilize_call or stabilize_init
	if processing_template_decl.

	* g++.dg/template/new8.C: New test.

--- gcc/cp/init.c.jj	2007-11-23 20:33:49.000000000 +0100
+++ gcc/cp/init.c	2007-12-05 20:14:59.000000000 +0100
@@ -1889,7 +1889,7 @@ build_new_1 (tree placement, tree type, 
 
   /* Preevaluate the placement args so that we don't reevaluate them for a
      placement delete.  */
-  if (placement_allocation_fn_p)
+  if (placement_allocation_fn_p && !processing_template_decl)
     {
       tree inits;
       stabilize_call (alloc_call, &inits);
@@ -2000,7 +2000,10 @@ build_new_1 (tree placement, tree type, 
 						     complete_ctor_identifier,
 						     init, elt_type,
 						     LOOKUP_NORMAL);
-	      stable = stabilize_init (init_expr, &init_preeval_expr);
+	      if (processing_template_decl)
+		stable = true;
+	      else
+		stable = stabilize_init (init_expr, &init_preeval_expr);
 	    }
 	  else
 	    {
@@ -2015,7 +2018,10 @@ build_new_1 (tree placement, tree type, 
 			    || TREE_TYPE (init) != NULL_TREE);
 
 	      init_expr = build_modify_expr (init_expr, INIT_EXPR, init);
-	      stable = stabilize_init (init_expr, &init_preeval_expr);
+	      if (processing_template_decl)
+		stable = true;
+	      else
+		stable = stabilize_init (init_expr, &init_preeval_expr);
 	    }
 	}
 
--- gcc/testsuite/g++.dg/template/new8.C.jj	2007-12-05 18:02:04.000000000 +0100
+++ gcc/testsuite/g++.dg/template/new8.C	2007-12-05 18:01:30.000000000 +0100
@@ -0,0 +1,29 @@
+// PR c++/34336
+// { dg-do compile }
+
+struct A;
+
+template <class T>
+struct S
+{
+  T *m;
+  T &operator* () { return *m; }
+};
+
+struct B
+{
+  B (const A &);
+};
+
+template <class T>
+struct C
+{
+  C ();
+  S<A> c;
+};
+
+template <class T>
+C<T>::C ()
+{
+  B *b = new B (*c);
+}


More information about the Gcc-patches mailing list