P0145R2: Refining Expression Order for C++.
authorJason Merrill <jason@redhat.com>
Tue, 14 Jun 2016 20:18:34 +0000 (16:18 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 14 Jun 2016 20:18:34 +0000 (16:18 -0400)
gcc/c-family/
* c.opt (fargs-in-order): New.
* c-opts.c (c_common_post_options): Adjust flag_args_in_order.
gcc/cp/
* cp-tree.h (CALL_EXPR_OPERATOR_SYNTAX, CALL_EXPR_ORDERED_ARGS)
(CALL_EXPR_REVERSE_ARGS): New.
* call.c (build_new_op_1): Set them.
(extract_call_expr, op_is_ordered): New.
(build_over_call): Set CALL_EXPR_ORDERED_ARGS.
* cp-gimplify.c (cp_gimplify_expr) [CALL_EXPR]: Handle new flags.
* pt.c (tsubst_copy_and_build): Copy new flags.
* semantics.c (simplify_aggr_init_expr): Likewise.
* tree.c (build_aggr_init_expr): Likewise.
(build_min_non_dep_op_overload): Likewise.

From-SVN: r237459

14 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-opts.c
gcc/c-family/c.opt
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-gimplify.c
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/doc/invoke.texi
gcc/testsuite/g++.dg/cpp1z/eval-order1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/eval-order2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/eval-order3.C [new file with mode: 0644]

index a3e1fd8958bed3887fc8bcf5b4cc6341517a7491..08302e1c5bd153cf3472da9870d872376b79945c 100644 (file)
@@ -1,3 +1,9 @@
+2016-06-14  Jason Merrill  <jason@redhat.com>
+
+       P0145R2: Refining Expression Order for C++.
+       * c.opt (fargs-in-order): New.
+       * c-opts.c (c_common_post_options): Adjust flag_args_in_order.
+
 2016-06-13  Jakub Jelinek  <jakub@redhat.com>
 
        PR sanitizer/71498
index fec58bcf91f454af36dd048a97d3ad8a87d9a3ec..ff6339c44b67d0e07a63d1035283f935c83e752b 100644 (file)
@@ -910,6 +910,12 @@ c_common_post_options (const char **pfilename)
   else if (warn_narrowing == -1)
     warn_narrowing = 0;
 
+  /* C++17 requires that function arguments be evaluated left-to-right even on
+     PUSH_ARGS_REVERSED targets.  */
+  if (c_dialect_cxx ()
+      && flag_args_in_order == -1)
+    flag_args_in_order = 2 /*(cxx_dialect >= cxx1z) ? 2 : 0*/;
+
   /* Global sized deallocation is new in C++14.  */
   if (flag_sized_deallocation == -1)
     flag_sized_deallocation = (cxx_dialect >= cxx14);
index 761a83bcfb38b86ab22a3f0dbe1c0c6c43b3a64b..83fd84ccc0f506a9cdb53ff9ce9cef6931132ce6 100644 (file)
@@ -1043,6 +1043,14 @@ falt-external-templates
 C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
 No longer supported.
 
+fargs-in-order
+C++ ObjC++ Alias(fargs-in-order=, 2, 0)
+Always evaluate function arguments in left-to-right order.
+
+fargs-in-order=
+C++ ObjC++ Var(flag_args_in_order) Joined UInteger Init(-1)
+Always evaluate function arguments in left-to-right order.
+
 fasm
 C ObjC C++ ObjC++ Var(flag_no_asm, 0)
 Recognize the \"asm\" keyword.
index cd5996bdd1d4a01f04b004a085a7c5ecd37fcb8b..54e934af572b4e4606e164f4ed59dfddc6ce6a48 100644 (file)
@@ -1,3 +1,17 @@
+2016-06-14  Jason Merrill  <jason@redhat.com>
+
+       P0145R2: Refining Expression Order for C++.
+       * cp-tree.h (CALL_EXPR_OPERATOR_SYNTAX, CALL_EXPR_ORDERED_ARGS)
+       (CALL_EXPR_REVERSE_ARGS): New.
+       * call.c (build_new_op_1): Set them.
+       (extract_call_expr, op_is_ordered): New.
+       (build_over_call): Set CALL_EXPR_ORDERED_ARGS.
+       * cp-gimplify.c (cp_gimplify_expr) [CALL_EXPR]: Handle new flags.
+       * pt.c (tsubst_copy_and_build): Copy new flags.
+       * semantics.c (simplify_aggr_init_expr): Likewise.
+       * tree.c (build_aggr_init_expr): Likewise.
+       (build_min_non_dep_op_overload): Likewise.
+
 2016-06-14  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/71528
index 729b7eb4ba3c8810c16771f29bed3e8ae52212b0..e2b89b8a2c44ac620a89d4c75d61dda6b10da1d4 100644 (file)
@@ -5372,6 +5372,40 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args,
     }
 }
 
