]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cp-tree.h (register_constexpr_fundef): Declare.
authorJason Merrill <jason@gcc.gnu.org>
Tue, 2 Nov 2010 01:30:51 +0000 (21:30 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 2 Nov 2010 01:30:51 +0000 (21:30 -0400)
* cp-tree.h (register_constexpr_fundef): Declare.
* decl.c (maybe_save_function_definition): New.
(finish_function): Use it.
* semantics.c (constexpr_fundef): New datatype.
(constexpr_fundef_table): New global table.
(constexpr_fundef_equal): New.
(constexpr_fundef_hash): Likewise.
(retrieve_constexpr_fundef): Likewise.
(validate_constexpr_fundecl): Store in the table.
(build_data_member_initialization): New fn.
(build_constexpr_constructor_member_initializers): New.
(register_constexpr_fundef): Define.
(is_this_parameter): New.
(get_function_named_in_call): Likewise.
(get_nth_callarg): Likewise.
(check_automatic_or_tls): New.
(morally_constexpr_builtin_function_p): New.
(potential_constant_expression): New.

From-SVN: r166165

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

index 264683949cbd25fc04ea401d14a6ae679fa6a6e1..f790525f1c68a295a364f9ee6ef90fdfafa3dc51 100644 (file)
@@ -1,3 +1,25 @@
+2010-11-01  Gabriel Dos Reis  <gdr@cse.tamu.edu>
+           Jason Merrill  <jason@redhat.com>
+
+       * cp-tree.h (register_constexpr_fundef): Declare.
+       * decl.c (maybe_save_function_definition): New.
+       (finish_function): Use it.
+       * semantics.c (constexpr_fundef): New datatype.
+       (constexpr_fundef_table): New global table.
+       (constexpr_fundef_equal): New.
+       (constexpr_fundef_hash): Likewise.
+       (retrieve_constexpr_fundef): Likewise.
+       (validate_constexpr_fundecl): Store in the table.
+       (build_data_member_initialization): New fn.
+       (build_constexpr_constructor_member_initializers): New.
+       (register_constexpr_fundef): Define.
+       (is_this_parameter): New.
+       (get_function_named_in_call): Likewise.
+       (get_nth_callarg): Likewise.
+       (check_automatic_or_tls): New.
+       (morally_constexpr_builtin_function_p): New.
+       (potential_constant_expression): New.
+
 2010-11-01  Jason Merrill  <jason@redhat.com>
 
        * decl2.c (decl_constant_var_p): New fn.
index bc4eb46e7f09d20e8838b74fd5600432f14a7c57..4dfa8e9c4f03fa688964d5e577e479f1704b1e41 100644 (file)
@@ -5252,6 +5252,7 @@ extern void finish_handler                        (tree);
 extern void finish_cleanup                     (tree, tree);
 extern bool literal_type_p (tree);
 extern tree validate_constexpr_fundecl (tree);
+extern tree register_constexpr_fundef (tree, tree);
 extern tree ensure_literal_type_for_constexpr_object (tree);
 
 enum {
index b7ab080f8cefa7522958e618af4e182e20c218ea..de6f0c4ff2777a272873dda4315b90a5a75b23e3 100644 (file)
@@ -12667,6 +12667,19 @@ record_key_method_defined (tree fndecl)
     }
 }
 
+/* Subroutine of finish_function.
+   Save the body of constexpr functions for possible
+   future compile time evaluation.  */
+
+static void
+maybe_save_function_definition (tree fun)
+{
+  if (!processing_template_decl
+      && DECL_DECLARED_CONSTEXPR_P (fun)
+      && !DECL_CLONED_FUNCTION_P (fun))
+    register_constexpr_fundef (fun, DECL_SAVED_TREE (fun));
+}
+
 /* Finish up a function declaration and compile that function
    all the way to assembler language output.  The free the storage
    for the function definition.
@@ -12778,6 +12791,10 @@ finish_function (int flags)
      of curly braces for a function.  */
   gcc_assert (stmts_are_full_exprs_p ());
 
