C++14 constexpr support (minus loops and multiple returns)
authorJason Merrill <jason@redhat.com>
Mon, 17 Nov 2014 18:16:14 +0000 (13:16 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 17 Nov 2014 18:16:14 +0000 (13:16 -0500)
C++14 constexpr support (minus loops and multiple returns)
gcc/
* tree-inline.c (copy_fn): New.
* tree-inline.h: Declare it.
gcc/cp/
* constexpr.c (use_new_call): New macro.
(build_data_member_initialization): Ignore non-mem-inits.
(check_constexpr_bind_expr_vars): Remove C++14 checks.
(constexpr_fn_retval): Likewise.
(check_constexpr_ctor_body): Do nothing in C++14.
(massage_constexpr_body): In C++14 only collect mem-inits.
(get_function_named_in_call): Handle null CALL_EXPR_FN.
(cxx_bind_parameters_in_call): Build bindings in same order as
parameters.  Don't treat iniviref parms specially in new call mode.
(cxx_eval_call_expression): If use_new_call, do constexpr expansion
based on DECL_SAVED_TREE rather than the massaged constexpr body.
Set up ctx->object from AGGR_INIT_EXPR_SLOT if we don't have one.
(is_sub_constant_expr): Don't mess with ctx.ctor here.
(cxx_eval_component_reference): A null element means we're mid-
initialization.
(cxx_eval_store_expression, cxx_eval_increment_expression): New.
(cxx_eval_constant_expression): Handle RESULT_DECL, DECL_EXPR,
MODIFY_EXPR, STATEMENT_LIST, BIND_EXPR, USING_STMT,
PREINCREMENT_EXPR, POSTINCREMENT_EXPR, PREDECREMENT_EXPR,
POSTDECREMENT_EXPR.  Don't look into DECL_INITIAL of variables in
constexpr functions.  In new-call mode find parms in the values table.
(potential_constant_expression_1): Handle null CALL_EXPR_FN.
Handle STATEMENT_LIST, MODIFY_EXPR, MODOP_EXPR, IF_STMT,
PREINCREMENT_EXPR, POSTINCREMENT_EXPR, PREDECREMENT_EXPR,
POSTDECREMENT_EXPR, BIND_EXPR, WITH_CLEANUP_EXPR,
CLEANUP_POINT_EXPR, MUST_NOT_THROW_EXPR, TRY_CATCH_EXPR,
EH_SPEC_BLOCK, EXPR_STMT, DECL_EXPR, CASE_LABEL_EXPR, BREAK_STMT,
CONTINUE_STMT, USING_STMT, IF_STMT, DO_STMT, FOR_STMT, WHILE_STMT,
SWITCH_STMT, ASM_EXPR.
(cxx_eval_vec_init_1): Call build_aggr_init_expr.
(cxx_eval_indirect_ref): Don't return a CONSTRUCTOR when the
caller wants an lvalue.
(cxx_eval_outermost_constant_expr): Pull object out of AGGR_INIT_EXPR.
(maybe_constant_init): Look through INIT_EXPR.
(ensure_literal_type_for_constexpr_object): Set
cp_function_chain->invalid_constexpr.
* cp-tree.h (struct language_function): Add invalid_constexpr bitfield.
* decl.c (start_decl): Set cp_function_chain->invalid_constexpr.
(check_for_uninitialized_const_var): Likewise.
(maybe_save_function_definition): Check it.
* parser.c (cp_parser_jump_statement): Set
cp_function_chain->invalid_constexpr.
(cp_parser_asm_definition): Likewise.

From-SVN: r217663

13 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/parser.c
gcc/testsuite/g++.dg/cpp0x/constexpr-diag5.C
gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C
gcc/testsuite/g++.dg/cpp0x/constexpr-function2.C
gcc/testsuite/g++.dg/cpp0x/constexpr-neg1.C
gcc/testsuite/g++.dg/cpp1y/constexpr-incr1.C [new file with mode: 0644]
gcc/tree-inline.c
gcc/tree-inline.h

index d661ec12cf67a50d36227fbb7ee4fa0c1b1756ab..1b5d8a0be4e2bb3770333fd4b219ef050c207329 100644 (file)
@@ -1,3 +1,8 @@
+2014-11-17  Jason Merrill  <jason@redhat.com>
+
+       * tree-inline.c (copy_fn): New.
+       * tree-inline.h: Declare it.
+
 2014-11-17  Alan Lawrence  <alan.lawrence@arm.com>
 
        * config/aarch64/aarch64-builtins.c (TYPES_CREATE): Remove.
index 42521c9b767b94d2754093f52d19735e2d2251e5..ae347d8b7301d452052d291b48e64326a13b6719 100644 (file)
@@ -1,5 +1,50 @@
 2014-11-17  Jason Merrill  <jason@redhat.com>
 
+       C++14 constexpr support (minus loops and multiple returns)
+       * constexpr.c (use_new_call): New macro.
+       (build_data_member_initialization): Ignore non-mem-inits.
+       (check_constexpr_bind_expr_vars): Remove C++14 checks.
+       (constexpr_fn_retval): Likewise.
+       (check_constexpr_ctor_body): Do nothing in C++14.
+       (massage_constexpr_body): In C++14 only collect mem-inits.
+       (get_function_named_in_call): Handle null CALL_EXPR_FN.
+       (cxx_bind_parameters_in_call): Build bindings in same order as
+       parameters.  Don't treat iniviref parms specially in new call mode.
+       (cxx_eval_call_expression): If use_new_call, do constexpr expansion
+       based on DECL_SAVED_TREE rather than the massaged constexpr body.
+       Set up ctx->object from AGGR_INIT_EXPR_SLOT if we don't have one.
+       (is_sub_constant_expr): Don't mess with ctx.ctor here.
+       (cxx_eval_component_reference): A null element means we're mid-
+       initialization.
+       (cxx_eval_store_expression, cxx_eval_increment_expression): New.
+       (cxx_eval_constant_expression): Handle RESULT_DECL, DECL_EXPR,
+       MODIFY_EXPR, STATEMENT_LIST, BIND_EXPR, USING_STMT,
+       PREINCREMENT_EXPR, POSTINCREMENT_EXPR, PREDECREMENT_EXPR,
+       POSTDECREMENT_EXPR.  Don't look into DECL_INITIAL of variables in
+       constexpr functions.  In new-call mode find parms in the values table.
+       (potential_constant_expression_1): Handle null CALL_EXPR_FN.
+       Handle STATEMENT_LIST, MODIFY_EXPR, MODOP_EXPR, IF_STMT,
+       PREINCREMENT_EXPR, POSTINCREMENT_EXPR, PREDECREMENT_EXPR,
+       POSTDECREMENT_EXPR, BIND_EXPR, WITH_CLEANUP_EXPR,
+       CLEANUP_POINT_EXPR, MUST_NOT_THROW_EXPR, TRY_CATCH_EXPR,
+       EH_SPEC_BLOCK, EXPR_STMT, DECL_EXPR, CASE_LABEL_EXPR, BREAK_STMT,
+       CONTINUE_STMT, USING_STMT, IF_STMT, DO_STMT, FOR_STMT, WHILE_STMT,
+       SWITCH_STMT, ASM_EXPR.
+       (cxx_eval_vec_init_1): Call build_aggr_init_expr.
+       (cxx_eval_indirect_ref): Don't return a CONSTRUCTOR when the
+       caller wants an lvalue.
+       (cxx_eval_outermost_constant_expr): Pull object out of AGGR_INIT_EXPR.
+       (maybe_constant_init): Look through INIT_EXPR.
+       (ensure_literal_type_for_constexpr_object): Set
+       cp_function_chain->invalid_constexpr.
+       * cp-tree.h (struct language_function): Add invalid_constexpr bitfield.
+       * decl.c (start_decl): Set cp_function_chain->invalid_constexpr.
+       (check_for_uninitialized_const_var): Likewise.
+       (maybe_save_function_definition): Check it.
+       * parser.c (cp_parser_jump_statement): Set
+       cp_function_chain->invalid_constexpr.
+       (cp_parser_asm_definition): Likewise.
+
        PR c++/52282
        * decl.c (build_ptrmemfunc_type): Don't build a different
        RECORD_TYPE for a qualified PMF.
index 66d356f2416aaf8f3a874857f99a5e6f92cc20ae..57d0c465d5f20338b5e69d71507621e505683b34 100644 (file)
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "gimplify.h"
 #include "builtins.h"
+#include "tree-inline.h"
 
 static bool verify_constant (tree, bool, bool *, bool *);
 #define VERIFY_CONSTANT(X)                                             \
@@ -93,8 +94,11 @@ ensure_literal_type_for_constexpr_object (tree decl)
            error ("the type %qT of constexpr variable %qD is not literal",
                   type, decl);
          else
-           error ("variable %qD of non-literal type %qT in %<constexpr%> "
-                  "function", decl, type);
+           {
+             error ("variable %qD of non-literal type %qT in %<constexpr%> "
+                    "function", decl, type);
+             cp_function_chain->invalid_constexpr = true;
+           }
          explain_non_literal_class (type);
          return NULL;
        }
