P0145R2: Refining Expression Order for C++.

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
This commit is contained in:
Jason Merrill 2016-06-14 16:18:34 -04:00 committed by Jason Merrill
parent a09c81b4ba
commit 4eb24e0109
14 changed files with 403 additions and 40 deletions

View 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> 2016-06-13 Jakub Jelinek <jakub@redhat.com>
PR sanitizer/71498 PR sanitizer/71498

View File

@ -910,6 +910,12 @@ c_common_post_options (const char **pfilename)
else if (warn_narrowing == -1) else if (warn_narrowing == -1)
warn_narrowing = 0; 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. */ /* Global sized deallocation is new in C++14. */
if (flag_sized_deallocation == -1) if (flag_sized_deallocation == -1)
flag_sized_deallocation = (cxx_dialect >= cxx14); flag_sized_deallocation = (cxx_dialect >= cxx14);

View File

@ -1043,6 +1043,14 @@ falt-external-templates
C++ ObjC++ Ignore Warn(switch %qs is no longer supported) C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
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 fasm
C ObjC C++ ObjC++ Var(flag_no_asm, 0) C ObjC C++ ObjC++ Var(flag_no_asm, 0)
Recognize the \"asm\" keyword. Recognize the \"asm\" keyword.

View 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> 2016-06-14 Jakub Jelinek <jakub@redhat.com>
PR c++/71528 PR c++/71528

View 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 static tree
build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1, 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) 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 else
result = build_over_call (cand, LOOKUP_NORMAL, complain); result = build_over_call (cand, LOOKUP_NORMAL, complain);
if (processing_template_decl if (trivial_fn_p (cand->fn))
&& result != NULL_TREE /* There won't be a CALL_EXPR. */;
&& result != error_mark_node else if (result && result != error_mark_node)
&& DECL_HIDDEN_FRIEND_P (cand->fn))
{ {
tree call = result; tree call = extract_call_expr (result);
if (REFERENCE_REF_P (call)) CALL_EXPR_OPERATOR_SYNTAX (call) = true;
call = TREE_OPERAND (call, 0);
/* This prevents build_new_function_call from discarding this if (processing_template_decl && DECL_HIDDEN_FRIEND_P (cand->fn))
function during instantiation of the enclosing template. */ /* This prevents build_new_function_call from discarding this
KOENIG_LOOKUP_P (call) = 1; 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 else
@ -5846,6 +5896,25 @@ build_new_op (location_t loc, enum tree_code code, int flags,
return ret; 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 /* Returns true if FN has two parameters, of which the second has type
size_t. */ size_t. */
@ -7533,10 +7602,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
} }
/* Ellipsis */ /* Ellipsis */
int magic = magic_varargs_p (fn);
for (; arg_index < vec_safe_length (args); ++arg_index) for (; arg_index < vec_safe_length (args); ++arg_index)
{ {
tree a = (*args)[arg_index]; tree a = (*args)[arg_index];
int magic = magic_varargs_p (fn);
if (magic == 2) if (magic == 2)
{ {
/* Do no conversions for certain magic varargs. */ /* 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)) if (is_really_empty_class (type))
{ {
/* Avoid copying empty classes. */ /* Avoid copying empty classes. */
val = build2 (COMPOUND_EXPR, void_type_node, to, arg); val = build2 (COMPOUND_EXPR, type, arg, to);
TREE_NO_WARNING (val) = 1;
val = build2 (COMPOUND_EXPR, type, val, to);
TREE_NO_WARNING (val) = 1; TREE_NO_WARNING (val) = 1;
} }
else if (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (as_base))) 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); tree call = build_cxx_call (fn, nargs, argarray, complain|decltype_flag);
if (TREE_CODE (call) == CALL_EXPR if (call != error_mark_node
&& (cand->flags & LOOKUP_LIST_INIT_CTOR)) && !magic
CALL_EXPR_LIST_INIT_P (call) = true; && (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; return call;
} }

