re PR c++/46977 ([C++0x] ICE: SIGSEGV in htab_find_slot_with_hash (hashtab.c:650))
authorJason Merrill <jason@redhat.com>
Fri, 21 Jan 2011 17:38:02 +0000 (12:38 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 21 Jan 2011 17:38:02 +0000 (12:38 -0500)
PR c++/46977
* semantics.c (potential_constant_expression_1): Split out from
potential_constant_expression.  Add want_rval parm.  Handle
template expression forms.  Don't enforce restriction on address
of automatic variable here.  Add a couple of diagnostics that
had been missing.
(require_potential_constant_expression): New entry point.
(build_data_member_initialization, register_constexpr_fundef): Adjust.
(maybe_constant_value): Check potential_constant_expression.
* pt.c (fold_non_dependent_expr_sfinae): Likewise.
* tree.c (build_vec_init_expr): Adjust.

From-SVN: r169096

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

index a28d672..dcf8c49 100644 (file)
@@ -1,3 +1,17 @@
+2011-01-21  Jason Merrill  <jason@redhat.com>
+
+       PR c++/46977
+       * semantics.c (potential_constant_expression_1): Split out from
+       potential_constant_expression.  Add want_rval parm.  Handle
+       template expression forms.  Don't enforce restriction on address
+       of automatic variable here.  Add a couple of diagnostics that
+       had been missing.
+       (require_potential_constant_expression): New entry point.
+       (build_data_member_initialization, register_constexpr_fundef): Adjust.
+       (maybe_constant_value): Check potential_constant_expression.
+       * pt.c (fold_non_dependent_expr_sfinae): Likewise.
+       * tree.c (build_vec_init_expr): Adjust.
+
 2011-01-19  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/47303
index 3d39b55..7500826 100644 (file)
@@ -5245,7 +5245,8 @@ extern tree validate_constexpr_fundecl (tree);
 extern tree register_constexpr_fundef (tree, tree);
 extern bool check_constexpr_ctor_body (tree, tree);
 extern tree ensure_literal_type_for_constexpr_object (tree);
-extern bool potential_constant_expression (tree, tsubst_flags_t);
+extern bool potential_constant_expression (tree);
+extern bool require_potential_constant_expression (tree);
 extern tree cxx_constant_value (tree);
 extern tree maybe_constant_value (tree);
 extern tree maybe_constant_init (tree);
index 01f8cd7..7d39e1c 100644 (file)
@@ -5159,6 +5159,7 @@ fold_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
      as two declarations of the same function, for example.  */
   if (processing_template_decl
       && !type_dependent_expression_p (expr)
+      && potential_constant_expression (expr)
       && !value_dependent_expression_p (expr))
     {
       HOST_WIDE_INT saved_processing_template_decl;
@@ -17964,11 +17965,11 @@ dependent_scope_p (tree scope)
    [temp.dep.constexpr].  EXPRESSION is already known to be a constant
    expression.  */
 
-/* FIXME this predicate is not appropriate for general expressions; the
-   predicates we want instead are "valid constant expression, value
-   dependent or not?", "really constant expression, not value dependent?"
-   and "instantiation-dependent?".  Try to integrate with
-   potential_constant_expression?
+/* Note that this predicate is not appropriate for general expressions;
+   only constant expressions (that satisfy potential_constant_expression)
+   can be tested for value dependence.
+
+   We should really also have a predicate for "instantiation-dependent".
 
    fold_non_dependent_expr: fold if constant and not type-dependent and not value-dependent.
      (what about instantiation-dependent constant-expressions?)
index 285b764..23ff27b 100644 (file)
@@ -5532,7 +5532,7 @@ build_data_member_initialization (tree t, VEC(constructor_elt,gc) **vec)
          gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (member))));
          /* But if the initializer isn't constexpr, leave it in so we
             complain later.  */
-         if (potential_constant_expression (init, tf_none))
+         if (potential_constant_expression (init))
            return true;
        }
     }
@@ -5658,10 +5658,11 @@ register_constexpr_fundef (tree fun, tree body)
       body = unshare_expr (TREE_OPERAND (body, 0));
     }
 
