Add immediate potential_constant_expression variants.
authorJason Merrill <jason@redhat.com>
Tue, 29 Aug 2017 19:40:14 +0000 (15:40 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 29 Aug 2017 19:40:14 +0000 (15:40 -0400)
* constexpr.c (potential_constant_expression_1): Add "now" parm.
(is_constant_expression, require_constant_expression): New.
(is_static_init_expression, is_nondependent_constant_expression)
(is_nondependent_static_init_expression): Drop "potential".
* except.c (build_must_not_throw_expr): Do type conversion on
value-dependent argument.
* pt.c, semantics.c, typeck2.c: Use variants without "potential".

From-SVN: r251423

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/except.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/cpp0x/constexpr-conv2.C [new file with mode: 0644]

index 308e13a..f91f6be 100644 (file)
@@ -1,5 +1,13 @@
 2017-08-29  Jason Merrill  <jason@redhat.com>
 
+       * constexpr.c (potential_constant_expression_1): Add "now" parm.
+       (is_constant_expression, require_constant_expression): New.
+       (is_static_init_expression, is_nondependent_constant_expression)
+       (is_nondependent_static_init_expression): Drop "potential".
+       * except.c (build_must_not_throw_expr): Do type conversion on
+       value-dependent argument.
+       * pt.c, semantics.c, typeck2.c: Use variants without "potential".
+
        Instantiate default arguments/member initializers once.
        * init.c (get_nsdmi): Remember NSDMI instantiations.
        * parser.c (inject_this_parameter): Be more picky about
index 29ba2c3..8cfc5a4 100644 (file)
@@ -1181,7 +1181,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
       return t;
     }
 
