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]

Re: C++ PATCH for c++/89852 - ICE with C++11 functional cast with { }


On 3/29/19 5:37 PM, Marek Polacek wrote:
On Fri, Mar 29, 2019 at 05:29:27PM -0400, Jason Merrill wrote:
On 3/29/19 4:25 PM, Marek Polacek wrote:
On Thu, Mar 28, 2019 at 02:55:55PM -0400, Jason Merrill wrote:
On 3/27/19 5:45 PM, Marek Polacek wrote:
Here we have a non-dependent constructor in a template:

     { VIEW_CONVERT_EXPR<const A>(j) }

In digest_init we call massage_init_elt, which calls digest_init_r on the
element.  We convert the element, but we're in a template, so
perform_implicit_conversion added an IMPLICIT_CONV_EXPR around it.  And then
massage_init_elt calls maybe_constant_init on the element and the usual sadness
ensues.

Only after fold_non_dependent_expr.  Perhaps we want a
fold_non_dependent_init?

Yeah, I recall we talked about adding fold_non_dependent_init a year ago.

Using it here works -- in a template, we won't call maybe_constant_*, so
there's no crash.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2019-03-29  Marek Polacek  <polacek@redhat.com>

	PR c++/89852 - ICE with C++11 functional cast with { }.
	* constexpr.c (fold_non_dependent_expr_template): New static function
	broken out of...
	(fold_non_dependent_expr): ...here.
	(fold_non_dependent_init): New function.
	* cp-tree.h (fold_non_dependent_init): Declare.
	* typeck2.c (massage_init_elt): Call fold_non_dependent_init instead
	of fold_non_dependent_expr.  Don't call maybe_constant_init.

@@ -5604,51 +5656,29 @@ fold_non_dependent_expr (tree t,
     if (t == NULL_TREE)
       return NULL_TREE;
+  if (processing_template_decl)
+    return fold_non_dependent_expr_template (t, complain,
+					     manifestly_const_eval);
+  return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
+}
+tree
+fold_non_dependent_init (tree t,
+			 tsubst_flags_t complain /*=tf_warning_or_error*/,
+			 bool manifestly_const_eval /*=false*/)
+{
+  if (t == NULL_TREE)
+    return NULL_TREE;
+  if (processing_template_decl)
+    return fold_non_dependent_expr_template (t, complain,
+					     manifestly_const_eval);

Don't we still need the maybe_constant_init TARGET_EXPR stripping behavior
in a template?

It would seem that we don't need it, since nothing broke.  But this patch
includes the stripping.

Bootstrap/regtest running on x86_64-linux, ok for trunk?

2019-03-29  Marek Polacek  <polacek@redhat.com>

	PR c++/89852 - ICE with C++11 functional cast with { }.
	* constexpr.c (fold_non_dependent_expr_template): New static function
	broken out of...
	(fold_non_dependent_expr): ...here.
	(fold_non_dependent_init): New function.
	* cp-tree.h (fold_non_dependent_init): Declare.
	* typeck2.c (massage_init_elt): Call fold_non_dependent_init instead
	of fold_non_dependent_expr.  Don't call maybe_constant_init.

OK.

	* g++.dg/cpp0x/initlist115.C: New test.

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index daf34e10784..53854a8acd4 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -5581,6 +5581,58 @@ clear_cv_and_fold_caches (void)
    clear_fold_cache ();
  }
