PR c++/86219 - ICE with erroneous initializer in template.
authorJason Merrill <jason@redhat.com>
Fri, 22 Jun 2018 21:57:07 +0000 (17:57 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 22 Jun 2018 21:57:07 +0000 (17:57 -0400)
* constexpr.c (fold_non_dependent_expr): Add complain parm.
* call.c, expr.c, init.c, pt.c, semantics.c, typeck.c, typeck2.c:
Pass it.
* call.c (build_cxx_call): Don't mess with builtins in a template.
* typeck2.c (store_init_value): If fold_non_dependent_expr didn't
produce a constant value, go back to the uninstantiated form.

From-SVN: r261972

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/expr.c
gcc/cp/init.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/template/conv15.C [new file with mode: 0644]

index 8c7b19b1754e41c4cbd03a513d06c405bc1a8ad8..ae2fd618c198e562db41cd7f04331ad4519405f2 100644 (file)
@@ -1,5 +1,13 @@
 2018-06-22  Jason Merrill  <jason@redhat.com>
 
+       PR c++/86219 - ICE with erroneous initializer in template.
+       * constexpr.c (fold_non_dependent_expr): Add complain parm.
+       * call.c, expr.c, init.c, pt.c, semantics.c, typeck.c, typeck2.c:
+       Pass it.
+       * call.c (build_cxx_call): Don't mess with builtins in a template.
+       * typeck2.c (store_init_value): If fold_non_dependent_expr didn't
+       produce a constant value, go back to the uninstantiated form.
+
        Avoid taking the address of something just because it's in parens.
        * constexpr.c (same_type_ignoring_tlq_and_bounds_p): New.
        (cxx_fold_indirect_ref): Use it.
index e417590e97d5b8954bb04dd6ae5f2133d4b6ddf1..aa0e696972ad04620d4b2fb3768c8b757d0ef537 100644 (file)
@@ -544,7 +544,7 @@ null_ptr_cst_p (tree t)
     }
   else if (CP_INTEGRAL_TYPE_P (type))
     {
-      t = fold_non_dependent_expr (t);
+      t = fold_non_dependent_expr (t, tf_none);
       STRIP_NOPS (t);
       if (integer_zerop (t) && !TREE_OVERFLOW (t))
        return true;
@@ -8796,6 +8796,7 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
 
   /* Check that arguments to builtin functions match the expectations.  */
   if (fndecl
+      && !processing_template_decl
       && DECL_BUILT_IN (fndecl)
       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
     {
@@ -8804,7 +8805,7 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
       /* We need to take care that values to BUILT_IN_NORMAL
          are reduced.  */
       for (i = 0; i < nargs; i++)
-       argarray[i] = fold_non_dependent_expr (argarray[i]);
+       argarray[i] = maybe_constant_value (argarray[i]);
 
       if (!check_builtin_function_arguments (EXPR_LOCATION (fn), vNULL, fndecl,
                                             nargs, argarray))
index dea2a4e57b3c55b6384cc6e15c311642df38be89..365296d6e3be936ac9c08bb885aad78c4cefae4a 100644 (file)
@@ -5179,12 +5179,20 @@ clear_cv_and_fold_caches (void)
 /* Like maybe_constant_value but first fully instantiate the argument.
 
    Note: this is equivalent to instantiate_non_dependent_expr_sfinae
-   (t, tf_none) followed by maybe_constant_value but is more efficient,
-   because calls instantiation_dependent_expression_p and
-   potential_constant_expression at most once.  */
+   (t, complain) followed by maybe_constant_value but is more efficient,
+   because it calls instantiation_dependent_expression_p and
+   potential_constant_expression at most once.
+
+   Callers should generally pass their active complain, or if they are in a
+   non-template, diagnosing context, they can use the default of
+   tf_warning_or_error.  Callers that might be within a template context, don't
+   have a complain parameter, and aren't going to remember the result for long
+   (e.g. null_ptr_cst_p), can pass tf_none and deal with error_mark_node
+   appropriately.  */
 
 tree
-fold_non_dependent_expr (tree t)
+fold_non_dependent_expr (tree t,
+                        tsubst_flags_t complain /* = tf_warning_or_error */)
 {
   if (t == NULL_TREE)
     return NULL_TREE;
@@ -5201,7 +5209,7 @@ fold_non_dependent_expr (tree t)
       if (is_nondependent_constant_expression (t))
        {
          processing_template_decl_sentinel s;
-         t = instantiate_non_dependent_expr_internal (t, tf_none);
+         t = instantiate_non_dependent_expr_internal (t, complain);
 
          if (type_unknown_p (t)
              || BRACE_ENCLOSED_INITIALIZER_P (t))
index f16f00c40ded1fc07804527edbdbe37560d5c0e3..284b44343d39369c0a56aa241af2635377619630 100644 (file)
@@ -7534,7 +7534,7 @@ extern tree cxx_constant_value                    (tree, tree = NULL_TREE);
 extern tree cxx_constant_init                  (tree, tree = NULL_TREE);
 extern tree maybe_constant_value               (tree, tree = NULL_TREE);
 extern tree maybe_constant_init                        (tree, tree = NULL_TREE);
-extern tree fold_non_dependent_expr            (tree);
+extern tree fold_non_dependent_expr            (tree, tsubst_flags_t = tf_warning_or_error);
 extern tree fold_simple                                (tree);
 extern bool is_sub_constant_expr                (tree);
 extern bool reduced_constant_expression_p       (tree);
index 133a01b8a51443c417833ef029f293fbcb4af9b7..93477bcd12f1409ba8c85ddf86e064d340654ee9 100644 (file)
@@ -353,7 +353,13 @@ fold_for_warn (tree x)
   /* It's not generally safe to fully fold inside of a template, so
      call fold_non_dependent_expr instead.  */
   if (processing_template_decl)
-    return fold_non_dependent_expr (x);
+    {
+      tree f = fold_non_dependent_expr (x, tf_none);
+      if (f == error_mark_node)
+       return x;
+      else
+       return f;
+    }
 
   return c_fully_fold (x, /*for_init*/false, /*maybe_constp*/NULL);
 }
index 810a776a3c8a2a3df712dce7ab36db77b27bcaf6..76ce0b829dd2e36c4b1c918e8342cac988c7ae90 100644 (file)
@@ -2931,7 +2931,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
 
   /* Lots of logic below depends on whether we have a constant number of
      elements, so go ahead and fold it now.  */
-  const_tree cst_outer_nelts = fold_non_dependent_expr (outer_nelts);
+  const_tree cst_outer_nelts = fold_non_dependent_expr (outer_nelts, complain);
 
   /* If our base type is an array, then make sure we know how many elements
      it has.  */
@@ -3731,7 +3731,7 @@ build_new (vec<tree, va_gc> **placement, tree type, tree nelts,
       /* Try to determine the constant value only for the purposes
         of the diagnostic below but continue to use the original
         value and handle const folding later.  */
-      const_tree cst_nelts = fold_non_dependent_expr (nelts);
+      const_tree cst_nelts = fold_non_dependent_expr (nelts, complain);
 
       /* The expression in a noptr-new-declarator is erroneous if it's of
         non-class type and its value before converting to std::size_t is
index 69e9479302eae87fc9c2ee9a2faa3a0ac19f147c..e1e2f0152c112c6025b167d5afb2a464aea77392 100644 (file)
@@ -16863,7 +16863,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
        /* Don't instantiate the THEN_CLAUSE. */;
       else
        {
-         bool inhibit = integer_zerop (fold_non_dependent_expr (tmp));
+         tree folded = fold_non_dependent_expr (tmp, complain);
+         bool inhibit = integer_zerop (folded);
          if (inhibit)
            ++c_inhibit_evaluation_warnings;
          RECUR (THEN_CLAUSE (t));
@@ -16876,7 +16877,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
        /* Don't instantiate the ELSE_CLAUSE. */;
       else if (ELSE_CLAUSE (t))
        {
-         bool inhibit = integer_nonzerop (fold_non_dependent_expr (tmp));
+         tree folded = fold_non_dependent_expr (tmp, complain);
+         bool inhibit = integer_nonzerop (folded);
          begin_else_clause (stmt);
          if (inhibit)
            ++c_inhibit_evaluation_warnings;
@@ -18517,7 +18519,7 @@ tsubst_copy_and_build (tree t,
       {
        tree cond = RECUR (TREE_OPERAND (t, 0));
        cond = mark_rvalue_use (cond);
-       tree folded_cond = fold_non_dependent_expr (cond);
+       tree folded_cond = fold_non_dependent_expr (cond, complain);
        tree exp1, exp2;
 
        if (TREE_CODE (folded_cond) == INTEGER_CST)
@@ -22082,7 +22084,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
         corresponding parameter is type-dependent.  Make any necessary
         adjustments based on whether arg is a reference.  */
       if (CONSTANT_CLASS_P (arg))
-       parm = fold_non_dependent_expr (parm);
+       parm = fold_non_dependent_expr (parm, complain);
       else if (REFERENCE_REF_P (arg))
        {
          tree sub = TREE_OPERAND (arg, 0);
@@ -25849,7 +25851,7 @@ build_non_dependent_expr (tree expr)
       /* Don't do this during concept expansion either and for
          the same reason.  */
       && !expanding_concept ())
-    fold_non_dependent_expr (expr);
+    fold_non_dependent_expr (expr, tf_none);
 
   STRIP_ANY_LOCATION_WRAPPER (expr);
 
index da75f30885f8c71af76e72557af54c8185285de4..c779137da456f07ad5cdd6498b098b6f9fae9f62 100644 (file)
@@ -8676,7 +8676,7 @@ finish_static_assert (tree condition, tree message, location_t location,
   /* Fold the expression and convert it to a boolean value. */
   condition = perform_implicit_conversion_flags (boolean_type_node, condition,
                                                 complain, LOOKUP_NORMAL);
-  condition = fold_non_dependent_expr (condition);
+  condition = fold_non_dependent_expr (condition, complain);
 
   if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
     /* Do nothing; the condition is satisfied. */
index 936de9fe5c6cf890577e0a07a5b2e499b42d84cd..3a4f1cdf479284ed6dc72adf4a8a1a489d666a89 100644 (file)
@@ -4163,7 +4163,7 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain)
       || TREE_NO_WARNING (op))
     return;
 
-  tree cop = fold_non_dependent_expr (op);
+  tree cop = fold_non_dependent_expr (op, complain);
 
   if (TREE_CODE (cop) == ADDR_EXPR
       && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0))
@@ -4480,7 +4480,7 @@ cp_build_binary_op (location_t location,
              || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
        {
          enum tree_code tcode0 = code0, tcode1 = code1;
-         tree cop1 = fold_non_dependent_expr (op1);
+         tree cop1 = fold_non_dependent_expr (op1, complain);
          doing_div_or_mod = true;
          warn_for_div_by_zero (location, cop1);
 
@@ -4519,7 +4519,7 @@ cp_build_binary_op (location_t location,
     case TRUNC_MOD_EXPR:
     case FLOOR_MOD_EXPR:
       {
-       tree cop1 = fold_non_dependent_expr (op1);
+       tree cop1 = fold_non_dependent_expr (op1, complain);
        doing_div_or_mod = true;
        warn_for_div_by_zero (location, cop1);
       }
@@ -4614,7 +4614,7 @@ cp_build_binary_op (location_t location,
        }
       else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        {
-         tree const_op1 = fold_non_dependent_expr (op1);
+         tree const_op1 = fold_non_dependent_expr (op1, complain);
          if (TREE_CODE (const_op1) != INTEGER_CST)
            const_op1 = op1;
          result_type = type0;
@@ -4660,10 +4660,10 @@ cp_build_binary_op (location_t location,
        }
       else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        {
-         tree const_op0 = fold_non_dependent_expr (op0);
+         tree const_op0 = fold_non_dependent_expr (op0, complain);
          if (TREE_CODE (const_op0) != INTEGER_CST)
            const_op0 = op0;
-         tree const_op1 = fold_non_dependent_expr (op1);
+         tree const_op1 = fold_non_dependent_expr (op1, complain);
          if (TREE_CODE (const_op1) != INTEGER_CST)
            const_op1 = op1;
          result_type = type0;
@@ -5370,8 +5370,8 @@ cp_build_binary_op (location_t location,
       /* OP0 and/or OP1 might have side-effects.  */
       op0 = cp_save_expr (op0);
       op1 = cp_save_expr (op1);
-      op0 = fold_non_dependent_expr (op0);
-      op1 = fold_non_dependent_expr (op1);
+      op0 = fold_non_dependent_expr (op0, complain);
+      op1 = fold_non_dependent_expr (op1, complain);
       if (doing_div_or_mod
          && sanitize_flags_p (SANITIZE_DIVIDE | SANITIZE_FLOAT_DIVIDE))
        {
index ca87b438bd3b551ab12642fb5131cbf649cd42f2..43e236de41c1d7deaa14bc13571bb52d35bad71d 100644 (file)
@@ -822,6 +822,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
   if (decl_maybe_constant_var_p (decl) || TREE_STATIC (decl))
     {
       bool const_init;
+      tree oldval = value;
       value = fold_non_dependent_expr (value);
       if (DECL_DECLARED_CONSTEXPR_P (decl)
          || (DECL_IN_AGGR_P (decl)
@@ -847,6 +848,8 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
       /* FIXME setting TREE_CONSTANT on refs breaks the back end.  */
       if (!TYPE_REF_P (type))
        TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
+      if (!const_init)
+       value = oldval;
     }
   value = cp_fully_fold (value);
 
@@ -899,7 +902,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
       return ok;
     }
 
-  init = fold_non_dependent_expr (init);
+  init = fold_non_dependent_expr (init, complain);
 
   if (TREE_CODE (type) == INTEGER_TYPE
       && TREE_CODE (ftype) == REAL_TYPE)
@@ -1254,7 +1257,7 @@ massage_init_elt (tree type, tree init, int nested, tsubst_flags_t complain)
     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);
+  tree t = fold_non_dependent_expr (init, complain);
   t = maybe_constant_init (t);
   if (TREE_CONSTANT (t))
     init = t;
diff --git a/gcc/testsuite/g++.dg/template/conv15.C b/gcc/testsuite/g++.dg/template/conv15.C
new file mode 100644 (file)
index 0000000..2f61c11
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/86219
+
+template <int a> struct t;
+template <int a>
+void f ()
+{
+   const int b = "";           // { dg-error "conversion" }
+   t<b>::c;                    // { dg-error "constant" }
+   // { dg-prune-output "template argument 1 is invalid" }
+}