-  if (!potential_constant_expression (new_call))
+  if (!is_constant_expression (new_call))
     {
       if (!*non_constant_p && !ctx->quiet)
        error ("%q+E is not a constant expression", new_call);
@@ -4861,7 +4861,7 @@ maybe_constant_value (tree t, tree decl)
 {
   tree r;
 
-  if (!potential_nondependent_constant_expression (t))
+  if (!is_nondependent_constant_expression (t))
     {
       if (TREE_OVERFLOW_P (t))
        {
@@ -4929,7 +4929,7 @@ fold_non_dependent_expr (tree t)
      as two declarations of the same function, for example.  */
   if (processing_template_decl)
     {
-      if (potential_nondependent_constant_expression (t))
+      if (is_nondependent_constant_expression (t))
        {
          processing_template_decl_sentinel s;
          t = instantiate_non_dependent_expr_internal (t, tf_none);
@@ -4982,7 +4982,7 @@ maybe_constant_init (tree t, tree decl)
     t = TREE_OPERAND (t, 1);
   if (TREE_CODE (t) == TARGET_EXPR)
     t = TARGET_EXPR_INITIAL (t);
-  if (!potential_nondependent_static_init_expression (t))
+  if (!is_nondependent_static_init_expression (t))
     /* Don't try to evaluate it.  */;
   else if (CONSTANT_CLASS_P (t))
     /* No evaluation needed.  */;
@@ -5025,7 +5025,9 @@ check_automatic_or_tls (tree ref)
 
 /* Return true if T denotes a potentially constant expression.  Issue
    diagnostic as appropriate under control of FLAGS.  If WANT_RVAL is true,
-   an lvalue-rvalue conversion is implied.
+   an lvalue-rvalue conversion is implied.  If NOW is true, we want to
+   consider the expression in the current context, independent of constexpr
+   substitution.
 
    C++0x [expr.const] used to say
 
@@ -5041,10 +5043,12 @@ check_automatic_or_tls (tree ref)
       not evaluated are not considered.   */
 
 static bool
-potential_constant_expression_1 (tree t, bool want_rval, bool strict,
+potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
                                 tsubst_flags_t flags)
 {
-#define RECUR(T,RV) potential_constant_expression_1 ((T), (RV), strict, flags)
+#define RECUR(T,RV) \
+  potential_constant_expression_1 ((T), (RV), strict, now, flags)
+
   enum { any = false, rval = true };
   int i;
   tree tmp;
@@ -5087,7 +5091,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
     case USERDEF_LITERAL:
       /* We can see a FIELD_DECL in a pointer-to-member expression.  */
     case FIELD_DECL:
-    case PARM_DECL:
     case RESULT_DECL:
     case USING_DECL:
     case USING_STMT:
@@ -5098,6 +5101,15 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
     case STATIC_ASSERT:
       return true;
 
+    case PARM_DECL:
+      if (now)
+       {
+         if (flags & tf_error)
+           error ("%qE is not a constant expression", t);
+         return false;
+       }
+      return true;
+
     case AGGR_INIT_EXPR:
     case CALL_EXPR:
       /* -- an invocation of a function other than a constexpr function
@@ -5173,7 +5185,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
                    tree x = get_nth_callarg (t, 0);
                    if (is_this_parameter (x))
                      return true;
-                   else if (!RECUR (x, rval))
+                   /* Don't require an immediately constant value, as
+                      constexpr substitution might not use the value.  */
+                   bool sub_now = false;
+                   if (!potential_constant_expression_1 (x, rval, strict,
+                                                         sub_now, flags))
                      return false;
                    i = 1;
                  }
@@ -5203,7 +5219,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
               REFERENCE_TYPE and we might not even know if the parameter
               is a reference, so accept lvalue constants too.  */
            bool rv = processing_template_decl ? any : rval;
-           if (!RECUR (x, rv))
+           /* Don't require an immediately constant value, as constexpr
+              substitution might not use the value of the argument.  */
+           bool sub_now = false;
+           if (!potential_constant_expression_1 (x, rv, strict,
+                                                 sub_now, flags))
              return false;
           }
         return true;
@@ -5759,7 +5779,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
        return RECUR (TREE_OPERAND (t, 1), want_rval);
       for (i = 1; i < 3; ++i)
        if (potential_constant_expression_1 (TREE_OPERAND (t, i),
-                                            want_rval, strict, tf_none))
+                                            want_rval, strict, now, tf_none))
          return true;
       if (flags & tf_error)
        error_at (loc, "expression %qE is not a constant expression", t);
@@ -5816,13 +5836,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
 bool
 potential_constant_expression (tree t)
 {
-  return potential_constant_expression_1 (t, false, true, tf_none);
-}
-
-bool
-potential_static_init_expression (tree t)
-{
-  return potential_constant_expression_1 (t, false, false, tf_none);
+  return potential_constant_expression_1 (t, false, true, false, tf_none);
 }
 
 /* As above, but require a constant rvalue.  */
@@ -5830,7 +5844,7 @@ potential_static_init_expression (tree t)
 bool
 potential_rvalue_constant_expression (tree t)
 {
-  return potential_constant_expression_1 (t, true, true, tf_none);
+  return potential_constant_expression_1 (t, true, true, false, tf_none);
 }
 
 /* Like above, but complain about non-constant expressions.  */
@@ -5838,7 +5852,7 @@ potential_rvalue_constant_expression (tree t)
 bool
 require_potential_constant_expression (tree t)
 {
-  return potential_constant_expression_1 (t, false, true, tf_warning_or_error);
+  return potential_constant_expression_1 (t, false, true, false, tf_warning_or_error);
 }
 
 /* Cross product of the above.  */
@@ -5846,7 +5860,38 @@ require_potential_constant_expression (tree t)
 bool
 require_potential_rvalue_constant_expression (tree t)
 {
-  return potential_constant_expression_1 (t, true, true, tf_warning_or_error);
+  return potential_constant_expression_1 (t, true, true, false, tf_warning_or_error);
+}
+
+/* Like potential_constant_expression, but don't consider possible constexpr
+   substitution of the current function.  That is, PARM_DECL qualifies under
+   potential_constant_expression, but not here.
+
+   This is basically what you can check when any actual constant values might
+   be value-dependent.  */
+
+bool
+is_constant_expression (tree t)
+{
+  return potential_constant_expression_1 (t, false, true, true, tf_none);
+}
+
+/* Like above, but complain about non-constant expressions.  */
+
+bool
+require_constant_expression (tree t)
+{
+  return potential_constant_expression_1 (t, false, true, true,
+                                         tf_warning_or_error);
+}
+
+/* Like is_constant_expression, but allow const variables that are not allowed
+   under constexpr rules.  */
+
+bool
+is_static_init_expression (tree t)
+{
+  return potential_constant_expression_1 (t, false, false, true, tf_none);
 }
 
 /* Returns true if T is a potential constant expression that is not
@@ -5854,11 +5899,11 @@ require_potential_rvalue_constant_expression (tree t)
    in a template.  */
 
 bool
-potential_nondependent_constant_expression (tree t)
+is_nondependent_constant_expression (tree t)
 {
   return (!type_unknown_p (t)
          && !BRACE_ENCLOSED_INITIALIZER_P (t)
-         && potential_constant_expression (t)
+         && is_constant_expression (t)
          && !instantiation_dependent_expression_p (t));
 }
 
@@ -5866,11 +5911,11 @@ potential_nondependent_constant_expression (tree t)
    instantiation-dependent.  */
 
 bool
-potential_nondependent_static_init_expression (tree t)
+is_nondependent_static_init_expression (tree t)
 {
   return (!type_unknown_p (t)
          && !BRACE_ENCLOSED_INITIALIZER_P (t)
-         && potential_static_init_expression (t)
+         && is_static_init_expression (t)
          && !instantiation_dependent_expression_p (t));
 }
 
index 17e7aad..f0eafb3 100644 (file)
@@ -7325,11 +7325,13 @@ extern bool is_valid_constexpr_fn               (tree, bool);
 extern bool check_constexpr_ctor_body           (tree, tree, bool);
 extern tree ensure_literal_type_for_constexpr_object (tree);
 extern bool potential_constant_expression       (tree);
-extern bool potential_nondependent_constant_expression (tree);
-extern bool potential_nondependent_static_init_expression (tree);
-extern bool potential_static_init_expression    (tree);
+extern bool is_constant_expression (tree);
+extern bool is_nondependent_constant_expression (tree);
+extern bool is_nondependent_static_init_expression (tree);
+extern bool is_static_init_expression    (tree);
 extern bool potential_rvalue_constant_expression (tree);
 extern bool require_potential_constant_expression (tree);
+extern bool require_constant_expression (tree);
 extern bool require_potential_rvalue_constant_expression (tree);
 extern tree cxx_constant_value                 (tree, tree = NULL_TREE);
 extern tree maybe_constant_value               (tree, tree = NULL_TREE);
index b25b91b..2ee7e97 100644 (file)
@@ -261,13 +261,19 @@ build_must_not_throw_expr (tree body, tree cond)
   if (!flag_exceptions)
     return body;
 
-  if (cond && !value_dependent_expression_p (cond))
+  if (!cond)
+    /* OK, unconditional.  */;
+  else
     {
-      cond = perform_implicit_conversion_flags (boolean_type_node, cond,
-                                               tf_warning_or_error,
-                                               LOOKUP_NORMAL);
-      cond = instantiate_non_dependent_expr (cond);
-      cond = cxx_constant_value (cond);
+      tree conv = NULL_TREE;
+      if (!type_dependent_expression_p (cond))
+       conv = perform_implicit_conversion_flags (boolean_type_node, cond,
+                                                 tf_warning_or_error,
+                                                 LOOKUP_NORMAL);
+      if (tree inst = instantiate_non_dependent_or_null (conv))
+       cond = cxx_constant_value (inst);
+      else
+       require_constant_expression (cond);
       if (integer_zerop (cond))
        return body;
       else if (integer_onep (cond))
index eec89db..e34fe21 100644 (file)
@@ -5827,7 +5827,7 @@ instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
 
      as two declarations of the same function, for example.  */
   if (processing_template_decl
-      && potential_nondependent_constant_expression (expr))
+      && is_nondependent_constant_expression (expr))
     {
       processing_template_decl_sentinel s;
       expr = instantiate_non_dependent_expr_internal (expr, complain);
@@ -5851,7 +5851,7 @@ instantiate_non_dependent_or_null (tree expr)
     return NULL_TREE;
   if (processing_template_decl)
     {
-      if (!potential_nondependent_constant_expression (expr))
+      if (!is_nondependent_constant_expression (expr))
        expr = NULL_TREE;
       else
        {
@@ -6437,15 +6437,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
       && has_value_dependent_address (expr))
     /* If we want the address and it's value-dependent, don't fold.  */;
   else if (processing_template_decl
-          && potential_nondependent_constant_expression (expr))
+          && is_nondependent_constant_expression (expr))
     non_dep = true;
   if (error_operand_p (expr))
     return error_mark_node;
   expr_type = TREE_TYPE (expr);
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    expr = mark_lvalue_use (expr);
-  else
-    expr = mark_rvalue_use (expr);
 
   /* If the argument is non-dependent, perform any conversions in
      non-dependent context as well.  */
@@ -6493,6 +6489,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
        }
     }
 
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    expr = mark_lvalue_use (expr);
+  else
+    expr = mark_rvalue_use (expr);
+
   /* HACK: Due to double coercion, we can get a
      NOP_EXPR<REFERENCE_TYPE>(ADDR_EXPR<POINTER_TYPE> (arg)) here,
      which is the tree that we built on the first call (see
index 14e680f..86ce9ce 100644 (file)
@@ -735,7 +735,7 @@ finish_if_stmt_cond (tree cond, tree if_stmt)
 {
   cond = maybe_convert_cond (cond);
   if (IF_STMT_CONSTEXPR_P (if_stmt)
-      && require_potential_rvalue_constant_expression (cond)
+      && is_constant_expression (cond)
       && !value_dependent_expression_p (cond))
     {
       cond = instantiate_non_dependent_expr (cond);
index 06c079e..e9aca39 100644 (file)
@@ -821,7 +821,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
          || (DECL_IN_AGGR_P (decl) && !DECL_VAR_DECLARED_INLINE_P (decl)))
        {
          /* Diagnose a non-constant initializer for constexpr.  */
-         if (!require_potential_constant_expression (value))
+         if (!require_constant_expression (value))
            value = error_mark_node;
          else
            value = cxx_constant_value (value, decl);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-conv2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-conv2.C
new file mode 100644 (file)
index 0000000..c64fb3d
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+
+template <int I> void f();
+
+struct A { constexpr operator int() { return 24; } };
+
+template <class T> constexpr void g(T t)
+{
+  f<t>();
+}
+
+int main()
+{
+  g(A());
+}