View File

@ -565,6 +565,7 @@ int
cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
{ {
int saved_stmts_are_full_exprs_p = 0; 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 tree_code code = TREE_CODE (*expr_p);
enum gimplify_status ret; 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); cilk_cp_gimplify_call_params_in_spawned_fn (expr_p, pre_p, post_p);
return (enum gimplify_status) gimplify_cilk_spawn (expr_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; ret = GS_OK;
if (PUSH_ARGS_REVERSED && CALL_EXPR_LIST_INIT_P (*expr_p) if (!CALL_EXPR_FN (*expr_p))
&& call_expr_nargs (*expr_p) > 2) /* Internal function call. */;
else if (CALL_EXPR_REVERSE_ARGS (*expr_p))
{ {
int nargs = call_expr_nargs (*expr_p); /* This is a call to a (compound) assignment operator that used
location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location); the operator syntax; gimplify the RHS first. */
for (int i = 1; i < nargs; ++i) 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 enum gimplify_status t
= gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p, loc); = 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; 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; break;
case RETURN_EXPR: case RETURN_EXPR:

View File

@ -179,19 +179,21 @@ operator == (const cp_expr &lhs, tree rhs)
IDENTIFIER_CTOR_OR_DTOR_P (in IDENTIFIER_NODE) IDENTIFIER_CTOR_OR_DTOR_P (in IDENTIFIER_NODE)
BIND_EXPR_BODY_BLOCK (in BIND_EXPR) BIND_EXPR_BODY_BLOCK (in BIND_EXPR)
DECL_NON_TRIVIALLY_INITIALIZED_P (in VAR_DECL) 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, 4: TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
or FIELD_DECL). CALL_EXPR, or FIELD_DECL).
IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE) IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE)
DECL_TINFO_P (in VAR_DECL) DECL_TINFO_P (in VAR_DECL)
FUNCTION_REF_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) FUNCTION_REF_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
5: C_IS_RESERVED_WORD (in IDENTIFIER_NODE) 5: C_IS_RESERVED_WORD (in IDENTIFIER_NODE)
DECL_VTABLE_OR_VTT_P (in VAR_DECL) DECL_VTABLE_OR_VTT_P (in VAR_DECL)
FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) 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) 6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE)
DECL_CONSTRUCTION_VTABLE_P (in VAR_DECL) DECL_CONSTRUCTION_VTABLE_P (in VAR_DECL)
TYPE_MARKED_P (in _TYPE) TYPE_MARKED_P (in _TYPE)
RANGE_FOR_IVDEP (in RANGE_FOR_STMT) RANGE_FOR_IVDEP (in RANGE_FOR_STMT)
CALL_EXPR_OPERATOR_SYNTAX (in CALL_EXPR, AGGR_INIT_EXPR)
Usage of TYPE_LANG_FLAG_?: Usage of TYPE_LANG_FLAG_?:
0: TYPE_DEPENDENT_P 0: TYPE_DEPENDENT_P
@ -3379,6 +3381,9 @@ extern void decl_shadowed_for_var_insert (tree, tree);
#define DELETE_EXPR_USE_VEC(NODE) \ #define DELETE_EXPR_USE_VEC(NODE) \
TREE_LANG_FLAG_1 (DELETE_EXPR_CHECK (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 /* Indicates that this is a non-dependent COMPOUND_EXPR which will
resolve to a function call. */ resolve to a function call. */
#define COMPOUND_EXPR_OVERLOADED(NODE) \ #define COMPOUND_EXPR_OVERLOADED(NODE) \
@ -3388,9 +3393,20 @@ extern void decl_shadowed_for_var_insert (tree, tree);
should be performed at instantiation time. */ should be performed at instantiation time. */
#define KOENIG_LOOKUP_P(NODE) TREE_LANG_FLAG_0 (CALL_EXPR_CHECK (NODE)) #define KOENIG_LOOKUP_P(NODE) TREE_LANG_FLAG_0 (CALL_EXPR_CHECK (NODE))
/* True if CALL_EXPR expresses list-initialization of an object. */ /* True if the arguments to NODE should be evaluated in left-to-right
#define CALL_EXPR_LIST_INIT_P(NODE) \ order regardless of PUSH_ARGS_REVERSED. */
TREE_LANG_FLAG_3 (TREE_CHECK2 ((NODE),CALL_EXPR,AGGR_INIT_EXPR)) #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 /* Indicates whether a string literal has been parenthesized. Such
usages are disallowed in certain circumstances. */ 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 null_member_pointer_value_p (tree);
extern bool sufficient_parms_p (const_tree); extern bool sufficient_parms_p (const_tree);
extern tree type_decays_to (tree); extern tree type_decays_to (tree);
extern tree extract_call_expr (tree);
extern tree build_user_type_conversion (tree, tree, int, extern tree build_user_type_conversion (tree, tree, int,
tsubst_flags_t); tsubst_flags_t);
extern tree build_new_function_call (tree, vec<tree, va_gc> **, bool, extern tree build_new_function_call (tree, vec<tree, va_gc> **, bool,

View File

@ -16652,6 +16652,20 @@ tsubst_copy_and_build (tree t,
release_tree_vector (call_args); 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); RETURN (ret);
} }

View File

@ -4057,8 +4057,11 @@ simplify_aggr_init_expr (tree *tp)
aggr_init_expr_nargs (aggr_init_expr), aggr_init_expr_nargs (aggr_init_expr),
AGGR_INIT_EXPR_ARGP (aggr_init_expr)); AGGR_INIT_EXPR_ARGP (aggr_init_expr));
TREE_NOTHROW (call_expr) = TREE_NOTHROW (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_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) if (style == ctor)
{ {

View File

@ -524,7 +524,9 @@ build_aggr_init_expr (tree type, tree init)
TREE_SIDE_EFFECTS (rval) = 1; TREE_SIDE_EFFECTS (rval) = 1;
AGGR_INIT_VIA_CTOR_P (rval) = is_ctor; AGGR_INIT_VIA_CTOR_P (rval) = is_ctor;
TREE_NOTHROW (rval) = TREE_NOTHROW (init); 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 else
rval = init; rval = init;
@ -2854,8 +2856,7 @@ build_min_non_dep_op_overload (enum tree_code op,
tree fn, call; tree fn, call;
vec<tree, va_gc> *args; vec<tree, va_gc> *args;
if (REFERENCE_REF_P (non_dep)) non_dep = extract_call_expr (non_dep);
non_dep = TREE_OPERAND (non_dep, 0);
nargs = call_expr_nargs (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); call = build_min_non_dep_call_vec (non_dep, fn, args);
release_tree_vector (args); release_tree_vector (args);
tree call_expr = call; tree call_expr = extract_call_expr (call);
if (REFERENCE_REF_P (call_expr))
call_expr = TREE_OPERAND (call_expr, 0);
KOENIG_LOOKUP_P (call_expr) = KOENIG_LOOKUP_P (non_dep); 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; return call;
} }

View File

@ -189,7 +189,8 @@ in the following sections.
@item C++ Language Options @item C++ Language Options
@xref{C++ Dialect Options,,Options Controlling C++ Dialect}. @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 -fconstexpr-depth=@var{n} -ffriend-injection @gol
-fno-elide-constructors @gol -fno-elide-constructors @gol
-fno-enforce-eh-specs @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 Turn off all access checking. This switch is mainly useful for working
around bugs in the access control code. 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 @item -fcheck-new
@opindex fcheck-new @opindex fcheck-new
Check that the pointer returned by @code{operator new} is non-null Check that the pointer returned by @code{operator new} is non-null

View File

@ -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));
}

View File

@ -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" ) ;
}

View File

@ -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>();
}