+2014-04-11 Jason Merrill <jason@redhat.com>
+
+ DR 1030
+ PR c++/51253
+ * cp-tree.h (CALL_EXPR_LIST_INIT_P): New.
+ * call.c (struct z_candidate): Add flags field.
+ (add_candidate): Add flags parm.
+ (add_function_candidate, add_conv_candidate, build_builtin_candidate)
+ (add_template_candidate_real): Pass it.
+ (build_over_call): Set CALL_EXPR_LIST_INIT_P.
+ * tree.c (build_aggr_init_expr): Copy it.
+ * semantics.c (simplify_aggr_init_expr): Preevaluate args if it's set.
+
2014-04-10 Richard Biener <rguenther@suse.de>
Jakub Jelinek <jakub@redhat.com>
static void maybe_handle_implicit_object (conversion **);
static struct z_candidate *add_candidate
(struct z_candidate **, tree, tree, const vec<tree, va_gc> *, size_t,
- conversion **, tree, tree, int, struct rejection_reason *);
+ conversion **, tree, tree, int, struct rejection_reason *, int);
static tree source_type (conversion *);
static void add_warning (struct z_candidate *, struct z_candidate *);
static bool reference_compatible_p (tree, tree);
sequence from the type returned by FN to the desired destination
type. */
conversion *second_conv;
- int viable;
struct rejection_reason *reason;
/* If FN is a member function, the binfo indicating the path used to
qualify the name of FN at the call site. This path is used to
tree explicit_targs;
candidate_warning *warnings;
z_candidate *next;
+ int viable;
+
+ /* The flags active in add_candidate. */
+ int flags;
};
/* Returns true iff T is a null pointer constant in the sense of
tree fn, tree first_arg, const vec<tree, va_gc> *args,
size_t num_convs, conversion **convs,
tree access_path, tree conversion_path,
- int viable, struct rejection_reason *reason)
+ int viable, struct rejection_reason *reason,
+ int flags)
{
struct z_candidate *cand = (struct z_candidate *)
conversion_obstack_alloc (sizeof (struct z_candidate));
cand->viable = viable;
cand->reason = reason;
cand->next = *candidates;
+ cand->flags = flags;
*candidates = cand;
return cand;
out:
return add_candidate (candidates, fn, orig_first_arg, args, len, convs,
- access_path, conversion_path, viable, reason);
+ access_path, conversion_path, viable, reason, flags);
}
/* Create an overload candidate for the conversion function FN which will
}
return add_candidate (candidates, totype, first_arg, arglist, len, convs,
- access_path, conversion_path, viable, reason);
+ access_path, conversion_path, viable, reason, flags);
}
static void
num_convs, convs,
/*access_path=*/NULL_TREE,
/*conversion_path=*/NULL_TREE,
- viable, reason);
+ viable, reason, flags);
}
static bool
return cand;
fail:
return add_candidate (candidates, tmpl, first_arg, arglist, nargs, NULL,
- access_path, conversion_path, 0, reason);
+ access_path, conversion_path, 0, reason, flags);
}
return error_mark_node;
}
- return 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
+ && (cand->flags & LOOKUP_LIST_INIT_CTOR))
+ CALL_EXPR_LIST_INIT_P (call) = true;
+ return call;
}
/* Build and return a call to FN, using NARGS arguments in ARGARRAY.
FNDECL_USED_AUTO (in FUNCTION_DECL)
DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE)
REF_PARENTHESIZED_P (in COMPONENT_REF, SCOPE_REF)
+ AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR)
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK)
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)
4: TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
or FIELD_DECL).
IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE)
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))
+
/* Indicates whether a string literal has been parenthesized. Such
usages are disallowed in certain circumstances. */
aggr_init_expr_nargs (aggr_init_expr),
AGGR_INIT_EXPR_ARGP (aggr_init_expr));
TREE_NOTHROW (call_expr) = TREE_NOTHROW (aggr_init_expr);
+ tree ret = call_expr;
if (style == ctor)
{
expand_call{,_inline}. */
cxx_mark_addressable (slot);
CALL_EXPR_RETURN_SLOT_OPT (call_expr) = true;
- call_expr = build2 (INIT_EXPR, TREE_TYPE (call_expr), slot, call_expr);
+ ret = build2 (INIT_EXPR, TREE_TYPE (ret), slot, ret);
}
else if (style == pcc)
{
need to copy the returned value out of the static buffer into the
SLOT. */
push_deferring_access_checks (dk_no_check);
- call_expr = build_aggr_init (slot, call_expr,
- DIRECT_BIND | LOOKUP_ONLYCONVERTING,
- tf_warning_or_error);
+ ret = build_aggr_init (slot, ret,
+ DIRECT_BIND | LOOKUP_ONLYCONVERTING,
+ tf_warning_or_error);
pop_deferring_access_checks ();
- call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (slot), call_expr, slot);
+ ret = build2 (COMPOUND_EXPR, TREE_TYPE (slot), ret, slot);
+ }
+
+ /* 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', force
+ pre-evaluation. */
+ if (PUSH_ARGS_REVERSED && CALL_EXPR_LIST_INIT_P (aggr_init_expr)
+ && aggr_init_expr_nargs (aggr_init_expr) > 2)
+ {
+ tree preinit;
+ stabilize_call (call_expr, &preinit);
+ if (preinit)
+ ret = build2 (COMPOUND_EXPR, TREE_TYPE (ret), preinit, ret);
}
if (AGGR_INIT_ZERO_FIRST (aggr_init_expr))
tree init = build_zero_init (type, NULL_TREE,
/*static_storage_p=*/false);
init = build2 (INIT_EXPR, void_type_node, slot, init);
- call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (call_expr),
- init, call_expr);
+ ret = build2 (COMPOUND_EXPR, TREE_TYPE (ret), init, ret);
}
- *tp = call_expr;
+ *tp = ret;
}
/* Emit all thunks to FN that should be emitted when FN is emitted. */
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);
}
else
rval = init;