+  /* Save constexpr function body before it gets munged by
+     the NRV transformation.   */
+  maybe_save_function_definition (fndecl);
+
   /* Set up the named return value optimization, if we can.  Candidate
      variables are selected in check_return_expr.  */
   if (current_function_return_value)
index ad26abb0930f01a02f03ca23bb39186f4cd7b5a6..0420d37789e50ae9394794c8816b455defa2b3a5 100644 (file)
@@ -5282,6 +5282,55 @@ ensure_literal_type_for_constexpr_object (tree decl)
   return decl;
 }
 
+/* Representation of entries in the constexpr function definition table.  */
+
+typedef struct GTY(()) constexpr_fundef {
+  tree decl;
+  tree body;
+} constexpr_fundef;
+
+/* This table holds all constexpr function definitions seen in
+   the current translation unit.  */
+
+static GTY ((param_is (constexpr_fundef))) htab_t constexpr_fundef_table;
+
+static bool potential_constant_expression (tree, tsubst_flags_t);
+
+/* Utility function used for managing the constexpr function table.
+   Return true if the entries pointed to by P and Q are for the
+   same constexpr function.  */
+
+static inline int
+constexpr_fundef_equal (const void *p, const void *q)
+{
+  const constexpr_fundef *lhs = (const constexpr_fundef *) p;
+  const constexpr_fundef *rhs = (const constexpr_fundef *) q;
+  return lhs->decl == rhs->decl;
+}
+
+/* Utility function used for managing the constexpr function table.
+   Return a hash value for the entry pointed to by Q.  */
+
+static inline hashval_t
+constexpr_fundef_hash (const void *p)
+{
+  const constexpr_fundef *fundef = (const constexpr_fundef *) p;
+  return DECL_UID (fundef->decl);
+}
+
+/* Return a previously saved definition of function FUN.   */
+
+static constexpr_fundef *
+retrieve_constexpr_fundef (tree fun)
+{
+  constexpr_fundef fundef = { NULL, NULL };
+  if (constexpr_fundef_table == NULL)
+    return NULL;
+
+  fundef.decl = fun;
+  return (constexpr_fundef *) htab_find (constexpr_fundef_table, &fundef);
+}
+
 /* Return true if type expression T is a valid parameter type, or
    a valid return type, of a constexpr function.  */
 
@@ -5343,6 +5392,9 @@ is_valid_constexpr_fn (tree fun, bool complain)
 tree
 validate_constexpr_fundecl (tree fun)
 {
+  constexpr_fundef entry;
+  constexpr_fundef **slot;
+
   if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
     return NULL;
   else if (DECL_CLONED_FUNCTION_P (fun))
@@ -5355,10 +5407,684 @@ validate_constexpr_fundecl (tree fun)
       return NULL;
     }
 