-  if (!potential_constant_expression (body, (DECL_TEMPLATE_INSTANTIATION (fun)
-                                            ? tf_none : tf_error)))
+  if (!potential_constant_expression (body))
     {
       DECL_DECLARED_CONSTEXPR_P (fun) = false;
+      if (!DECL_TEMPLATE_INSTANTIATION (fun))
+       require_potential_constant_expression (body);
       return NULL;
     }
   fundef->body = body;
@@ -7115,8 +7116,7 @@ maybe_constant_value (tree t)
   tree r;
 
   if (type_dependent_expression_p (t)
-      /* FIXME shouldn't check value-dependence first; see comment before
-        value_dependent_expression_p.  */
+      || !potential_constant_expression (t)
       || value_dependent_expression_p (t))
     return t;
 
@@ -7148,6 +7148,8 @@ maybe_constant_init (tree t)
   return t;
 }
 
+#if 0
+/* FIXME see ADDR_EXPR section in potential_constant_expression_1.  */
 /* Return true if the object referred to by REF has automatic or thread
    local storage.  */
 
@@ -7170,6 +7172,7 @@ check_automatic_or_tls (tree ref)
   dk = decl_storage_duration (decl);
   return (dk == dk_auto || dk == dk_thread) ? ck_bad : ck_ok;
 }
+#endif
 
 /* Return true if the DECL designates a builtin function that is
    morally constexpr, in the sense that its parameter types and
@@ -7197,13 +7200,11 @@ morally_constexpr_builtin_function_p (tree decl)
   return t != NULL;
 }
 
-/* Return true if T denotes a constant expression, or potential constant
-   expression if POTENTIAL is true.
-   Issue diagnostic as appropriate under control of flags.  Variables
-   with static storage duration initialized by constant expressions
-   are guaranteed to be statically initialized.
+/* 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.
 
-   C++0x [expr.const]
+   C++0x [expr.const] used to say
 
    6 An expression is a potential constant expression if it is
      a constant expression where all occurences of function
@@ -7216,13 +7217,23 @@ morally_constexpr_builtin_function_p (tree decl)
       logical OR (5.15), and conditional (5.16) operations that are
       not evaluated are not considered.   */
 
