mirror of git://gcc.gnu.org/git/gcc.git
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>
|
2016-06-13 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
PR sanitizer/71498
|
PR sanitizer/71498
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
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
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
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);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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