+  /* Create the constexpr function table if necessary.  */
+  if (constexpr_fundef_table == NULL)
+    constexpr_fundef_table = htab_create_ggc (101,
+                                              constexpr_fundef_hash,
+                                              constexpr_fundef_equal,
+                                              ggc_free);
+  entry.decl = fun;
+  entry.body = NULL;
+  slot = (constexpr_fundef **)
+    htab_find_slot (constexpr_fundef_table, &entry, INSERT);
+  if (*slot == NULL)
+    {
+      *slot = ggc_alloc_constexpr_fundef ();
+      **slot = entry;
+    }
+  return fun;
+}
+
+/* Subroutine of  build_constexpr_constructor_member_initializers.
+   The expression tree T represents a data member initialization
+   in a (constexpr) constructor definition.  Build a pairing of
+   the data member with its initializer, and prepend that pair
+   to the existing initialization pair INITS.  */
+
+static bool
+build_data_member_initialization (tree t, VEC(constructor_elt,gc) **vec)
+{
+  tree member, init;
+  if (TREE_CODE (t) == CLEANUP_POINT_EXPR)
+    t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == EXPR_STMT)
+    t = TREE_OPERAND (t, 0);
+  if (t == error_mark_node)
+    return false;
+  if (TREE_CODE (t) == CLEANUP_STMT)
+    /* We can't see a CLEANUP_STMT in a constructor for a literal class,
+       but we can in a constexpr constructor for a non-literal class.  Just
+       ignore it; either all the initialization will be constant, in which
+       case the cleanup can't run, or it can't be constexpr.  */
+    return true;
+  if (TREE_CODE (t) == CONVERT_EXPR)
+    t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == INIT_EXPR
+      || TREE_CODE (t) == MODIFY_EXPR)
+    {
+      member = TREE_OPERAND (t, 0);
+      init = unshare_expr (TREE_OPERAND (t, 1));
+    }
+  else
+    {
+      tree memtype;
+      gcc_assert (TREE_CODE (t) == CALL_EXPR);
+      member = CALL_EXPR_ARG (t, 0);
+      memtype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (member)));
+      if (TREE_CODE (member) == NOP_EXPR)
+       {
+         /* We don't put out anything for an empty base.  */
+         gcc_assert (is_empty_class (memtype));
+         /* But if the constructor used isn't constexpr, leave in the call
+            so we complain later.  */
+         if (potential_constant_expression (t, tf_none))
+           return true;
+       }
+      else
+       {
+         gcc_assert (TREE_CODE (member) == ADDR_EXPR);
+         member = TREE_OPERAND (member, 0);
+       }
+      /* We don't use build_cplus_new here because it complains about
+        abstract bases.  T has the wrong type, but
+        cxx_eval_constant_expression doesn't care.  */
+      init = unshare_expr (t);
+    }
+  if (TREE_CODE (member) == COMPONENT_REF)
+    member = TREE_OPERAND (member, 1);
+  CONSTRUCTOR_APPEND_ELT (*vec, member, init);
+  return true;
+}
+
+/* Build compile-time evalable representations of member-initializer list
+   for a constexpr constructor.  */
+
+static tree
+build_constexpr_constructor_member_initializers (tree type, tree body)
+{
+  VEC(constructor_elt,gc) *vec = NULL;
+  bool ok = true;
+  if (TREE_CODE (body) == MUST_NOT_THROW_EXPR
+      || TREE_CODE (body) == EH_SPEC_BLOCK)
+    body = TREE_OPERAND (body, 0);
+  if (TREE_CODE (body) == BIND_EXPR)
+    body = BIND_EXPR_BODY (body);
+  if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
+    ok = build_data_member_initialization (body, &vec);
+  else
+    {
+      tree_stmt_iterator i;
+      gcc_assert (TREE_CODE (body) == STATEMENT_LIST);
+      for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
+       {
+         ok = build_data_member_initialization (tsi_stmt (i), &vec);
+         if (!ok)
+           break;
+       }
+    }
+  if (ok)
+    return build_constructor (type, vec);
+  else
+    return error_mark_node;
+}
+
+/* We are processing the definition of the constexpr function FUN.
+   Check that its BODY fulfills the propriate requirements and
+   enter it in the constexpr function definition table.
+   For constructor BODY is actually the TREE_LIST of the
+   member-initializer list.  */
+
+tree
+register_constexpr_fundef (tree fun, tree body)
+{
+  constexpr_fundef *fundef = retrieve_constexpr_fundef (fun);
+  gcc_assert (fundef != NULL && fundef->body == NULL);
+
+  if (DECL_CONSTRUCTOR_P (fun))
+    body = build_constexpr_constructor_member_initializers
+      (DECL_CONTEXT (fun), body);
+  else
+    {
+      if (TREE_CODE (body) == BIND_EXPR)
+       body = BIND_EXPR_BODY (body);
+      if (TREE_CODE (body) == EH_SPEC_BLOCK)
+        body = EH_SPEC_STMTS (body);
+      if (TREE_CODE (body) == MUST_NOT_THROW_EXPR)
+       body = TREE_OPERAND (body, 0);
+      if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
+        body = TREE_OPERAND (body, 0);
+      if (TREE_CODE (body) != RETURN_EXPR)
+        {
+          error ("body of constexpr function %qD not a return-statement", fun);
+          DECL_DECLARED_CONSTEXPR_P (fun) = false;
+          return NULL;
+        }
+      body = unshare_expr (TREE_OPERAND (body, 0));
+    }
+
+  if (!potential_constant_expression (body, (DECL_TEMPLATE_INSTANTIATION (fun)
+                                            ? tf_none : tf_error)))
+    {
+      DECL_DECLARED_CONSTEXPR_P (fun) = false;
+      return NULL;
+    }
+  fundef->body = body;
+  return fun;
+}
+
+/* Return true if T designates the implied `this' parameter.  */
+
+static inline bool
+is_this_parameter (tree t)
+{
+  return t == current_class_ptr;
+}
+
+/* We have an expression tree T that represents a call, either CALL_EXPR
+   or AGGR_INIT_EXPR.  If the call is lexically to a named function,
+   retrun the _DECL for that function.  */
+
+static tree
+get_function_named_in_call (tree t)
+{
+  tree fun = NULL;
+  switch (TREE_CODE (t))
+    {
+    case CALL_EXPR:
+      fun = CALL_EXPR_FN (t);
+      break;
+
+    case AGGR_INIT_EXPR:
+      fun = AGGR_INIT_EXPR_FN (t);
+      break;
+
+    default:
+      gcc_unreachable();
+      break;
+    }
+  if (TREE_CODE (fun) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (fun, 0)) == FUNCTION_DECL)
+    fun = TREE_OPERAND (fun, 0);
   return fun;
 }
 