+/* Returns 1 if P0145R2 says that the LHS of operator CODE is evaluated first,
+   -1 if the RHS is evaluated first, or 0 if the order is unspecified.  */
+
+static int
+op_is_ordered (tree_code code)
+{
+  if (!flag_args_in_order)
+    return 0;
+
+  switch (code)
+    {
+      // 5. b @= a
+    case MODIFY_EXPR:
+      return -1;
+
+      // 1. a.b
+      // Not overloadable (yet).
+      // 2. a->b
+      // Only one argument.
+      // 3. a->*b
+    case MEMBER_REF:
+      // 6. a[b]
+    case ARRAY_REF:
+      // 7. a << b
+    case LSHIFT_EXPR:
+      // 8. a >> b
+    case RSHIFT_EXPR:
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
 static tree
 build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
                tree arg2, tree arg3, tree *overload, tsubst_flags_t complain)
@@ -5660,17 +5694,33 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
          else
            result = build_over_call (cand, LOOKUP_NORMAL, complain);
 
-         if (processing_template_decl
-             && result != NULL_TREE
-             && result != error_mark_node
-             && DECL_HIDDEN_FRIEND_P (cand->fn))
+         if (trivial_fn_p (cand->fn))
+           /* There won't be a CALL_EXPR.  */;
+         else if (result && result != error_mark_node)
            {
-             tree call = result;
-             if (REFERENCE_REF_P (call))
-               call = TREE_OPERAND (call, 0);
-             /* This prevents build_new_function_call from discarding this
-                function during instantiation of the enclosing template.  */
-             KOENIG_LOOKUP_P (call) = 1;
+             tree call = extract_call_expr (result);
+             CALL_EXPR_OPERATOR_SYNTAX (call) = true;
+
+             if (processing_template_decl && DECL_HIDDEN_FRIEND_P (cand->fn))
+               /* This prevents build_new_function_call from discarding this
+                  function during instantiation of the enclosing template.  */
+               KOENIG_LOOKUP_P (call) = 1;
+
+             /* Specify evaluation order as per P0145R2.  */
+             CALL_EXPR_ORDERED_ARGS (call) = false;
+             switch (op_is_ordered (code))
+               {
+               case -1:
+                 CALL_EXPR_REVERSE_ARGS (call) = true;
+                 break;
+
+               case 1:
+                 CALL_EXPR_ORDERED_ARGS (call) = true;
+                 break;
+
+               default:
+                 break;
+               }
            }
        }
       else
@@ -5846,6 +5896,25 @@ build_new_op (location_t loc, enum tree_code code, int flags,
   return ret;
 }
 
+/* CALL was returned by some call-building function; extract the actual
+   CALL_EXPR from any bits that have been tacked on, e.g. by
+   convert_from_reference.  */
+
+tree
+extract_call_expr (tree call)
+{
+  while (TREE_CODE (call) == COMPOUND_EXPR)
+    call = TREE_OPERAND (call, 1);
+  if (REFERENCE_REF_P (call))
+    call = TREE_OPERAND (call, 0);
+  if (TREE_CODE (call) == TARGET_EXPR)
+    call = TARGET_EXPR_INITIAL (call);
+  gcc_assert (TREE_CODE (call) == CALL_EXPR
+             || TREE_CODE (call) == AGGR_INIT_EXPR
+             || call == error_mark_node);
+  return call;
+}
+
 /* Returns true if FN has two parameters, of which the second has type
    size_t.  */
 