+/* Internal function handling expressions in templates for
+   fold_non_dependent_expr and fold_non_dependent_init.
+
+   If we're in a template, but T isn't value dependent, simplify
+   it.  We're supposed to treat:
+
+     template <typename T> void f(T[1 + 1]);
+     template <typename T> void f(T[2]);
+
+   as two declarations of the same function, for example.  */
+
+static tree
+fold_non_dependent_expr_template (tree t, tsubst_flags_t complain,
+				  bool manifestly_const_eval)
+{
+  gcc_assert (processing_template_decl);
+
+  if (is_nondependent_constant_expression (t))
+    {
+      processing_template_decl_sentinel s;
+      t = instantiate_non_dependent_expr_internal (t, complain);
+
+      if (type_unknown_p (t) || BRACE_ENCLOSED_INITIALIZER_P (t))
+	{
+	  if (TREE_OVERFLOW_P (t))
+	    {
+	      t = build_nop (TREE_TYPE (t), t);
+	      TREE_CONSTANT (t) = false;
+	    }
+	  return t;
+	}
+
+      tree r = cxx_eval_outermost_constant_expr (t, true, true,
+						 manifestly_const_eval,
+						 NULL_TREE);
+      /* cp_tree_equal looks through NOPs, so allow them.  */
+      gcc_checking_assert (r == t
+			   || CONVERT_EXPR_P (t)
+			   || TREE_CODE (t) == VIEW_CONVERT_EXPR
+			   || (TREE_CONSTANT (t) && !TREE_CONSTANT (r))
+			   || !cp_tree_equal (r, t));
+      return r;
+    }
+  else if (TREE_OVERFLOW_P (t))
+    {
+      t = build_nop (TREE_TYPE (t), t);
+      TREE_CONSTANT (t) = false;
+    }
+
+  return t;
+}
+
  /* Like maybe_constant_value but first fully instantiate the argument.
Note: this is equivalent to instantiate_non_dependent_expr_sfinae
@@ -5604,51 +5656,39 @@ fold_non_dependent_expr (tree t,
    if (t == NULL_TREE)
      return NULL_TREE;
- /* If we're in a template, but T isn't value dependent, simplify
-     it.  We're supposed to treat:
+  if (processing_template_decl)
+    return fold_non_dependent_expr_template (t, complain,
+					     manifestly_const_eval);
- template <typename T> void f(T[1 + 1]);
-       template <typename T> void f(T[2]);
+  return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
+}
- as two declarations of the same function, for example. */
-  if (processing_template_decl)
-    {
-      if (is_nondependent_constant_expression (t))
-	{
-	  processing_template_decl_sentinel s;
-	  t = instantiate_non_dependent_expr_internal (t, complain);
- if (type_unknown_p (t)
-	      || BRACE_ENCLOSED_INITIALIZER_P (t))
-	    {
-	      if (TREE_OVERFLOW_P (t))
-		{
-		  t = build_nop (TREE_TYPE (t), t);
-		  TREE_CONSTANT (t) = false;
-		}
-	      return t;
-	    }
+/* Like maybe_constant_init but first fully instantiate the argument.  */
- tree r = cxx_eval_outermost_constant_expr (t, true, true,
-						     manifestly_const_eval,
-						     NULL_TREE);
-	  /* cp_tree_equal looks through NOPs, so allow them.  */
-	  gcc_checking_assert (r == t
-			       || CONVERT_EXPR_P (t)
-			       || TREE_CODE (t) == VIEW_CONVERT_EXPR
-			       || (TREE_CONSTANT (t) && !TREE_CONSTANT (r))
-			       || !cp_tree_equal (r, t));
-	  return r;
-	}
-      else if (TREE_OVERFLOW_P (t))
+tree
+fold_non_dependent_init (tree t,
+			 tsubst_flags_t complain /*=tf_warning_or_error*/,
+			 bool manifestly_const_eval /*=false*/)
+{
+  if (t == NULL_TREE)
+    return NULL_TREE;
+
+  if (processing_template_decl)
+    {
+      t = fold_non_dependent_expr_template (t, complain,
+					    manifestly_const_eval);
+      /* maybe_constant_init does this stripping, so do it here too.  */
+      if (TREE_CODE (t) == TARGET_EXPR)
  	{
-	  t = build_nop (TREE_TYPE (t), t);
-	  TREE_CONSTANT (t) = false;
+	  tree init = TARGET_EXPR_INITIAL (t);
+	  if (TREE_CODE (init) == CONSTRUCTOR)
+	    t = init;
  	}
        return t;
      }
- return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
+  return maybe_constant_init (t, NULL_TREE, manifestly_const_eval);
  }
/* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index fd612b0dbb1..31218a79be7 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -7708,6 +7708,9 @@ extern tree maybe_constant_init			(tree, tree = NULL_TREE, bool = false);
  extern tree fold_non_dependent_expr		(tree,
  						 tsubst_flags_t = tf_warning_or_error,
  						 bool = false);
+extern tree fold_non_dependent_init		(tree,
+						 tsubst_flags_t = tf_warning_or_error,
+						 bool = false);
  extern tree fold_simple				(tree);
  extern bool is_sub_constant_expr                (tree);
  extern bool reduced_constant_expression_p       (tree);
diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index 7f242ba93da..fa98b1cb8b5 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -1346,8 +1346,7 @@ massage_init_elt (tree type, tree init, int nested, int flags,
      init = TARGET_EXPR_INITIAL (init);
    /* When we defer constant folding within a statement, we may want to
       defer this folding as well.  */
-  tree t = fold_non_dependent_expr (init, complain);
-  t = maybe_constant_init (t);
+  tree t = fold_non_dependent_init (init, complain);
    if (TREE_CONSTANT (t))
      init = t;
    return init;
diff --git gcc/testsuite/g++.dg/cpp0x/initlist115.C gcc/testsuite/g++.dg/cpp0x/initlist115.C
new file mode 100644
index 00000000000..ee4b6d4a870
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/initlist115.C
@@ -0,0 +1,18 @@
+// PR c++/89852
+// { dg-do compile { target c++11 } }
+
+struct A {
+  int b;
+};
+
+struct B {
+  A g;
+};
+
+const auto j = A{};
+
+template <typename>
+void k()
+{
+  B{j};
+}



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