+/* We have an expression tree T that represents a call, either CALL_EXPR
+   or AGGR_INIT_EXPR.  Return the Nth argument.  */
+
+static inline tree
+get_nth_callarg (tree t, int n)
+{
+  switch (TREE_CODE (t))
+    {
+    case CALL_EXPR:
+      return CALL_EXPR_ARG (t, n);
+
+    case AGGR_INIT_EXPR:
+      return AGGR_INIT_EXPR_ARG (t, n);
+
+    default:
+      gcc_unreachable ();
+      return NULL;
+    }
+}
+
+/* Return true if the object referred to by REF has automatic or thread
+   local storage.  */
+
+enum { ck_ok, ck_bad, ck_unknown };
+static int
+check_automatic_or_tls (tree ref)
+{
+  enum machine_mode mode;
+  HOST_WIDE_INT bitsize, bitpos;
+  tree offset;
+  int volatilep = 0, unsignedp = 0;
+  tree decl = get_inner_reference (ref, &bitsize, &bitpos, &offset,
+                                  &mode, &unsignedp, &volatilep, false);
+  duration_kind dk;
+
+  /* If there isn't a decl in the middle, we don't know the linkage here,
+     and this isn't a constant expression anyway.  */
+  if (!DECL_P (decl))
+    return ck_unknown;
+  dk = decl_storage_duration (decl);
+  return (dk == dk_auto || dk == dk_thread) ? ck_bad : ck_ok;
+}
+
+/* Return true if the DECL designates a builtin function that is
+   morally constexpr, in the sense that its parameter types and
+   return type are literal types and the compiler is allowed to
+   fold its invocations.  */
+
+static bool
+morally_constexpr_builtin_function_p (tree decl)
+{
+  tree funtype = TREE_TYPE (decl);
+  tree t;
+
+  if (!is_builtin_fn (decl))
+    return false;
+  if (!literal_type_p (TREE_TYPE (funtype)))
+    return false;
+  for (t = TYPE_ARG_TYPES (funtype); t != NULL ; t = TREE_CHAIN (t))
+    {
+      if (t == void_list_node)
+        return true;
+      if (!literal_type_p (TREE_VALUE (t)))
+        return false;
+    }
+  /* We assume no varargs builtins are suitable.  */
+  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.
+
+   C++0x [expr.const]
+
+   6 An expression is a potential constant expression if it is
+     a constant expression where all occurences of function
+     parameters are replaced by arbitrary constant expressions
+     of the appropriate type.
+
+   2  A conditional expression is a constant expression unless it
+      involves one of the following as a potentially evaluated
+      subexpression (3.2), but subexpressions of logical AND (5.14),
+      logical OR (5.15), and conditional (5.16) operations that are
+      not evaluated are not considered.   */
+
+static bool
+potential_constant_expression (tree t, tsubst_flags_t flags)
+{
+  int i;
+  tree tmp;
+  if (t == error_mark_node)
+    return false;
+  if (TREE_THIS_VOLATILE (t))
+    {
+      if (flags & tf_error)
+        error ("expression %qE has side-effects", t);
+      return false;
+    }
+  if (CONSTANT_CLASS_P (t))
+    return true;
+
+  switch (TREE_CODE (t))
+    {
+    case FUNCTION_DECL:
+    case LABEL_DECL:
+    case CONST_DECL:
+      return true;
+
+    case PARM_DECL:
+      /* -- this (5.1) unless it appears as the postfix-expression in a
+            class member access expression, including the result of the
+            implicit transformation in the body of the non-static
+            member function (9.3.1);  */
+      if (is_this_parameter (t))
+        {
+          if (flags & tf_error)
+            error ("%qE is not a potential constant expression", t);
+          return false;
+        }
+      return true;
+
+    case AGGR_INIT_EXPR:
+    case CALL_EXPR:
+      /* -- an invocation of a function other than a constexpr function
+            or a constexpr constructor.  */
+      {
+        tree fun = get_function_named_in_call (t);
+        const int nargs = call_expr_nargs (t);
+        if (TREE_CODE (fun) != FUNCTION_DECL)
+          {
+           if (potential_constant_expression (fun, flags))
+             /* Might end up being a constant function pointer.  */
+             return true;
+            if (flags & tf_error)
+              error ("%qE is not a function name", fun);
+            return false;
+          }
+       /* Skip initial arguments to base constructors.  */
+       if (DECL_BASE_CONSTRUCTOR_P (fun))
+         i = num_artificial_parms_for (fun);
+       else
+         i = 0;
+       fun = DECL_ORIGIN (fun);
+        if (builtin_valid_in_constant_expr_p (fun))
+          return true;
+        if (!DECL_DECLARED_CONSTEXPR_P (fun)
+            && !morally_constexpr_builtin_function_p (fun))
+          {
+            if (flags & tf_error)
+              error ("%qD is not %<constexpr%>", fun);
+            return false;
+          }
+        for (; i < nargs; ++i)
+          {
+            tree x = get_nth_callarg (t, i);
+            /* A call to a non-static member function takes the
+               address of the object as the first argument.
+               But in a constant expression the address will be folded
+              away, so look through it now.  */
+            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))
+                 {
+                   if (flags & tf_error)
+                     error ("object argument is not a potential constant "
+                            "expression");
+                   return false;
+                 }
+              }
+           else if (!potential_constant_expression (x, flags))
+             {
+               if (flags & tf_error)
+                 error ("argument in position %qP is not a "
+                        "potential constant expression", i);
+               return false;
+              }
+          }
+        return true;
+      }
+
+    case NON_LVALUE_EXPR:
+      /* -- an lvalue-to-rvalue conversion (4.1) unless it is applied to
+            -- an lvalue of integral type that refers to a non-volatile
+               const variable or static data member initialized with
+               constant expressions, or
+
+            -- 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);
+
+    case VAR_DECL:
+      if (!decl_constant_var_p (t))
+        {
+          if (flags & tf_error)
+            error ("variable %qD is not declared constexpr", t);
+          return false;
+        }
+      return true;
+
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+    case VIEW_CONVERT_EXPR:
+      /* -- an array-to-pointer conversion that is applied to an lvalue
+            that designates an object with thread or automatic storage
+            duration;  FIXME not implemented as it breaks constexpr arrays;
+           need to fix the standard
+         -- a type conversion from a pointer or pointer-to-member type
+            to a literal type.  */
+      {
+        tree from = TREE_OPERAND (t, 0);
+        tree source = TREE_TYPE (from);
+        tree target = TREE_TYPE (t);
+        if (TYPE_PTR_P (source) && ARITHMETIC_TYPE_P (target)
+           && !(TREE_CODE (from) == COMPONENT_REF
+                && TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (from, 0)))))
+          {
+            if (flags & tf_error)
+              error ("conversion of expression %qE of pointer type "
+                     "cannot yield a constant expression", from);
+            return false;
+          }
+        return potential_constant_expression (from, flags);
+      }
+
+    case ADDR_EXPR:
+      /* -- a unary operator & that is applied to an lvalue that
+            designates an object with thread or automatic storage
+            duration;  */
+      t = TREE_OPERAND (t, 0);
+      i = check_automatic_or_tls (t);
+      if (i == ck_ok)
+       return true;
+      if (i == ck_bad)
+        {
+          if (flags & tf_error)
+            error ("address-of an object %qE with thread local or "
+                   "automatic storage is not a constant expression", t);
+          return false;
+        }
+      return potential_constant_expression (t, flags);
+
+    case COMPONENT_REF:
+    case BIT_FIELD_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);
+
+    case INDIRECT_REF:
+      {
+        tree x = TREE_OPERAND (t, 0);
+        STRIP_NOPS (x);
+        if (is_this_parameter (x))
+         return true;
+       return potential_constant_expression (x, flags);
+      }
+
+    case LAMBDA_EXPR:
+    case DYNAMIC_CAST_EXPR:
+    case PSEUDO_DTOR_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case NEW_EXPR:
+    case VEC_NEW_EXPR:
+    case DELETE_EXPR:
+    case VEC_DELETE_EXPR:
+    case THROW_EXPR:
+    case MODIFY_EXPR:
+    case MODOP_EXPR:
+      /* GCC internal stuff.  */
+    case VA_ARG_EXPR:
+    case OBJ_TYPE_REF:
+    case WITH_CLEANUP_EXPR:
+    case CLEANUP_POINT_EXPR:
+    case MUST_NOT_THROW_EXPR:
+    case TRY_CATCH_EXPR:
+    case STATEMENT_LIST:
+    case BIND_EXPR:
+      if (flags & tf_error)
+        error ("expression %qE is not a constant-expression", t);
+      return false;
 