@@ -7533,10 +7602,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
     }
 
   /* Ellipsis */
+  int magic = magic_varargs_p (fn);
   for (; arg_index < vec_safe_length (args); ++arg_index)
     {
       tree a = (*args)[arg_index];
-      int magic = magic_varargs_p (fn);
       if (magic == 2)
        {
          /* Do no conversions for certain magic varargs.  */
@@ -7666,9 +7735,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       if (is_really_empty_class (type))
        {
          /* Avoid copying empty classes.  */
-         val = build2 (COMPOUND_EXPR, void_type_node, to, arg);
-         TREE_NO_WARNING (val) = 1;
-         val = build2 (COMPOUND_EXPR, type, val, to);
+         val = build2 (COMPOUND_EXPR, type, arg, to);
          TREE_NO_WARNING (val) = 1;
        }
       else if (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (as_base)))
@@ -7756,9 +7823,15 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
     }
 
   tree call = build_cxx_call (fn, nargs, argarray, complain|decltype_flag);
-  if (TREE_CODE (call) == CALL_EXPR
-      && (cand->flags & LOOKUP_LIST_INIT_CTOR))
-    CALL_EXPR_LIST_INIT_P (call) = true;
+  if (call != error_mark_node
+      && !magic
+      && (flag_args_in_order > 1
+         || (cand->flags & LOOKUP_LIST_INIT_CTOR)))
+    {
+      tree c = extract_call_expr (call);
+      /* build_new_op_1 will clear this when appropriate.  */
+      CALL_EXPR_ORDERED_ARGS (c) = true;
+    }
   return call;
 }
 
index dcb0fa6215be684115be345f806477aa3c5c862b..97b043acbf293ba959340c0b97747e1cf361a26c 100644 (file)
@@ -565,6 +565,7 @@ int
 cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 {
   int saved_stmts_are_full_exprs_p = 0;
+  location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location);
   enum tree_code code = TREE_CODE (*expr_p);
   enum gimplify_status ret;
 
@@ -752,18 +753,26 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
          cilk_cp_gimplify_call_params_in_spawned_fn (expr_p, pre_p, post_p);
          return (enum gimplify_status) gimplify_cilk_spawn (expr_p);
        }
-      /* DR 1030 says that we need to evaluate the elements of an
-        initializer-list in forward order even when it's used as arguments to
-        a constructor.  So if the target wants to evaluate them in reverse
-        order and there's more than one argument other than 'this', gimplify
-        them in order.  */
       ret = GS_OK;
-      if (PUSH_ARGS_REVERSED && CALL_EXPR_LIST_INIT_P (*expr_p)
-         && call_expr_nargs (*expr_p) > 2)
+      if (!CALL_EXPR_FN (*expr_p))
+       /* Internal function call.  */;
+      else if (CALL_EXPR_REVERSE_ARGS (*expr_p))
        {
-         int nargs = call_expr_nargs (*expr_p);
-         location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location);
-         for (int i = 1; i < nargs; ++i)
+         /* This is a call to a (compound) assignment operator that used
+            the operator syntax; gimplify the RHS first.  */
+         gcc_assert (call_expr_nargs (*expr_p) == 2);
+         gcc_assert (!CALL_EXPR_ORDERED_ARGS (*expr_p));
+         enum gimplify_status t
+           = gimplify_arg (&CALL_EXPR_ARG (*expr_p, 1), pre_p, loc);
+         if (t == GS_ERROR)
+           ret = GS_ERROR;
+       }
+      else if (CALL_EXPR_ORDERED_ARGS (*expr_p))
+       {
+         /* Leave the last argument for gimplify_call_expr, to avoid problems
+            with __builtin_va_arg_pack().  */
+         int nargs = call_expr_nargs (*expr_p) - 1;
+         for (int i = 0; i < nargs; ++i)
            {
              enum gimplify_status t
                = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p, loc);
@@ -771,6 +780,22 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
                ret = GS_ERROR;
            }
        }