@@ -310,13 +314,20 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)
   if (TREE_CODE (t) == CONVERT_EXPR)
     t = TREE_OPERAND (t, 0);
   if (TREE_CODE (t) == INIT_EXPR
-      || TREE_CODE (t) == MODIFY_EXPR)
+      /* vptr initialization shows up as a MODIFY_EXPR.  In C++14 we only
+        use what this function builds for cx_check_missing_mem_inits, and
+        assignment in the ctor body doesn't count.  */
+      || (cxx_dialect < cxx14 && TREE_CODE (t) == MODIFY_EXPR))
     {
       member = TREE_OPERAND (t, 0);
       init = break_out_target_exprs (TREE_OPERAND (t, 1));
     }
   else if (TREE_CODE (t) == CALL_EXPR)
     {
+      tree fn = get_callee_fndecl (t);
+      if (!fn || !DECL_CONSTRUCTOR_P (fn))
+       /* We're only interested in calls to subobject constructors.  */
+       return true;
       member = CALL_EXPR_ARG (t, 0);
       /* We don't use build_cplus_new here because it complains about
         abstract bases.  Leaving the call unwrapped means that it has the
@@ -325,13 +336,9 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec)
     }
   else if (TREE_CODE (t) == BIND_EXPR)
     return build_data_member_initialization (BIND_EXPR_BODY (t), vec);
-  else if (TREE_CODE (t) == DECL_EXPR
-          || TREE_CODE (t) == USING_STMT)
-    /* Declaring a temporary, don't add it to the CONSTRUCTOR.
-       Likewise for using directives.  */
-    return true;
   else
-    gcc_unreachable ();
+    /* Don't add anything else to the CONSTRUCTOR.  */
+    return true;
   if (INDIRECT_REF_P (member))
     member = TREE_OPERAND (member, 0);
   if (TREE_CODE (member) == NOP_EXPR)
@@ -390,9 +397,6 @@ check_constexpr_bind_expr_vars (tree t)
 {
   gcc_assert (TREE_CODE (t) == BIND_EXPR);
 
-  if (cxx_dialect >= cxx14)
-    return true;
-
   for (tree var = BIND_EXPR_VARS (t); var; var = DECL_CHAIN (var))
     if (TREE_CODE (var) == TYPE_DECL
        && DECL_IMPLICIT_TYPEDEF_P (var))
@@ -410,8 +414,6 @@ check_constexpr_ctor_body_1 (tree last, tree list)
     case DECL_EXPR:
       if (TREE_CODE (DECL_EXPR_DECL (list)) == USING_DECL)
        return true;
-      if (cxx_dialect >= cxx14)
-       return true;
       return false;
 
     case CLEANUP_POINT_EXPR:
@@ -440,6 +442,10 @@ check_constexpr_ctor_body_1 (tree last, tree list)
 bool
 check_constexpr_ctor_body (tree last, tree list, bool complain)
 {
+  /* C++14 doesn't require a constexpr ctor to have an empty body.  */
+  if (cxx_dialect >= cxx14)
+    return true;
+
   bool ok = true;
   if (TREE_CODE (list) == STATEMENT_LIST)
     {
@@ -612,8 +618,6 @@ constexpr_fn_retval (tree body)
     case DECL_EXPR:
       if (TREE_CODE (DECL_EXPR_DECL (body)) == USING_DECL)
        return NULL_TREE;
-      if (cxx_dialect >= cxx14)
-       return NULL_TREE;
       return error_mark_node;
 
     case CLEANUP_POINT_EXPR:
@@ -642,7 +646,7 @@ massage_constexpr_body (tree fun, tree body)
   if (DECL_CONSTRUCTOR_P (fun))
     body = build_constexpr_constructor_member_initializers
       (DECL_CONTEXT (fun), body);
-  else
+  else if (cxx_dialect < cxx14)
     {
       if (TREE_CODE (body) == EH_SPEC_BLOCK)
         body = EH_SPEC_STMTS (body);
@@ -936,7 +940,7 @@ get_function_named_in_call (tree t)
       gcc_unreachable();
       break;
     }
-  if (TREE_CODE (fun) == ADDR_EXPR
+  if (fun && TREE_CODE (fun) == ADDR_EXPR
       && TREE_CODE (TREE_OPERAND (fun, 0)) == FUNCTION_DECL)
     fun = TREE_OPERAND (fun, 0);
   return fun;
@@ -1016,6 +1020,10 @@ adjust_temp_type (tree type, tree temp)
   return cp_fold_convert (type, temp);
 }
 
+/* True if we want to use the new handling of constexpr calls based on
+   DECL_SAVED_TREE.  Currently only active for C++14 mode.  */
+#define use_new_call (cxx_dialect >= cxx14)
+
 /* Subroutine of cxx_eval_call_expression.
    We are processing a call expression (either CALL_EXPR or
    AGGR_INIT_EXPR) in the context of CTX.  Evaluate
@@ -1032,6 +1040,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
   tree fun = new_call->fundef->decl;
   tree parms = DECL_ARGUMENTS (fun);
   int i;
+  tree *p = &new_call->bindings;
   for (i = 0; i < nargs; ++i)
     {
       tree x, arg;
@@ -1039,19 +1048,19 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
       x = get_nth_callarg (t, i);
       /* For member function, the first argument is a pointer to the implied
          object.  For a constructor, it might still be a dummy object, in
-         which case we get the real argument from ctx or the AGGR_INIT_EXPR. */
+         which case we get the real argument from ctx. */
       if (i == 0 && DECL_CONSTRUCTOR_P (fun)
          && is_dummy_object (x))
        {
          x = ctx->object;
-         if (!x)
-           x = AGGR_INIT_EXPR_SLOT (t);
          x = cp_build_addr_expr (x, tf_warning_or_error);
        }
-      if (parms && DECL_BY_REFERENCE (parms))
+      if (parms && DECL_BY_REFERENCE (parms) && !use_new_call)
        {
          /* cp_genericize made this a reference for argument passing, but
-            we don't want to treat it like one for constexpr evaluation.  */
+            we don't want to treat it like one for C++11 constexpr
+            evaluation.  C++14 constexpr evaluation uses the genericized
+            DECL_SAVED_TREE.  */
          gcc_assert (TREE_CODE (type) == REFERENCE_TYPE);
          gcc_assert (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE);
          type = TREE_TYPE (type);
@@ -1073,7 +1082,8 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
       /* Make sure the binding has the same type as the parm.  */
       if (TREE_CODE (type) != REFERENCE_TYPE)
        arg = adjust_temp_type (type, arg);
-      new_call->bindings = tree_cons (parms, arg, new_call->bindings);
+      *p = build_tree_list (parms, arg);
+      p = &TREE_CHAIN (*p);
     next:
       parms = TREE_CHAIN (parms);
     }
@@ -1205,6 +1215,20 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
           return t;
         }
     }
+
+  constexpr_ctx new_ctx = *ctx;
+  if (DECL_CONSTRUCTOR_P (fun) && !ctx->object
+      && TREE_CODE (t) == AGGR_INIT_EXPR)
+    {
+      /* We want to have an initialization target for an AGGR_INIT_EXPR.
+        If we don't already have one in CTX, use the AGGR_INIT_EXPR_SLOT.  */
+      new_ctx.object = AGGR_INIT_EXPR_SLOT (t);
+      tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL);
+      CONSTRUCTOR_NO_IMPLICIT_ZERO (ctor) = true;
+      ctx->values->put (new_ctx.object, ctor);
+      ctx = &new_ctx;
+    }
+
   cxx_bind_parameters_in_call (ctx, t, &new_call,
                               allow_non_constant, non_constant_p, overflow_p);
   if (*non_constant_p)
@@ -1251,18 +1275,91 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
       result = entry->result;
       if (!result || result == error_mark_node)
        {
-         constexpr_ctx new_ctx = *ctx;
-         new_ctx.call = &new_call;
-         result = (cxx_eval_constant_expression
-                   (&new_ctx, new_call.fundef->body,
-                    allow_non_constant, addr,
-                    non_constant_p, overflow_p));
+         if (!use_new_call)
+           {
+             new_ctx.call = &new_call;
+             result = (cxx_eval_constant_expression
+                       (&new_ctx, new_call.fundef->body,
+                        allow_non_constant, addr,
+                        non_constant_p, overflow_p));
+           }
+         else
+           {
+             if (DECL_SAVED_TREE (fun) == NULL_TREE
+                 && (DECL_CONSTRUCTOR_P (fun) || DECL_DESTRUCTOR_P (fun)))
+               /* The maybe-in-charge 'tor had its DECL_SAVED_TREE
+                  cleared, try the first clone.  */
+               fun = DECL_CHAIN (fun);
+             gcc_assert (DECL_SAVED_TREE (fun));
+             tree parms, res;
+
+             /* Unshare the whole function body.  */
+             tree body = copy_fn (fun, parms, res);
+
+             /* Associate the bindings with the remapped parms.  */
+             tree bound = new_call.bindings;
+             tree remapped = parms;
+             while (bound)
+               {
+                 tree oparm = TREE_PURPOSE (bound);
+                 tree arg = TREE_VALUE (bound);
+                 gcc_assert (DECL_NAME (remapped) == DECL_NAME (oparm));
+                 ctx->values->put (remapped, arg);
+                 bound = TREE_CHAIN (bound);
+                 remapped = DECL_CHAIN (remapped);
+               }
+             /* Add the RESULT_DECL to the values map, too.  */
+             tree slot = NULL_TREE;
+             if (DECL_BY_REFERENCE (res))
+               {
+                 slot = AGGR_INIT_EXPR_SLOT (t);
+                 tree addr = build_address (slot);
+                 addr = build_nop (TREE_TYPE (res), addr);
+                 ctx->values->put (res, addr);
+                 ctx->values->put (slot, NULL_TREE);
+               }
+             else
+               ctx->values->put (res, NULL_TREE);
+
+             cxx_eval_constant_expression (ctx, body, allow_non_constant,
+                                           addr, non_constant_p, overflow_p);
+
+             if (VOID_TYPE_P (TREE_TYPE (res)))
+               /* This can be null for a subobject constructor call, in
+                  which case what we care about is the initialization
+                  side-effects rather than the value.  We could get at the
+                  value by evaluating *this, but we don't bother; there's
+                  no need to put such a call in the hash table.  */
+               result = addr ? ctx->object : ctx->ctor;
+             else
+               {
+                 result = *ctx->values->get (slot ? slot : res);
+                 if (result == NULL_TREE)
+                   {
+                     if (!allow_non_constant)
+                       error ("constexpr call flows off the end "
+                              "of the function");
+                     *non_constant_p = true;
+                   }
+               }
+
+             /* Remove the parms/result from the values map.  Is it worth
+                bothering to do this when the map itself is only live for
+                one constexpr evaluation?  If so, maybe also clear out
+                other vars from call, maybe in BIND_EXPR handling?  */
+             ctx->values->remove (res);
+             if (slot)
+               ctx->values->remove (slot);
+             for (tree parm = parms; parm; parm = TREE_CHAIN (parm))
+               ctx->values->remove (parm);
+           }
        }
+
       if (result == error_mark_node)
        *non_constant_p = true;
       if (*non_constant_p)
        entry->result = result = error_mark_node;
-      else
+      else if (result)
        {
          /* If this was a call to initialize an object, set the type of
             the CONSTRUCTOR to the type of that object.  */
@@ -1277,6 +1374,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
            }
          entry->result = result;
        }