+    case TYPEID_EXPR:
+      /* -- a typeid expression whose operand is of polymorphic
+            class type;  */
+      {
+        tree e = TREE_OPERAND (t, 0);
+        if (!TYPE_P (e) && TYPE_POLYMORPHIC_P (TREE_TYPE (e)))
+          {
+            if (flags & tf_error)
+              error ("typeid-expression is not a constant expression "
+                     "because %qE is of polymorphic type", e);
+            return false;
+          }
+        return true;
+      }
+
+    case MINUS_EXPR:
+      /* -- a subtraction where both operands are pointers.   */
+      if (TYPE_PTR_P (TREE_OPERAND (t, 0))
+          && TYPE_PTR_P (TREE_OPERAND (t, 1)))
+        {
+          if (flags & tf_error)
+            error ("difference of two pointer expressions is not "
+                   "a constant expression");
+          return false;
+        }
+      goto binary;
+
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+      /* -- a relational or equality operator where at least
+            one of the operands is a pointer.  */
+      if (TYPE_PTR_P (TREE_OPERAND (t, 0))
+          || TYPE_PTR_P (TREE_OPERAND (t, 1)))
+        {
+          if (flags & tf_error)
+            error ("pointer comparison expression is not a "
+                   "constant expression");
+          return false;
+        }
+      goto binary;
+
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case CONJ_EXPR:
+    case SAVE_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FLOAT_EXPR:
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case PAREN_EXPR:
+    case FIXED_CONVERT_EXPR:
+      /* For convenience.  */
+    case RETURN_EXPR:
+      return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+
+    case INIT_EXPR:
+    case TARGET_EXPR:
+      return potential_constant_expression (TREE_OPERAND (t, 1), 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))
+           return false;
+       return true;
+      }
+
+    case TREE_LIST:
+      {
+       gcc_assert (TREE_PURPOSE (t) == NULL_TREE
+                   || DECL_P (TREE_PURPOSE (t)));
+       if (!potential_constant_expression (TREE_VALUE (t), flags))
+         return false;
+       if (TREE_CHAIN (t) == NULL_TREE)
+         return true;
+       return potential_constant_expression (TREE_CHAIN (t), flags);
+      }
+
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+      if (integer_zerop (decl_constant_value (TREE_OPERAND (t, 1))))
+       return false;
+      else
+       goto binary;
+
+    case COMPOUND_EXPR:
+      {
+       /* check_return_expr sometimes wraps a TARGET_EXPR in a
+          COMPOUND_EXPR; don't get confused.  Also handle EMPTY_CLASS_EXPR
+          introduced by build_call_a.  */
+       tree op0 = TREE_OPERAND (t, 0);
+       tree op1 = TREE_OPERAND (t, 1);
+       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);
+       else
+         goto binary;
+      }
+
+      /* If the first operand is the non-short-circuit constant, look at
+        the second operand; otherwise we only care about the first one for
+        potentiality.  */
+    case TRUTH_AND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+      tmp = boolean_true_node;
+      goto truth;
+    case TRUTH_OR_EXPR:
+    case TRUTH_ORIF_EXPR:
+      tmp = boolean_false_node;
+    truth:
+      if (TREE_OPERAND (t, 0) == tmp)
+       return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+      else
+       return potential_constant_expression (TREE_OPERAND (t, 0), flags);
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+    case PLUS_EXPR:
+    case MULT_EXPR:
+    case POINTER_PLUS_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case MIN_EXPR:
+    case MAX_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case BIT_AND_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case RANGE_EXPR:
+    case COMPLEX_EXPR:
+    binary:
+      for (i = 0; i < 2; ++i)
+       if (!potential_constant_expression (TREE_OPERAND (t, i),
+                                     flags))
+         return false;
+      return true;
+
+    case COND_EXPR:
+    case VEC_COND_EXPR:
+      /* If the condition is a known constant, we know which of the legs we
+        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))
+       return false;
+      else if (tmp == boolean_true_node)
+       return potential_constant_expression (TREE_OPERAND (t, 1), flags);
+      else if (tmp == boolean_false_node)
+       return potential_constant_expression (TREE_OPERAND (t, 2), flags);
+      for (i = 1; i < 3; ++i)
+       if (potential_constant_expression (TREE_OPERAND (t, i), tf_none))
+         return true;
+      if (flags & tf_error)
+        error ("expression %qE is not a constant-expression", t);
+      return false;
+
+    case VEC_INIT_EXPR:
+      /* We should only see this in a defaulted constructor for a class
+        with a non-static data member of array type; if we get here we
+        know this is a potential constant expression.  */
+      gcc_assert (DECL_DEFAULTED_FN (current_function_decl));
+      return true;
+
+    default:
+      sorry ("unexpected ast of kind %s", tree_code_name[TREE_CODE (t)]);
+      gcc_unreachable();
+      return false;
+    }
+}
+
+\f
 /* Constructor for a lambda expression.  */
 
 tree
index ea07278fd778842377b51d0f1ec61a484ba49cee..c5be6e9f14299987b686706792ee1e8896d3a309 100644 (file)
@@ -1,3 +1,7 @@
+2010-11-01  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/cpp0x/constexpr-ctor2.C: New.
+
 2010-11-01  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        Implemented format and noreturn attributes for Objective-C methods.
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor2.C
new file mode 100644 (file)
index 0000000..5280b13
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+  A();
+};
+
+struct B : A
+{
+  constexpr B(): A() { }       // { dg-error "A::A" }
+};