+      else if (flag_args_in_order == 1
+              && !CALL_EXPR_OPERATOR_SYNTAX (*expr_p))
+       {
+         /* If flag_args_in_order == 1, we don't force an order on all
+            function arguments, but do evaluate the object argument first.  */
+         tree fntype = TREE_TYPE (CALL_EXPR_FN (*expr_p));
+         if (POINTER_TYPE_P (fntype))
+           fntype = TREE_TYPE (fntype);
+         if (TREE_CODE (fntype) == METHOD_TYPE)
+           {
+             enum gimplify_status t
+               = gimplify_arg (&CALL_EXPR_ARG (*expr_p, 0), pre_p, loc);
+             if (t == GS_ERROR)
+               ret = GS_ERROR;
+           }
+       }
       break;
 
     case RETURN_EXPR:
index 14ba12073eec85bb5180eebca3c9ebf294184729..6c6ad10804eb54b32436d0e5710fd7c231a4f7b2 100644 (file)
@@ -179,19 +179,21 @@ operator == (const cp_expr &lhs, tree rhs)
       IDENTIFIER_CTOR_OR_DTOR_P (in IDENTIFIER_NODE)
       BIND_EXPR_BODY_BLOCK (in BIND_EXPR)
       DECL_NON_TRIVIALLY_INITIALIZED_P (in VAR_DECL)
-      CALL_EXPR_LIST_INIT_P (in CALL_EXPR, AGGR_INIT_EXPR)
+      CALL_EXPR_ORDERED_ARGS (in CALL_EXPR, AGGR_INIT_EXPR)
    4: TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
-         or FIELD_DECL).
+         CALL_EXPR, or FIELD_DECL).
       IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE)
       DECL_TINFO_P (in VAR_DECL)
       FUNCTION_REF_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
    5: C_IS_RESERVED_WORD (in IDENTIFIER_NODE)
       DECL_VTABLE_OR_VTT_P (in VAR_DECL)
       FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
+      CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR)
    6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE)
       DECL_CONSTRUCTION_VTABLE_P (in VAR_DECL)
       TYPE_MARKED_P (in _TYPE)
       RANGE_FOR_IVDEP (in RANGE_FOR_STMT)
+      CALL_EXPR_OPERATOR_SYNTAX (in CALL_EXPR, AGGR_INIT_EXPR)
 
    Usage of TYPE_LANG_FLAG_?:
    0: TYPE_DEPENDENT_P
@@ -3379,6 +3381,9 @@ extern void decl_shadowed_for_var_insert (tree, tree);
 #define DELETE_EXPR_USE_VEC(NODE) \
   TREE_LANG_FLAG_1 (DELETE_EXPR_CHECK (NODE))
 
+#define CALL_OR_AGGR_INIT_CHECK(NODE) \
+  TREE_CHECK2 ((NODE), CALL_EXPR, AGGR_INIT_EXPR)
+
 /* Indicates that this is a non-dependent COMPOUND_EXPR which will
    resolve to a function call.  */
 #define COMPOUND_EXPR_OVERLOADED(NODE) \
@@ -3388,9 +3393,20 @@ extern void decl_shadowed_for_var_insert (tree, tree);
    should be performed at instantiation time.  */
 #define KOENIG_LOOKUP_P(NODE) TREE_LANG_FLAG_0 (CALL_EXPR_CHECK (NODE))
 