+      else
+       result = void_node;
     }
 
   pop_cx_call_context ();
@@ -1537,7 +1636,13 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value)
     {
       if (field == part)
-        return value;
+       {
+         if (value)
+           return value;
+         else
+           /* We're in the middle of initializing it.  */
+           break;
+       }
     }
   if (TREE_CODE (TREE_TYPE (whole)) == UNION_TYPE
       && CONSTRUCTOR_NELTS (whole) > 0)
@@ -1903,6 +2008,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
                                        &argvec, elttype, LOOKUP_NORMAL,
                                        tf_warning_or_error);
       release_tree_vector (argvec);
+      init = build_aggr_init_expr (TREE_TYPE (init), init);
       pre_init = true;
     }
 
@@ -2219,7 +2325,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
   /* If we're pulling out the value of an empty base, make sure
      that the whole object is constant and then return an empty
      CONSTRUCTOR.  */
-  if (empty_base)
+  if (empty_base && !addr)
     {
       VERIFY_CONSTANT (r);
       r = build_constructor (TREE_TYPE (t), NULL);
@@ -2317,9 +2423,163 @@ var_in_constexpr_fn (tree t)
          && DECL_DECLARED_CONSTEXPR_P (ctx));
 }
 
+/* Evaluate an INIT_EXPR or MODIFY_EXPR.  */
+
+static tree
+cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
+                          bool allow_non_constant, bool addr,
+                          bool *non_constant_p, bool *overflow_p)
+{
+  constexpr_ctx new_ctx = *ctx;
+
+  /* First we figure out where we're storing to.  */
+  tree target = TREE_OPERAND (t, 0);
+  target = cxx_eval_constant_expression (ctx, target,
+                                        allow_non_constant, true,
+                                        non_constant_p, overflow_p);
+  if (*non_constant_p)
+    return t;
+
+  /* And then find the underlying variable.  */
+  vec<tree,va_gc> *refs = make_tree_vector();
+  tree object = NULL_TREE;
+  for (tree probe = target; object == NULL_TREE; )
+    {
+      switch (TREE_CODE (probe))
+       {
+       case BIT_FIELD_REF:
+       case COMPONENT_REF:
+       case ARRAY_REF:
+         vec_safe_push (refs, TREE_OPERAND (probe, 1));
+         vec_safe_push (refs, TREE_TYPE (probe));
+         probe = TREE_OPERAND (probe, 0);
+         break;
+
+       default:
+         object = probe;
+         gcc_assert (DECL_P (object));
+       }
+    }
+
+  /* And then find/build up our initializer for the path to the subobject
+     we're initializing.  */
+  tree *valp = ctx->values->get (object);
+  if (!valp)
+    {
+      /* A constant-expression cannot modify objects from outside the
+        constant-expression.  */
+      if (!allow_non_constant)
+       error ("modification of %qD is not a constant-expression", object);
+      *non_constant_p = true;
+      return t;
+    }
+  tree type = TREE_TYPE (object);
+  while (!refs->is_empty())
+    {
+      if (*valp == NULL_TREE)
+       {
+         *valp = build_constructor (type, NULL);
+         CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp) = true;
+       }
+
+      constructor_elt ce;
+      type = refs->pop();
+      ce.index = refs->pop();
+      ce.value = NULL_TREE;
+
+      unsigned HOST_WIDE_INT idx = 0;
+      constructor_elt *cep = NULL;
+      for (idx = 0;
+          vec_safe_iterate (CONSTRUCTOR_ELTS (*valp), idx, &cep);
+          idx++)
+       /* ??? slow */
+       if (cp_tree_equal (ce.index, cep->index))
+         break;
+      if (!cep)
+       cep = vec_safe_push (CONSTRUCTOR_ELTS (*valp), ce);
+      valp = &cep->value;
+    }
+  release_tree_vector (refs);
+
+  if ((AGGREGATE_TYPE_P (TREE_TYPE (t)) || VECTOR_TYPE_P (TREE_TYPE (t))))
+    {
+      /* Create a new CONSTRUCTOR in case evaluation of the initializer
+        wants to modify it.  */
+      *valp = new_ctx.ctor = build_constructor (TREE_TYPE (t), NULL);
+      CONSTRUCTOR_NO_IMPLICIT_ZERO (new_ctx.ctor) = true;
+      new_ctx.object = target;
+    }
+
+  tree init = cxx_eval_constant_expression (&new_ctx, TREE_OPERAND (t, 1),
+                                           allow_non_constant, false,
+                                           non_constant_p, overflow_p);
+  if (target == object)
+    /* The hash table might have moved since the get earlier.  */
+    ctx->values->put (object, init);
+  else
+    *valp = init;
+
+  if (*non_constant_p)
+    return t;
+  else if (addr)
+    return target;
+  else
+    return *valp;
+}
+
+/* Evaluate a ++ or -- expression.  */
+
+static tree
+cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
+                             bool allow_non_constant, bool addr,
+                             bool *non_constant_p, bool *overflow_p)
+{
+  enum tree_code code = TREE_CODE (t);
+  tree type = TREE_TYPE (t);
+  tree op = TREE_OPERAND (t, 0);
+  tree offset = TREE_OPERAND (t, 1);
+  gcc_assert (TREE_CONSTANT (offset));
+
+  /* The operand as an lvalue.  */
+  op = cxx_eval_constant_expression (ctx, op, allow_non_constant, true,
+                                    non_constant_p, overflow_p);
+
+  /* The operand as an rvalue.  */
+  tree val = rvalue (op);
+  val = cxx_eval_constant_expression (ctx, val, allow_non_constant, false,
+                                     non_constant_p, overflow_p);
+  VERIFY_CONSTANT (val);
+
+  /* The modified value.  */
+  bool inc = (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR);
+  tree mod = fold_build2 (inc ? PLUS_EXPR : MINUS_EXPR,
+                         type, val, offset);
+  VERIFY_CONSTANT (mod);
+
+  /* Storing the modified value.  */
+  tree store = build2 (MODIFY_EXPR, type, op, mod);
+  cxx_eval_constant_expression (ctx, store, allow_non_constant,
+                               true, non_constant_p, overflow_p);
+
+  /* And the value of the expression.  */
+  if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
+    {
+      /* Prefix ops are lvalues.  */
+      if (addr)
+       return op;
+      else
+       /* But we optimize when the caller wants an rvalue.  */
+       return mod;
+    }
+  else
+    /* Postfix ops are rvalues.  */
+    return val;
+}
+
 /* Attempt to reduce the expression T to a constant value.
    On failure, issue diagnostic and return error_mark_node.  */
 /* FIXME unify with c_fully_fold */