-bool
-potential_constant_expression (tree t, tsubst_flags_t flags)
+static bool
+potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
 {
+  enum { any = false, rval = true };
   int i;
   tree tmp;
+
+  /* C++98 has different rules for the form of a constant expression that
+     are enforced in the parser, so we can assume that anything that gets
+     this far is suitable.  */
+  if (cxx_dialect < cxx0x)
+    return true;
+
   if (t == error_mark_node)
     return false;
+  if (t == NULL_TREE)
+    return true;
   if (TREE_THIS_VOLATILE (t))
     {
       if (flags & tf_error)
@@ -7235,8 +7246,18 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
   switch (TREE_CODE (t))
     {
     case FUNCTION_DECL:
+    case BASELINK:
+    case OVERLOAD:
+    case TEMPLATE_ID_EXPR:
     case LABEL_DECL:
     case CONST_DECL:
+    case SIZEOF_EXPR:
+    case ALIGNOF_EXPR:
+    case OFFSETOF_EXPR:
+    case NOEXCEPT_EXPR:
+    case TEMPLATE_PARM_INDEX:
+    case TRAIT_EXPR:
+    case IDENTIFIER_NODE:
       return true;
 
     case PARM_DECL:
@@ -7261,7 +7282,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
         const int nargs = call_expr_nargs (t);
         if (TREE_CODE (fun) != FUNCTION_DECL)
           {
-           if (potential_constant_expression (fun, flags))
+           if (potential_constant_expression_1 (fun, rval, flags))
              /* Might end up being a constant function pointer.  */
              return true;
             if (flags & tf_error)
@@ -7293,11 +7314,9 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
             if (i == 0 && DECL_NONSTATIC_MEMBER_P (fun)
                 && !DECL_CONSTRUCTOR_P (fun))
              {
-               if (TREE_CODE (x) == ADDR_EXPR)
-                 x = TREE_OPERAND (x, 0);
                if (is_this_parameter (x))
                  /* OK.  */;
-                else if (!potential_constant_expression (x, flags))
+                else if (!potential_constant_expression_1 (x, rval, flags))
                  {
                    if (flags & tf_error)
                      error ("object argument is not a potential constant "
@@ -7305,7 +7324,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
                    return false;
                  }
               }
-           else if (!potential_constant_expression (x, flags))
+           else if (!potential_constant_expression_1 (x, rval, flags))
              {
                if (flags & tf_error)
                  error ("argument in position %qP is not a "
@@ -7325,10 +7344,10 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
             -- an lvalue of literal type that refers to non-volatile
                object defined with constexpr, or that refers to a
                sub-object of such an object;  */
-      return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+      return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval, flags);
 
     case VAR_DECL:
-      if (!decl_constant_var_p (t))
+      if (want_rval && !decl_constant_var_p (t))
         {
           if (flags & tf_error)
             error ("variable %qD is not declared constexpr", t);
@@ -7358,7 +7377,8 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
                      "cannot yield a constant expression", from);
             return false;
           }
-        return potential_constant_expression (from, flags);
+        return (potential_constant_expression_1
+               (from, TREE_CODE (t) != VIEW_CONVERT_EXPR, flags));
       }
 
     case ADDR_EXPR:
@@ -7366,6 +7386,10 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
             designates an object with thread or automatic storage
             duration;  */
       t = TREE_OPERAND (t, 0);
+#if 0
+      /* FIXME adjust when issue 1197 is fully resolved.  For now don't do
+         any checking here, as we might dereference the pointer later.  If
+         we remove this code, also remove check_automatic_or_tls.  */
       i = check_automatic_or_tls (t);
       if (i == ck_ok)
        return true;
@@ -7376,15 +7400,23 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
                    "automatic storage is not a constant expression", t);
           return false;
         }
-      return potential_constant_expression (t, flags);
+#endif
+      return potential_constant_expression_1 (t, any, flags);
 
     case COMPONENT_REF:
     case BIT_FIELD_REF:
+    case ARROW_EXPR:
+    case OFFSET_REF:
       /* -- a class member access unless its postfix-expression is
             of literal type or of pointer to literal type.  */
       /* This test would be redundant, as it follows from the
         postfix-expression being a potential constant expression.  */
-      return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+      return potential_constant_expression_1 (TREE_OPERAND (t, 0),
+                                             want_rval, flags);
+
+    case EXPR_PACK_EXPANSION:
+      return potential_constant_expression_1 (PACK_EXPANSION_PATTERN (t),
+                                             want_rval, flags);
 
     case INDIRECT_REF:
       {
@@ -7392,7 +7424,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
         STRIP_NOPS (x);
         if (is_this_parameter (x))
          return true;
-       return potential_constant_expression (x, flags);
+       return potential_constant_expression_1 (x, rval, flags);
       }
 
     case LAMBDA_EXPR:
@@ -7417,6 +7449,10 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
     case MUST_NOT_THROW_EXPR:
     case TRY_CATCH_EXPR:
     case STATEMENT_LIST:
+      /* Don't bother trying to define a subset of statement-expressions to
+        be constant-expressions, at least for now.  */
+    case STMT_EXPR:
+    case EXPR_STMT:
     case BIND_EXPR:
       if (flags & tf_error)
         error ("expression %qE is not a constant-expression", t);
@@ -7427,7 +7463,8 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
             class type;  */
       {
         tree e = TREE_OPERAND (t, 0);
-        if (!TYPE_P (e) && TYPE_POLYMORPHIC_P (TREE_TYPE (e)))
+        if (!TYPE_P (e) && !type_dependent_expression_p (e)
+           && TYPE_POLYMORPHIC_P (TREE_TYPE (e)))
           {
             if (flags & tf_error)
               error ("typeid-expression is not a constant expression "
@@ -7447,6 +7484,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
                    "a constant expression");
           return false;
         }
+      want_rval = true;
       goto binary;
 
     case LT_EXPR:
@@ -7465,6 +7503,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
                    "constant expression");
           return false;
         }
+      want_rval = true;
       goto binary;
 
     case REALPART_EXPR:
@@ -7477,22 +7516,41 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
     case ABS_EXPR:
     case BIT_NOT_EXPR:
     case TRUTH_NOT_EXPR:
-    case PAREN_EXPR:
     case FIXED_CONVERT_EXPR:
+    case UNARY_PLUS_EXPR:
+      return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval,
+                                             flags);
+
+    case CAST_EXPR:
+    case CONST_CAST_EXPR:
+    case STATIC_CAST_EXPR:
+    case REINTERPRET_CAST_EXPR:
+      return (potential_constant_expression_1
+             (TREE_OPERAND (t, 0),
+              TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE, flags));
+
+    case PAREN_EXPR:
+    case NON_DEPENDENT_EXPR:
       /* For convenience.  */
     case RETURN_EXPR:
-      return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+      return potential_constant_expression_1 (TREE_OPERAND (t, 0),
+                                             want_rval, flags);
+
+    case SCOPE_REF:
+      return potential_constant_expression_1 (TREE_OPERAND (t, 1),
+                                             want_rval, flags);
 
     case INIT_EXPR:
     case TARGET_EXPR:
-      return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+      return potential_constant_expression_1 (TREE_OPERAND (t, 1),
+                                             rval, flags);
 
     case CONSTRUCTOR:
       {
         VEC(constructor_elt, gc) *v = CONSTRUCTOR_ELTS (t);
         constructor_elt *ce;
         for (i = 0; VEC_iterate (constructor_elt, v, i, ce); ++i)
-         if (!potential_constant_expression (ce->value, flags))
+         if (!potential_constant_expression_1 (ce->value, want_rval, flags))
            return false;
        return true;
       }
@@ -7501,11 +7559,13 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
       {
        gcc_assert (TREE_PURPOSE (t) == NULL_TREE
                    || DECL_P (TREE_PURPOSE (t)));
-       if (!potential_constant_expression (TREE_VALUE (t), flags))
+       if (!potential_constant_expression_1 (TREE_VALUE (t), want_rval,
+                                             flags))
          return false;
        if (TREE_CHAIN (t) == NULL_TREE)
          return true;
-       return potential_constant_expression (TREE_CHAIN (t), flags);
+       return potential_constant_expression_1 (TREE_CHAIN (t), want_rval,
+                                               flags);
       }
 
     case TRUNC_DIV_EXPR:
@@ -7515,10 +7575,24 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
     case TRUNC_MOD_EXPR:
     case CEIL_MOD_EXPR:
     case ROUND_MOD_EXPR:
-      if (integer_zerop (maybe_constant_value (TREE_OPERAND (t, 1))))
-       return false;
-      else
-       goto binary;
+      {
+       tree denom = TREE_OPERAND (t, 1);
+       /* We can't call maybe_constant_value on an expression
+          that hasn't been through fold_non_dependent_expr yet.  */
+       if (!processing_template_decl)
+         denom = maybe_constant_value (denom);
+       if (integer_zerop (denom))
+         {
+           if (flags & tf_error)
+             error ("division by zero is not a constant-expression");
+           return false;
+         }
+       else
+         {
+           want_rval = true;
+           goto binary;
+         }
+      }
 
     case COMPOUND_EXPR:
       {
@@ -7530,7 +7604,7 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
        STRIP_NOPS (op1);
        if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0))
            || TREE_CODE (op1) == EMPTY_CLASS_EXPR)
-         return potential_constant_expression (op0, flags);
+         return potential_constant_expression_1 (op0, want_rval, flags);
        else
          goto binary;
       }
@@ -7547,12 +7621,10 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
       tmp = boolean_false_node;
     truth:
       if (TREE_OPERAND (t, 0) == tmp)
-       return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+       return potential_constant_expression_1 (TREE_OPERAND (t, 1), rval, flags);
       else
-       return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+       return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval, flags);
 
-    case ARRAY_REF:
-    case ARRAY_RANGE_REF:
     case PLUS_EXPR:
     case MULT_EXPR:
     case POINTER_PLUS_EXPR:
@@ -7574,10 +7646,16 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
     case UNEQ_EXPR:
     case RANGE_EXPR:
     case COMPLEX_EXPR:
+      want_rval = true;
+      /* Fall through.  */
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+    case MEMBER_REF:
+    case DOTSTAR_EXPR:
     binary:
       for (i = 0; i < 2; ++i)
-       if (!potential_constant_expression (TREE_OPERAND (t, i),
-                                     flags))
+       if (!potential_constant_expression_1 (TREE_OPERAND (t, i),
+                                             want_rval, flags))
          return false;
       return true;
 
@@ -7587,21 +7665,28 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
         care about; otherwise we only require that the condition and
         either of the legs be potentially constant.  */
       tmp = TREE_OPERAND (t, 0);
-      if (!potential_constant_expression (tmp, flags))
+      if (!potential_constant_expression_1 (tmp, rval, flags))
        return false;
       else if (tmp == boolean_true_node)
-       return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+       return potential_constant_expression_1 (TREE_OPERAND (t, 1),
+                                               want_rval, flags);
       else if (tmp == boolean_false_node)
-       return potential_constant_expression (TREE_OPERAND (t, 2), flags);
+       return potential_constant_expression_1 (TREE_OPERAND (t, 2),
+                                               want_rval, flags);
       for (i = 1; i < 3; ++i)
-       if (potential_constant_expression (TREE_OPERAND (t, i), tf_none))
+       if (potential_constant_expression_1 (TREE_OPERAND (t, i),
+                                            want_rval, tf_none))
          return true;
       if (flags & tf_error)
         error ("expression %qE is not a constant-expression", t);
       return false;
 
     case VEC_INIT_EXPR:
-      return VEC_INIT_EXPR_IS_CONSTEXPR (t);
+      if (VEC_INIT_EXPR_IS_CONSTEXPR (t))
+       return true;
+      if (flags & tf_error)
+        error ("non-constant array initialization");
+      return false;
 
     default:
       sorry ("unexpected ast of kind %s", tree_code_name[TREE_CODE (t)]);
@@ -7610,6 +7695,21 @@ potential_constant_expression (tree t, tsubst_flags_t flags)
     }
 }
 
+/* The main entry point to the above.  */
+
+bool
+potential_constant_expression (tree t)
+{
+  return potential_constant_expression_1 (t, false, tf_none);
+}
+
+/* Like above, but complain about non-constant expressions.  */
+
+bool
+require_potential_constant_expression (tree t)
+{
+  return potential_constant_expression_1 (t, false, tf_warning_or_error);
+}
 \f
 /* Constructor for a lambda expression.  */
 
index 813b88d..1a1f150 100644 (file)
@@ -513,9 +513,13 @@ build_vec_init_expr (tree type, tree init)
   SET_EXPR_LOCATION (init, input_location);
 
   if (current_function_decl
-      && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
-      && potential_constant_expression (elt_init, tf_warning_or_error))
-    VEC_INIT_EXPR_IS_CONSTEXPR (init) = true;
+      && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+    {
+      if (potential_constant_expression (elt_init))
+       VEC_INIT_EXPR_IS_CONSTEXPR (init) = true;
+      else if (!processing_template_decl)
+       require_potential_constant_expression (elt_init);
+    }
   VEC_INIT_EXPR_VALUE_INIT (init) = value_init;
 
   init = build_target_expr (slot, init);
index b8962fe..df43d93 100644 (file)
@@ -1,3 +1,7 @@
+2011-01-21  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/cpp0x/constexpr-stmtexpr.C: New.
+
 2011-01-21  Jeff Law <law@redhat.com>
 
        PR rtl-optimization/41619
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-stmtexpr.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-stmtexpr.C
new file mode 100644 (file)
index 0000000..40e0c2d
--- /dev/null
@@ -0,0 +1,8 @@
+// PR c++/46977
+// { dg-options "-std=c++0x" }
+
+template < typename > void
+foo ()
+{
+  ({int i;}), 0;
+}