-/* True if CALL_EXPR expresses list-initialization of an object.  */
-#define CALL_EXPR_LIST_INIT_P(NODE) \
-  TREE_LANG_FLAG_3 (TREE_CHECK2 ((NODE),CALL_EXPR,AGGR_INIT_EXPR))
+/* True if the arguments to NODE should be evaluated in left-to-right
+   order regardless of PUSH_ARGS_REVERSED.  */
+#define CALL_EXPR_ORDERED_ARGS(NODE) \
+  TREE_LANG_FLAG_3 (CALL_OR_AGGR_INIT_CHECK (NODE))
+
+/* True if the arguments to NODE should be evaluated in right-to-left
+   order regardless of PUSH_ARGS_REVERSED.  */
+#define CALL_EXPR_REVERSE_ARGS(NODE) \
+  TREE_LANG_FLAG_5 (CALL_OR_AGGR_INIT_CHECK (NODE))
+
+/* True if CALL_EXPR was written as an operator expression, not a function
+   call.  */
+#define CALL_EXPR_OPERATOR_SYNTAX(NODE) \
+  TREE_LANG_FLAG_6 (CALL_OR_AGGR_INIT_CHECK (NODE))
 
 /* Indicates whether a string literal has been parenthesized. Such
    usages are disallowed in certain circumstances.  */
@@ -5542,6 +5558,7 @@ extern bool null_ptr_cst_p                        (tree);
 extern bool null_member_pointer_value_p                (tree);
 extern bool sufficient_parms_p                 (const_tree);
 extern tree type_decays_to                     (tree);
+extern tree extract_call_expr                  (tree);
 extern tree build_user_type_conversion         (tree, tree, int,
                                                 tsubst_flags_t);
 extern tree build_new_function_call            (tree, vec<tree, va_gc> **, bool, 
index 3a3d9b8f4396be0c3593f6bedb4450ea5faec154..11b5d822a351114e39a2aef5e2fa1d5ea03d51f1 100644 (file)
@@ -16652,6 +16652,20 @@ tsubst_copy_and_build (tree t,
 
        release_tree_vector (call_args);
 
+       if (ret != error_mark_node)
+         {
+           bool op = CALL_EXPR_OPERATOR_SYNTAX (t);
+           bool ord = CALL_EXPR_ORDERED_ARGS (t);
+           bool rev = CALL_EXPR_REVERSE_ARGS (t);
+           if (op || ord || rev)
+             {
+               function = extract_call_expr (ret);
+               CALL_EXPR_OPERATOR_SYNTAX (function) = op;
+               CALL_EXPR_ORDERED_ARGS (function) = ord;
+               CALL_EXPR_REVERSE_ARGS (function) = rev;
+             }
+         }
+
        RETURN (ret);
       }
 
index 536509127e4fbd5d4689772872ba00c31b47cfdc..9b0cff8c3107c70857f92bfd9e6a4b11e8a8b54b 100644 (file)
@@ -4057,8 +4057,11 @@ simplify_aggr_init_expr (tree *tp)
                                    aggr_init_expr_nargs (aggr_init_expr),
                                    AGGR_INIT_EXPR_ARGP (aggr_init_expr));
   TREE_NOTHROW (call_expr) = TREE_NOTHROW (aggr_init_expr);
-  CALL_EXPR_LIST_INIT_P (call_expr) = CALL_EXPR_LIST_INIT_P (aggr_init_expr);
   CALL_FROM_THUNK_P (call_expr) = AGGR_INIT_FROM_THUNK_P (aggr_init_expr);
+  CALL_EXPR_OPERATOR_SYNTAX (call_expr)
+    = CALL_EXPR_OPERATOR_SYNTAX (aggr_init_expr);
+  CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (aggr_init_expr);
+  CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (aggr_init_expr);
 
   if (style == ctor)
     {
index abda6e4f7294a488af588e8501d4d16f693bf0f9..9ab964d0b132ef0bf3537e89f5b574f44a660300 100644 (file)
@@ -524,7 +524,9 @@ build_aggr_init_expr (tree type, tree init)
       TREE_SIDE_EFFECTS (rval) = 1;
       AGGR_INIT_VIA_CTOR_P (rval) = is_ctor;
       TREE_NOTHROW (rval) = TREE_NOTHROW (init);
-      CALL_EXPR_LIST_INIT_P (rval) = CALL_EXPR_LIST_INIT_P (init);
+      CALL_EXPR_OPERATOR_SYNTAX (rval) = CALL_EXPR_OPERATOR_SYNTAX (init);
+      CALL_EXPR_ORDERED_ARGS (rval) = CALL_EXPR_ORDERED_ARGS (init);
+      CALL_EXPR_REVERSE_ARGS (rval) = CALL_EXPR_REVERSE_ARGS (init);
     }
   else
     rval = init;