+/* FIXME overflow_p is too global */
 
 static tree
 cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
@@ -2348,6 +2608,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 
   switch (TREE_CODE (t))
     {
+    case RESULT_DECL:
+      if (addr)
+       return t;
+      /* We ask for an rvalue for the RESULT_DECL when indirecting
+        through an invisible reference.  */
+      gcc_assert (DECL_BY_REFERENCE (t));
+      return (*ctx->values->get (t));
+
     case VAR_DECL:
       if (addr)
        return t;
@@ -2357,11 +2625,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       if (TREE_CODE (r) == TARGET_EXPR
          && TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
        r = TARGET_EXPR_INITIAL (r);
-      if (TREE_CODE (r) == VAR_DECL && var_in_constexpr_fn (r)
-         && DECL_INITIAL (r))
-       r = cxx_eval_constant_expression (ctx, DECL_INITIAL (r),
-                                         allow_non_constant, false,
-                                         non_constant_p, overflow_p);
       if (TREE_CODE (r) == VAR_DECL)
        if (tree *p = ctx->values->get (r))
          r = *p;
@@ -2379,8 +2642,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       return t;
 
     case PARM_DECL:
-      if (ctx && ctx->call && DECL_CONTEXT (t) == ctx->call->fundef->decl)
+      if (!use_new_call && ctx
+         && ctx->call && DECL_CONTEXT (t) == ctx->call->fundef->decl)
        r = lookup_parameter_binding (ctx->call, t);
+      else if (addr && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
+       /* glvalue use.  */;
+      else if (tree *p = ctx->values->get (r))
+       r = *p;
       else if (addr)
        /* Defer in case this is only used for its type.  */;
       else
@@ -2397,6 +2665,34 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                                    non_constant_p, overflow_p);
       break;
 
+    case DECL_EXPR:
+      {
+       r = DECL_EXPR_DECL (t);
+       if (AGGREGATE_TYPE_P (TREE_TYPE (r))
+           || VECTOR_TYPE_P (TREE_TYPE (r)))
+         {
+           new_ctx = *ctx;
+           new_ctx.object = r;
+           new_ctx.ctor = build_constructor (TREE_TYPE (r), NULL);
+           CONSTRUCTOR_NO_IMPLICIT_ZERO (new_ctx.ctor) = true;
+           new_ctx.values->put (r, new_ctx.ctor);
+           ctx = &new_ctx;
+         }
+
+       if (tree init = DECL_INITIAL (r))
+         {
+           init = cxx_eval_constant_expression (ctx, init,
+                                                allow_non_constant, false,
+                                                non_constant_p, overflow_p);
+           ctx->values->put (r, init);
+         }
+       else if (ctx == &new_ctx)
+         /* We gave it a CONSTRUCTOR above.  */;
+       else
+         ctx->values->put (r, NULL_TREE);
+      }
+      break;
+
     case TARGET_EXPR:
       if (!literal_type_p (TREE_TYPE (t)))
        {
@@ -2421,9 +2717,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
          ctx->values->put (new_ctx.object, new_ctx.ctor);
          ctx = &new_ctx;
        }
-      /* else fall through.  */
-    case INIT_EXPR:
-      /* Pass false for 'addr' because these codes indicate
+      /* Pass false for 'addr' because this indicates
         initialization of a temporary.  */
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
                                        allow_non_constant, false,
@@ -2433,6 +2727,22 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        r = adjust_temp_type (TREE_TYPE (t), r);
       break;
 
+    case INIT_EXPR:
+      if (!use_new_call)
+       {
+         /* In C++11 constexpr evaluation we are looking for the value,
+            not the side-effect of the initialization.  */
+         r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
+                                           allow_non_constant, false,
+                                           non_constant_p, overflow_p);
+         break;
+       }
+      /* else fall through */
+    case MODIFY_EXPR:
+      r = cxx_eval_store_expression (ctx, t, allow_non_constant, addr,
+                                    non_constant_p, overflow_p);
+      break;
+
     case SCOPE_REF:
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
                                        allow_non_constant, addr,
@@ -2445,6 +2755,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case CLEANUP_POINT_EXPR:
     case MUST_NOT_THROW_EXPR:
     case SAVE_EXPR:
+    case EXPR_STMT:
+    case EH_SPEC_BLOCK:
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
                                        allow_non_constant, addr,
                                        non_constant_p, overflow_p);
