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:
parent
a09c81b4ba
commit
4eb24e0109
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
107
gcc/cp/call.c
107
gcc/cp/call.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
14
gcc/cp/pt.c
14
gcc/cp/pt.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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" ) ;
|
||||
}
|
|
@ -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>();
|
||||
}
|
Loading…
Reference in New Issue