@@ -2854,8 +2856,7 @@ build_min_non_dep_op_overload (enum tree_code op,
   tree fn, call;
   vec<tree, va_gc> *args;
 
-  if (REFERENCE_REF_P (non_dep))
-    non_dep = TREE_OPERAND (non_dep, 0);
+  non_dep = extract_call_expr (non_dep);
 
   nargs = call_expr_nargs (non_dep);
 
@@ -2897,10 +2898,11 @@ build_min_non_dep_op_overload (enum tree_code op,
   call = build_min_non_dep_call_vec (non_dep, fn, args);
   release_tree_vector (args);
 
-  tree call_expr = call;
-  if (REFERENCE_REF_P (call_expr))
-    call_expr = TREE_OPERAND (call_expr, 0);
+  tree call_expr = extract_call_expr (call);
   KOENIG_LOOKUP_P (call_expr) = KOENIG_LOOKUP_P (non_dep);
+  CALL_EXPR_OPERATOR_SYNTAX (call_expr) = true;
+  CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (non_dep);
+  CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (non_dep);
 
   return call;
 }
index 223fd86ac95edb16231e45791207dcab22c4edfe..21053511dedac8bb95a9f6c73a93603b4cd6ff07 100644 (file)
@@ -189,7 +189,8 @@ in the following sections.
 
 @item C++ Language Options
 @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
-@gccoptlist{-fabi-version=@var{n}  -fno-access-control  -fcheck-new @gol
+@gccoptlist{-fabi-version=@var{n}  -fno-access-control @gol
+-fargs-in-order=@var{n} -fcheck-new @gol
 -fconstexpr-depth=@var{n}  -ffriend-injection @gol
 -fno-elide-constructors @gol
 -fno-enforce-eh-specs @gol
@@ -2233,6 +2234,14 @@ option is used for the warning.
 Turn off all access checking.  This switch is mainly useful for working
 around bugs in the access control code.
 
+@item -fargs-in-order
+@opindex fargs-in-order
+Evaluate function arguments and operands of some binary expressions in
+left-to-right order, and evaluate the right side of an assignment
+before the left side, as proposed in P0145R2.  Enabled by default with
+@option{-std=c++1z}.  @option{-fargs-in-order=1} implements all of the
+ordering requirements except function arguments.
+
 @item -fcheck-new
 @opindex fcheck-new
 Check that the pointer returned by @code{operator new} is non-null
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order1.C b/gcc/testsuite/g++.dg/cpp1z/eval-order1.C
new file mode 100644 (file)
index 0000000..278990d
--- /dev/null
@@ -0,0 +1,21 @@
+// P0145R2: Refining Expression Order for C++
+// { dg-do run }
+// { dg-options "-std=c++1z" }
+
+extern "C" int printf (const char *, ...);
+void sink(...) { }
+
+int last = 0;
+int f(int i)
+{
+  if (i < last)
+    __builtin_abort ();
+  last = i;
+  return i;
+}
+
+int main()
+{
+  sink(f(1), f(2));
+  sink(f(3), f(4), f(5));
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order2.C b/gcc/testsuite/g++.dg/cpp1z/eval-order2.C
new file mode 100644 (file)
index 0000000..2a741d6
--- /dev/null
@@ -0,0 +1,15 @@
+// P0145R2: Refining Expression Order for C++
+// { dg-do run }
+// { dg-options "-std=c++1z" }
+
+#include <string>
+#define assert(X) if (!(X)) __builtin_abort();
+
+int main()
+{
+  std::string s = "but I have heard it works even if you don't believe in it" ;
+  s.replace(0, 4, "" ).replace( s.find( "even" ), 4, "only" )
+    .replace( s.find( " don't" ), 6, "" );
+
+  assert( s == "I have heard it works only if you believe in it" ) ;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order3.C b/gcc/testsuite/g++.dg/cpp1z/eval-order3.C
new file mode 100644 (file)
index 0000000..15df903
--- /dev/null
@@ -0,0 +1,150 @@
+// P0145R2: Refining Expression Order for C++
+// { dg-do run }
+// { dg-options "-std=c++1z -fargs-in-order=1" }
+
+extern "C" int printf (const char *, ...);
+void sink(...) { }
+
+int last = 0;
+int f(int i)
+{
+  if (i < last)
+    __builtin_abort ();
+  last = i;
+  return i;
+}
+
+int& g(int i)
+{
+  static int dummy;
+  f(i);
+  return dummy;
+}
+
+struct A
+{
+  int _i;
+  A(int i): _i(f(i)) { }
+  A& memfn(int i, int j) { f(j); return *this; }
+  int operator<<(int i) { }
+  A& operator=(const A&) { return *this; }
+  A& operator+=(int i) { return *this; }
+};
+
+int operator>>(A&, int i) { }
+
+A a(0);
+A* afn(int i)
+{
+  f(i);
+  return &a;
+}
+
+A& aref(int i)
+{
+  f(i);
+  return a;
+}
+
+static int si;
+int* ip (int i)
+{
+  f(i);
+  return &si;
+}
+
+int& iref(int i)
+{
+  f(i);
+  return si;
+}
+
+auto pmff(int i) {
+  f(i);
+  return &A::memfn;
+}
+
+template <class T> void f()
+{
+  // a.b
+  A(1).memfn(f(2),3).memfn(f(4),5);
+  aref(6).memfn(f(7),8);
+  (aref(9).*pmff(10))(f(11),12);
+  last = 0;
+
+  // a->b
+  afn(12)->memfn(f(13),14);
+
+  // a->*b
+  (afn(15)->*pmff(16))(f(17),18);
+  last = 0;
+
+  // a(b)
+  // covered in eval-order1.C
+
+  // b @= a
+  aref(19)=A(18);
+  //iref(21)=f(20);
+  aref(23)+=f(22);
+  last = 0;
+
+  // a[b]
+  afn(20)[f(21)-21].memfn(f(22),23);
+  ip(24)[f(25)-25] = 0;
+  last=0;
+
+  // a << b
+  aref(24) << f(25);
+  iref(26) << f(27);
+  last=0;
+
+  // a >> b
+  aref(26) >> f(27);
+  iref(28) >> f(29);
+}
+
+void g()
+{
+  // a.b
+  A(1).memfn(f(2),3).memfn(f(4),5);
+  aref(6).memfn(f(7),8);
+  (aref(9).*pmff(10))(f(11),12);
+  last = 0;
+
+  // a->b
+  afn(12)->memfn(f(13),14);
+
+  // a->*b
+  (afn(15)->*pmff(16))(f(17),18);
+  last = 0;
+
+  // a(b)
+  // covered in eval-order1.C
+
+  // b @= a
+  aref(19)=A(18);
+  //iref(21)=f(20);
+  aref(23)+=f(22);
+  last = 0;
+
+  // a[b]
+  afn(20)[f(21)-21].memfn(f(22),23);
+  ip(24)[f(25)-25] = 0;
+  last=0;
+
+  // a << b
+  aref(24) << f(25);
+  iref(26) << f(27);
+  last=0;
+
+  // a >> b
+  aref(26) >> f(27);
+  iref(28) >> f(29);
+}
+
+int main()
+{
+  g();
+  last = 0;
+  f<int>();
+}