@@ -2679,27 +2991,47 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
         used, and they can't do anything with it, so just return it.  */
       return t;
 
-    case LAMBDA_EXPR:
+    case STATEMENT_LIST:
+      {
+       new_ctx = *ctx;
+       new_ctx.ctor = new_ctx.object = NULL_TREE;
+       tree_stmt_iterator i;
+       for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
+         {
+           cxx_eval_constant_expression (&new_ctx, tsi_stmt (i),
+                                         allow_non_constant, false,
+                                         non_constant_p, overflow_p);
+           if (*non_constant_p)
+             break;
+         }
+      }
+      break;
+
+    case BIND_EXPR:
+      return cxx_eval_constant_expression (ctx, BIND_EXPR_BODY (t),
+                                          allow_non_constant, addr,
+                                          non_constant_p, overflow_p);
+
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
     case PREDECREMENT_EXPR:
     case POSTDECREMENT_EXPR:
+      return cxx_eval_increment_expression (ctx, t, allow_non_constant,
+                                           addr, non_constant_p, overflow_p);
+
+    case LAMBDA_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 STATEMENT_LIST:
-    case BIND_EXPR:
     case NON_DEPENDENT_EXPR:
     case BASELINK:
-    case EXPR_STMT:
     case OFFSET_REF:
       if (!allow_non_constant)
         error_at (EXPR_LOC_OR_LOC (t, input_location),
@@ -2730,6 +3062,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        }
       break;
 
