aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/call.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/call.c')
-rw-r--r--gcc/cp/call.c139
1 files changed, 126 insertions, 13 deletions
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 4c19d2ffcd3..27aa7fdd74b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -414,6 +414,7 @@ enum rejection_reason_code {
rr_bad_arg_conversion,
rr_template_unification,
rr_invalid_copy,
+ rr_inherited_ctor,
rr_constraint_failure
};
@@ -689,6 +690,13 @@ invalid_copy_with_fn_template_rejection (void)
return r;
}
+static struct rejection_reason *
+inherited_ctor_rejection (void)
+{
+ struct rejection_reason *r = alloc_rejection (rr_inherited_ctor);
+ return r;
+}
+
// Build a constraint failure record, saving information into the
// template_instantiation field of the rejection. If FN is not a template
// declaration, the TMPL member is the FN declaration and TARGS is empty.
@@ -2111,6 +2119,18 @@ add_function_candidate (struct z_candidate **candidates,
}
}
+ /* Don't consider inherited constructors for initialization from an
+ expression of the same or derived type. */
+ /* FIXME extend to operator=. */
+ if (i == 0 && len == 1
+ && DECL_INHERITED_CTOR (fn)
+ && reference_related_p (ctype, argtype))
+ {
+ viable = 0;
+ reason = inherited_ctor_rejection ();
+ goto out;
+ }
+
/* Core issue 899: When [copy-]initializing a temporary to be bound
to the first parameter of a copy constructor (12.8) called with
a single argument in the context of direct-initialization,
@@ -3393,32 +3413,40 @@ print_z_candidate (location_t loc, const char *msgstr,
const char *msg = (msgstr == NULL
? ""
: ACONCAT ((msgstr, " ", NULL)));
- location_t cloc = location_of (candidate->fn);
+ tree fn = candidate->fn;
+ if (flag_new_inheriting_ctors)
+ fn = strip_inheriting_ctors (fn);
+ location_t cloc = location_of (fn);
- if (identifier_p (candidate->fn))
+ if (identifier_p (fn))
{
cloc = loc;
if (candidate->num_convs == 3)
- inform (cloc, "%s%D(%T, %T, %T) <built-in>", msg, candidate->fn,
+ inform (cloc, "%s%D(%T, %T, %T) <built-in>", msg, fn,
candidate->convs[0]->type,
candidate->convs[1]->type,
candidate->convs[2]->type);
else if (candidate->num_convs == 2)
- inform (cloc, "%s%D(%T, %T) <built-in>", msg, candidate->fn,
+ inform (cloc, "%s%D(%T, %T) <built-in>", msg, fn,
candidate->convs[0]->type,
candidate->convs[1]->type);
else
- inform (cloc, "%s%D(%T) <built-in>", msg, candidate->fn,
+ inform (cloc, "%s%D(%T) <built-in>", msg, fn,
candidate->convs[0]->type);
}
- else if (TYPE_P (candidate->fn))
- inform (cloc, "%s%T <conversion>", msg, candidate->fn);
+ else if (TYPE_P (fn))
+ inform (cloc, "%s%T <conversion>", msg, fn);
else if (candidate->viable == -1)
- inform (cloc, "%s%#D <near match>", msg, candidate->fn);
- else if (DECL_DELETED_FN (candidate->fn))
- inform (cloc, "%s%#D <deleted>", msg, candidate->fn);
+ inform (cloc, "%s%#D <near match>", msg, fn);
+ else if (DECL_DELETED_FN (fn))
+ inform (cloc, "%s%#D <deleted>", msg, fn);
else
- inform (cloc, "%s%#D", msg, candidate->fn);
+ inform (cloc, "%s%#D", msg, fn);
+ if (fn != candidate->fn)
+ {
+ cloc = location_of (candidate->fn);
+ inform (cloc, " inherited here");
+ }
/* Give the user some information about why this candidate failed. */
if (candidate->reason != NULL)
{
@@ -3483,6 +3511,11 @@ print_z_candidate (location_t loc, const char *msgstr,
diagnose_constraints (cloc, tmpl, args);
}
break;
+ case rr_inherited_ctor:
+ inform (cloc, " an inherited constructor is not a candidate for "
+ "initialization from an expression of the same or derived "
+ "type");
+ break;
case rr_none:
default:
/* This candidate didn't have any issues or we failed to
@@ -6338,10 +6371,22 @@ enforce_access (tree basetype_path, tree decl, tree diag_decl,
{
gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
+ if (flag_new_inheriting_ctors
+ && DECL_INHERITED_CTOR (decl))
+ {
+ /* 7.3.3/18: The additional constructors are accessible if they would be
+ accessible when used to construct an object of the corresponding base
+ class. */
+ decl = strip_inheriting_ctors (decl);
+ basetype_path = TYPE_BINFO (DECL_CONTEXT (decl));
+ }
+
if (!accessible_p (basetype_path, decl, true))
{
if (complain & tf_error)
{
+ if (flag_new_inheriting_ctors)
+ diag_decl = strip_inheriting_ctors (diag_decl);
if (TREE_PRIVATE (decl))
{
error ("%q#D is private within this context", diag_decl);
@@ -6773,6 +6818,15 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
if (! MAYBE_CLASS_TYPE_P (totype))
return expr;
+
+ /* Don't introduce copies when passing arguments along to the inherited
+ constructor. */
+ if (current_function_decl
+ && flag_new_inheriting_ctors
+ && DECL_INHERITED_CTOR (current_function_decl)
+ && TREE_ADDRESSABLE (totype))
+ return expr;
+
/* Fall through. */
case ck_base:
if (convs->kind == ck_base && !convs->need_temporary_p)
@@ -7800,6 +7854,29 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
check_function_arguments (input_location, TREE_TYPE (fn), nargs, fargs);
}
+ if (DECL_INHERITED_CTOR (fn))
+ {
+ /* Check for passing ellipsis arguments to an inherited constructor. We
+ could handle this by open-coding the inherited constructor rather than
+ defining it, but let's not bother now. */
+ if (!cp_unevaluated_operand
+ && cand->convs[cand->num_convs-1]->ellipsis_p)
+ {
+ if (complain & tf_error)
+ {
+ sorry ("passing arguments to ellipsis of inherited constructor "
+ "%qD", cand->fn);
+ inform (DECL_SOURCE_LOCATION (cand->fn), "declared here");
+ }
+ return error_mark_node;
+ }
+
+ /* A base constructor inheriting from a virtual base doesn't get the
+ inherited arguments, just this and __vtt. */
+ if (ctor_omit_inherited_parms (fn))
+ nargs = 2;
+ }
+
/* Avoid actually calling copy constructors and copy assignment operators,
if possible. */
@@ -7985,13 +8062,21 @@ 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 (call != error_mark_node
- && cand->flags & LOOKUP_LIST_INIT_CTOR)
+ if (call == error_mark_node)
+ return call;
+ if (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;
}
+ if (current_function_decl
+ && flag_new_inheriting_ctors
+ && DECL_INHERITED_CTOR (current_function_decl)
+ && cand->num_convs)
+ /* Don't introduce copies when passing arguments along to the inherited
+ constructor. */
+ CALL_FROM_THUNK_P (call) = true;
return call;
}
@@ -9539,6 +9624,34 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
return winner;
}
+ /* or, if not that, F2 is from a using-declaration, F1 is not, and the
+ conversion sequences are equivalent.
+ (proposed in http://lists.isocpp.org/core/2016/10/1142.php) */
+ if (DECL_P (cand1->fn) && DECL_CLASS_SCOPE_P (cand1->fn)
+ && !DECL_CONV_FN_P (cand1->fn)
+ && DECL_P (cand2->fn) && DECL_CLASS_SCOPE_P (cand2->fn)
+ && !DECL_CONV_FN_P (cand2->fn))
+ {
+ bool used1 = (DECL_INHERITED_CTOR (cand1->fn)
+ || (BINFO_TYPE (cand1->access_path)
+ != DECL_CONTEXT (cand1->fn)));
+ bool used2 = (DECL_INHERITED_CTOR (cand2->fn)
+ || (BINFO_TYPE (cand2->access_path)
+ != DECL_CONTEXT (cand2->fn)));
+ if (int diff = used2 - used1)
+ {
+ for (i = 0; i < len; ++i)
+ {
+ conversion *t1 = cand1->convs[i + off1];
+ conversion *t2 = cand2->convs[i + off2];
+ if (!same_type_p (t1->type, t2->type))
+ break;
+ }
+ if (i == len)
+ return diff;
+ }
+ }
+
/* Check whether we can discard a builtin candidate, either because we
have two identical ones or matching builtin and non-builtin candidates.