+    case GOTO_EXPR:
+    case LOOP_EXPR:
+    case SWITCH_EXPR:
+      if (!allow_non_constant)
+       sorry ("%qs in constant expression", get_tree_code_name (TREE_CODE (t)));
+      *non_constant_p = true;
+      break;
+
     default:
       internal_error ("unexpected expression %qE of kind %s", t,
                      get_tree_code_name (TREE_CODE (t)));
@@ -2768,8 +3108,13 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
         initialized.  */
       ctx.ctor = build_constructor (type, NULL);
       CONSTRUCTOR_NO_IMPLICIT_ZERO (ctx.ctor) = true;
-      if (!object && TREE_CODE (t) == TARGET_EXPR)
-       object = TARGET_EXPR_SLOT (t);
+      if (!object)
+       {
+         if (TREE_CODE (t) == TARGET_EXPR)
+           object = TARGET_EXPR_SLOT (t);
+         else if (TREE_CODE (t) == AGGR_INIT_EXPR)
+           object = AGGR_INIT_EXPR_SLOT (t);
+       }
       ctx.object = object;
       if (object)
        gcc_assert (same_type_ignoring_top_level_qualifiers_p
@@ -2859,13 +3204,6 @@ is_sub_constant_expr (tree t)
   constexpr_ctx ctx = { NULL, NULL, NULL, NULL };
   hash_map <tree, tree> map;
   ctx.values = &map;
-  tree type = initialized_type (t);
-  if ((AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
-      && TREE_CODE (t) != TARGET_EXPR)
-    {
-      ctx.ctor = build_constructor (type, NULL);
-      CONSTRUCTOR_NO_IMPLICIT_ZERO (ctx.ctor) = true;
-    }
   cxx_eval_constant_expression (&ctx, t, true, false, &non_constant_p,
                                &overflow_p);
   return !non_constant_p && !overflow_p;
@@ -2996,6 +3334,8 @@ maybe_constant_init (tree t, tree decl)
   if (TREE_CODE (t) == CONVERT_EXPR
       && VOID_TYPE_P (TREE_TYPE (t)))
     t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == INIT_EXPR)
+    t = TREE_OPERAND (t, 1);
   t = maybe_constant_value (t, decl);
   if (TREE_CODE (t) == TARGET_EXPR)
     {
@@ -3078,6 +3418,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
     case TEMPLATE_ID_EXPR:
     case LABEL_DECL:
     case LABEL_EXPR:
+    case CASE_LABEL_EXPR:
     case CONST_DECL:
     case SIZEOF_EXPR:
     case ALIGNOF_EXPR:
@@ -3091,7 +3432,10 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
     case FIELD_DECL:
     case PARM_DECL:
     case USING_DECL:
+    case USING_STMT:
     case PLACEHOLDER_EXPR:
+    case BREAK_STMT:
+    case CONTINUE_STMT:
       return true;
 
     case AGGR_INIT_EXPR:
@@ -3103,6 +3447,14 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
         const int nargs = call_expr_nargs (t);
        i = 0;
 
+       if (fun == NULL_TREE)
+         {
+           /* fold_call_expr can't do anything with IFN calls.  */
+           if (flags & tf_error)
+             error_at (EXPR_LOC_OR_LOC (t, input_location),
+                       "call to internal function");
+           return false;
+         }
        if (is_overloaded_fn (fun))
          {
            if (TREE_CODE (fun) == FUNCTION_DECL)
@@ -3266,20 +3618,85 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
        return potential_constant_expression_1 (x, rval, flags);
       }
 
+    case STATEMENT_LIST:
+      {
+       tree_stmt_iterator i;
+       for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
+         {
+           if (!potential_constant_expression_1 (tsi_stmt (i), any, flags))
+             return false;
+         }
+       return true;
+      }
+      break;
+
+    case MODIFY_EXPR:
+      if (cxx_dialect < cxx14)
+       goto fail;
+      if (!potential_constant_expression_1 (TREE_OPERAND (t, 0), any, flags))
+       return false;
+      if (!potential_constant_expression_1 (TREE_OPERAND (t, 1), rval, flags))
+       return false;
+      return true;
+
+    case MODOP_EXPR:
+      if (cxx_dialect < cxx14)
+       goto fail;
+      if (!potential_constant_expression_1 (TREE_OPERAND (t, 0), rval, flags))
+       return false;
+      if (!potential_constant_expression_1 (TREE_OPERAND (t, 2), rval, flags))
+       return false;
+      return true;
+
+    case IF_STMT:
+      if (!potential_constant_expression_1 (IF_COND (t), rval, flags))
+       return false;
+      if (!potential_constant_expression_1 (THEN_CLAUSE (t), any, flags))
+       return false;
+      if (!potential_constant_expression_1 (ELSE_CLAUSE (t), any, flags))
+       return false;
+      return true;
+
+    case DO_STMT:
+      if (!potential_constant_expression_1 (DO_COND (t), rval, flags))
+       return false;
+      if (!potential_constant_expression_1 (DO_BODY (t), any, flags))
+       return false;
+      return true;
+
+    case FOR_STMT:
+      if (!potential_constant_expression_1 (FOR_INIT_STMT (t), any, flags))
+       return false;
+      if (!potential_constant_expression_1 (FOR_COND (t), rval, flags))
+       return false;
+      if (!potential_constant_expression_1 (FOR_EXPR (t), any, flags))
+       return false;
+      if (!potential_constant_expression_1 (FOR_BODY (t), any, flags))
+       return false;
+      return true;
+
+    case WHILE_STMT:
+      if (!potential_constant_expression_1 (WHILE_COND (t), rval, flags))
+       return false;
+      if (!potential_constant_expression_1 (WHILE_BODY (t), any, flags))
+       return false;
+      return true;
+
+    case SWITCH_STMT:
+      if (!potential_constant_expression_1 (SWITCH_STMT_COND (t), rval, flags))
+       return false;
+      if (!potential_constant_expression_1 (SWITCH_STMT_BODY (t), any, flags))
+       return false;
+      return true;
+
     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:
     case OMP_ATOMIC:
     case OMP_ATOMIC_READ:
     case OMP_ATOMIC_CAPTURE_OLD:
@@ -3287,22 +3704,10 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
       /* 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:
-      /* 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:
     case TRANSACTION_EXPR:
-    case IF_STMT:
-    case DO_STMT:
-    case FOR_STMT:
-    case WHILE_STMT:
-    case DECL_EXPR:
+    case ASM_EXPR:
+    fail:
       if (flags & tf_error)
         error ("expression %qE is not a constant-expression", t);
       return false;
@@ -3355,6 +3760,14 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
       want_rval = true;
       goto binary;
 
+    case PREINCREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      if (cxx_dialect < cxx14)
+       goto fail;
+      goto unary;
+
     case BIT_NOT_EXPR:
       /* A destructor.  */
       if (TYPE_P (TREE_OPERAND (t, 0)))
@@ -3372,6 +3785,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
     case TRUTH_NOT_EXPR:
     case FIXED_CONVERT_EXPR:
     case UNARY_PLUS_EXPR:
+    unary:
       return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval,
                                              flags);
 
@@ -3396,7 +3810,18 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
              (TREE_OPERAND (t, 0),
               TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE, flags));
 
+    case BIND_EXPR:
+      return potential_constant_expression_1 (BIND_EXPR_BODY (t),
+                                             want_rval, flags);
+
+    case WITH_CLEANUP_EXPR:
+    case CLEANUP_POINT_EXPR:
+    case MUST_NOT_THROW_EXPR:
+    case TRY_CATCH_EXPR:
+    case EH_SPEC_BLOCK:
+    case EXPR_STMT:
     case PAREN_EXPR:
+    case DECL_EXPR:
     case NON_DEPENDENT_EXPR:
       /* For convenience.  */
     case RETURN_EXPR:
index 54f7e9b863396c7342974e8c118204e3222b86f6..adc8aa72d973b4c1582f715d79008c18a6e80dfa 100644 (file)
@@ -1182,6 +1182,8 @@ struct GTY(()) language_function {
   /* True if this function can throw an exception.  */
   BOOL_BITFIELD can_throw : 1;
 
+  BOOL_BITFIELD invalid_constexpr : 1;
+
   hash_table<named_label_hasher> *x_named_labels;
   cp_binding_level *bindings;
   vec<tree, va_gc> *x_local_names;
index 1f22c265b8c93fa37e9ae555a5a6a4bf0c2b8a04..47da0ca4eccb424249ef03b1b17336ec05b06042 100644 (file)
@@ -4779,11 +4779,16 @@ start_decl (const cp_declarator *declarator,
   if (current_function_decl && VAR_P (decl)
       && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
     {
+      bool ok = false;
       if (DECL_THREAD_LOCAL_P (decl))
        error ("%qD declared %<thread_local%> in %<constexpr%> function",
               decl);
       else if (TREE_STATIC (decl))
        error ("%qD declared %<static%> in %<constexpr%> function", decl);
+      else
+       ok = true;
+      if (!ok)
+       cp_function_chain->invalid_constexpr = true;
     }
 
   if (!processing_template_decl && VAR_P (decl))
@@ -5165,9 +5170,12 @@ check_for_uninitialized_const_var (tree decl)
        permerror (DECL_SOURCE_LOCATION (decl),
                   "uninitialized const %qD", decl);
       else
-       error_at (DECL_SOURCE_LOCATION (decl),
-                 "uninitialized variable %qD in %<constexpr%> function",
-                 decl);
+       {
+         error_at (DECL_SOURCE_LOCATION (decl),
+                   "uninitialized variable %qD in %<constexpr%> function",
+                   decl);
+         cp_function_chain->invalid_constexpr = true;
+       }
 
       if (CLASS_TYPE_P (type))
        {
@@ -13995,6 +14003,7 @@ maybe_save_function_definition (tree fun)
 {
   if (!processing_template_decl
       && DECL_DECLARED_CONSTEXPR_P (fun)
+      && !cp_function_chain->invalid_constexpr
       && !DECL_CLONED_FUNCTION_P (fun))
     register_constexpr_fundef (fun, DECL_SAVED_TREE (fun));
 }
index 111ec1090b8b785625af084b07d999fda30d762c..3eff5fad862159b7d57cf62bf6f4e1700c496290 100644 (file)
@@ -11004,7 +11004,10 @@ cp_parser_jump_statement (cp_parser* parser)
     case RID_GOTO:
       if (parser->in_function_body
          && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
-       error ("%<goto%> in %<constexpr%> function");
+       {
+         error ("%<goto%> in %<constexpr%> function");
+         cp_function_chain->invalid_constexpr = true;
+       }
 
       /* Create the goto-statement.  */
       if (cp_lexer_next_token_is (parser->lexer, CPP_MULT))
@@ -16588,7 +16591,10 @@ cp_parser_asm_definition (cp_parser* parser)
 
   if (parser->in_function_body
       && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
-    error ("%<asm%> in %<constexpr%> function");
+    {
+      error ("%<asm%> in %<constexpr%> function");
+      cp_function_chain->invalid_constexpr = true;
+    }
 
   /* See if the next token is `volatile'.  */
   if (cp_parser_allow_gnu_extensions_p (parser)
index c8043e3bdb4ffe26a85987d7d8faec9001c14e02..708f5f2b3f82abff55c45ae0e3892b09150d3e07 100644 (file)
@@ -23,20 +23,20 @@ struct C
 
 struct D
 {
-    constexpr D() { return;} // { dg-error "does not have empty body" }
+    constexpr D() { return;} // { dg-error "does not have empty body" "" { target c++11_only } }
 };
 
 struct D1
 {
     A a;
-    constexpr D1() { return;} // { dg-error "does not have empty body" }
+    constexpr D1() { return;} // { dg-error "does not have empty body" "" { target c++11_only } }
 };
 
 struct D2
 {
     A a;
     A b;
-    constexpr D2() { return;} // { dg-error "does not have empty body" }
+    constexpr D2() { return;} // { dg-error "does not have empty body" "" { target c++11_only } }
 };
 
 struct D3
@@ -44,5 +44,5 @@ struct D3
     A a;
     A b;
     A c;
-    constexpr D3() { return;} // { dg-error "does not have empty body" }
+    constexpr D3() { return;} // { dg-error "does not have empty body" "" { target c++11_only } }
 };
index 55a2329eb54ce01be733b970665f4d81e50b8186..85dfca4ff1db266b1285c0f28fa293bdf05fa928 100644 (file)
@@ -12,12 +12,14 @@ template <class T>
 struct C
 {
   friend constexpr int f(C) { return 0; }
-  friend constexpr int g(C, A) { return 0; } // { dg-error "double" }
+  friend constexpr int g(C, A) { return 0; }
   constexpr int m(C) { return 0; }
-  constexpr int m(A) { return 0; } // { dg-error "double" }
+  constexpr int m(A) { return 0; }
 };
 
 constexpr int i = f(C<int>());
 constexpr int j = C<int>().m(C<int>());
-constexpr int k = C<double>().m(A()); // { dg-error "constexpr" }
-constexpr int l = g(C<double>(),A()); // { dg-error "constexpr" }
+constexpr int k = C<double>().m(A()); // { dg-error "" }
+constexpr int l = g(C<double>(),A()); // { dg-error "" }
+
+// { dg-prune-output "parameter" }
index 8cb32c9ad94257cd1608215ca9b4f6e4ae6897d9..8c51c9ddd257931688389213cb77f0003607adff 100644 (file)
@@ -27,14 +27,14 @@ constexpr void f(int x)       // { dg-error "return type .void" }
 { /* ... */ }
 
 constexpr int prev(int x)
-{ return --x; }               // { dg-error "--" }
+{ return --x; }               // { dg-error "--" "" { target c++11_only } }
 
 constexpr int g(int x, int n) // error: body not just ‘‘return expr’’
 {
    int r = 1;
    while (--n > 0) r *= x;
    return r;
-} // { dg-error "not a return-statement" }
+} // { dg-error "not a return-statement" "" { target c++11_only } }
 
 constexpr int
 bar(int x, int y) { return x + y + x * y; } // { dg-message "previously" }
index fb4c01274d9962555e6bd4dc6e37ead4153023c9..35f5e8e94f44e4c6858bf86f47d2156041ba63ff 100644 (file)
@@ -33,14 +33,14 @@ constexpr void f(int x)             // { dg-error "void" }
 { /* ... */ }
 // error: use of decrement
 constexpr int prev(int x)
-{ return --x; }                        // { dg-error "-- x" }
+{ return --x; }                        // { dg-error "-- x" "" { target c++11_only } }
 
 // error: body not just return expr
 constexpr int g(int x, int n) {
   int r = 1;
   while (--n > 0) r *= x;
   return r;
-} // { dg-error "body of constexpr function" }
+} // { dg-error "body of constexpr function" "" { target c++11_only } }
 
 class debug_flag {
 public:
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-incr1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-incr1.C
new file mode 100644 (file)
index 0000000..2b099c8
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++14 } }
+
+constexpr int f (int i)
+{
+  ++i;
+  int x = i;
+  ++x;
+  return x;
+}
+
+constexpr int i = f(42);
+#define SA(X) static_assert((X),#X)
+SA(i==44);
index 510b53ee41654c069e579d5a029b27b1d0541fe7..4b937ca8daa2ee13ecb6ed054ab4e677b655d027 100644 (file)
@@ -5817,3 +5817,55 @@ build_duplicate_type (tree type)
 
   return type;
 }
+
+/* Unshare the entire DECL_SAVED_TREE of FN and return the remapped
+   parameters and RESULT_DECL in PARMS and RESULT.  Used by C++ constexpr
+   evaluation.  */
+
+tree
+copy_fn (tree fn, tree& parms, tree& result)
+{
+  copy_body_data id;
+  tree param;
+  hash_map<tree, tree> decl_map;
+
+  tree *p = &parms;
+  *p = NULL_TREE;
+
+  memset (&id, 0, sizeof (id));
+  id.src_fn = fn;
+  id.dst_fn = current_function_decl;
+  id.src_cfun = DECL_STRUCT_FUNCTION (fn);
+  id.decl_map = &decl_map;
+
+  id.copy_decl = copy_decl_no_change;
+  id.transform_call_graph_edges = CB_CGE_DUPLICATE;
+  id.transform_new_cfg = false;
+  id.transform_return_to_modify = false;
+  id.transform_parameter = true;
+  id.transform_lang_insert_block = NULL;
+
+  /* Make sure not to unshare trees behind the front-end's back
+     since front-end specific mechanisms may rely on sharing.  */
+  id.regimplify = false;
+  id.do_not_unshare = true;
+
+  /* We're not inside any EH region.  */
+  id.eh_lp_nr = 0;
+
+  /* Remap the parameters and result and return them to the caller.  */
+  for (param = DECL_ARGUMENTS (fn);
+       param;
+       param = DECL_CHAIN (param))
+    {
+      *p = remap_decl (param, &id);
+      p = &DECL_CHAIN (*p);
+    }
+
+  if (DECL_RESULT (fn))
+    result = remap_decl (DECL_RESULT (fn), &id);
+  else
+    result = NULL_TREE;
+
+  return copy_tree_body (&id);
+}
index 9eb75c7fc9657f70912b4e580c8c59d3f00bb8e5..9d70e3efce91db66ef5787f08a6e1f318b36ce4a 100644 (file)
@@ -209,6 +209,7 @@ extern tree remap_decl (tree decl, copy_body_data *id);
 extern tree remap_type (tree type, copy_body_data *id);
 extern gimple_seq copy_gimple_seq_and_replace_locals (gimple_seq seq);
 extern bool debug_find_tree (tree, tree);
+extern tree copy_fn (tree, tree&, tree&);
 
 /* This is in tree-inline.c since the routine uses
    data structures from the inliner.  */