diff options
Diffstat (limited to 'gcc/cp/call.c')
-rw-r--r-- | gcc/cp/call.c | 282 |
1 files changed, 209 insertions, 73 deletions
diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4c19d2ffcd3..0dcf322344c 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -45,7 +45,7 @@ along with GCC; see the file COPYING3. If not see enum conversion_kind { ck_identity, ck_lvalue, - ck_tsafe, + ck_fnptr, ck_qual, ck_std, ck_ptr, @@ -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. @@ -763,6 +771,7 @@ build_conv (conversion_kind code, tree type, conversion *from) break; case ck_qual: + case ck_fnptr: if (rank < cr_exact) rank = cr_exact; break; @@ -1204,19 +1213,40 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, tree to_pointee; tree from_pointee; + if (tcode == POINTER_TYPE) + { + to_pointee = TREE_TYPE (to); + from_pointee = TREE_TYPE (from); + + /* Since this is the target of a pointer, it can't have function + qualifiers, so any TYPE_QUALS must be for attributes const or + noreturn. Strip them. */ + if (TREE_CODE (to_pointee) == FUNCTION_TYPE + && TYPE_QUALS (to_pointee)) + to_pointee = build_qualified_type (to_pointee, TYPE_UNQUALIFIED); + if (TREE_CODE (from_pointee) == FUNCTION_TYPE + && TYPE_QUALS (from_pointee)) + from_pointee = build_qualified_type (from_pointee, TYPE_UNQUALIFIED); + } + else + { + to_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (to); + from_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (from); + } + if (tcode == POINTER_TYPE - && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (from), - TREE_TYPE (to))) + && same_type_ignoring_top_level_qualifiers_p (from_pointee, + to_pointee)) ; - else if (VOID_TYPE_P (TREE_TYPE (to)) + else if (VOID_TYPE_P (to_pointee) && !TYPE_PTRDATAMEM_P (from) - && TREE_CODE (TREE_TYPE (from)) != FUNCTION_TYPE) + && TREE_CODE (from_pointee) != FUNCTION_TYPE) { tree nfrom = TREE_TYPE (from); /* Don't try to apply restrict to void. */ int quals = cp_type_quals (nfrom) & ~TYPE_QUAL_RESTRICT; - from = build_pointer_type - (cp_build_qualified_type (void_type_node, quals)); + from_pointee = cp_build_qualified_type (void_type_node, quals); + from = build_pointer_type (from_pointee); conv = build_conv (ck_ptr, from, conv); } else if (TYPE_PTRDATAMEM_P (from)) @@ -1226,18 +1256,16 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, if (DERIVED_FROM_P (fbase, tbase) && (same_type_ignoring_top_level_qualifiers_p - (TYPE_PTRMEM_POINTED_TO_TYPE (from), - TYPE_PTRMEM_POINTED_TO_TYPE (to)))) + (from_pointee, to_pointee))) { - from = build_ptrmem_type (tbase, - TYPE_PTRMEM_POINTED_TO_TYPE (from)); + from = build_ptrmem_type (tbase, from_pointee); conv = build_conv (ck_pmem, from, conv); } else if (!same_type_p (fbase, tbase)) return NULL; } - else if (CLASS_TYPE_P (TREE_TYPE (from)) - && CLASS_TYPE_P (TREE_TYPE (to)) + else if (CLASS_TYPE_P (from_pointee) + && CLASS_TYPE_P (to_pointee) /* [conv.ptr] An rvalue of type "pointer to cv D," where D is a @@ -1249,37 +1277,15 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, that necessitates this conversion is ill-formed. Therefore, we use DERIVED_FROM_P, and do not check access or uniqueness. */ - && DERIVED_FROM_P (TREE_TYPE (to), TREE_TYPE (from))) + && DERIVED_FROM_P (to_pointee, from_pointee)) { - from = - cp_build_qualified_type (TREE_TYPE (to), - cp_type_quals (TREE_TYPE (from))); - from = build_pointer_type (from); + from_pointee + = cp_build_qualified_type (to_pointee, + cp_type_quals (from_pointee)); + from = build_pointer_type (from_pointee); conv = build_conv (ck_ptr, from, conv); conv->base_p = true; } - else if (tx_safe_fn_type_p (TREE_TYPE (from))) - { - /* A prvalue of type "pointer to transaction_safe function" can be - converted to a prvalue of type "pointer to function". */ - tree unsafe = tx_unsafe_fn_variant (TREE_TYPE (from)); - if (same_type_p (unsafe, TREE_TYPE (to))) - { - from = build_pointer_type (unsafe); - conv = build_conv (ck_tsafe, from, conv); - } - } - - if (tcode == POINTER_TYPE) - { - to_pointee = TREE_TYPE (to); - from_pointee = TREE_TYPE (from); - } - else - { - to_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (to); - from_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (from); - } if (same_type_p (from, to)) /* OK */; @@ -1293,6 +1299,8 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, else if (expr && string_conv_p (to, expr, 0)) /* converting from string constant to char *. */ conv = build_conv (ck_qual, to, conv); + else if (fnptr_conv_p (to, from)) + conv = build_conv (ck_fnptr, to, conv); /* Allow conversions among compatible ObjC pointer types (base conversions have been already handled above). */ else if (c_dialect_objc () @@ -1315,18 +1323,29 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, tree fbase = class_of_this_parm (fromfn); tree tbase = class_of_this_parm (tofn); - if (!DERIVED_FROM_P (fbase, tbase) - || !same_type_p (static_fn_type (fromfn), - static_fn_type (tofn))) + if (!DERIVED_FROM_P (fbase, tbase)) return NULL; - from = build_memfn_type (fromfn, - tbase, - cp_type_quals (tbase), - type_memfn_rqual (tofn)); - from = build_ptrmemfunc_type (build_pointer_type (from)); - conv = build_conv (ck_pmem, from, conv); - conv->base_p = true; + tree fstat = static_fn_type (fromfn); + tree tstat = static_fn_type (tofn); + if (same_type_p (tstat, fstat) + || fnptr_conv_p (tstat, fstat)) + /* OK */; + else + return NULL; + + if (!same_type_p (fbase, tbase)) + { + from = build_memfn_type (fstat, + tbase, + cp_type_quals (tbase), + type_memfn_rqual (tofn)); + from = build_ptrmemfunc_type (build_pointer_type (from)); + conv = build_conv (ck_pmem, from, conv); + conv->base_p = true; + } + if (fnptr_conv_p (tstat, fstat)) + conv = build_conv (ck_fnptr, to, conv); } else if (tcode == BOOLEAN_TYPE) { @@ -1424,10 +1443,14 @@ reference_compatible_p (tree t1, tree t2) { /* [dcl.init.ref] - "cv1 T1" is reference compatible with "cv2 T2" if T1 is - reference-related to T2 and cv1 is the same cv-qualification as, - or greater cv-qualification than, cv2. */ - return (reference_related_p (t1, t2) + "cv1 T1" is reference compatible with "cv2 T2" if + * T1 is reference-related to T2 or + * T2 is "noexcept function" and T1 is "function", where the + function types are otherwise the same, + and cv1 is the same cv-qualification as, or greater cv-qualification + than, cv2. */ + return ((reference_related_p (t1, t2) + || fnptr_conv_p (t1, t2)) && at_least_as_qualified_p (t1, t2)); } @@ -1461,7 +1484,7 @@ direct_reference_binding (tree type, conversion *conv) either an identity conversion or, if the conversion function returns an entity of a type that is a derived class of the parameter type, a derived-to-base conversion. */ - if (!same_type_ignoring_top_level_qualifiers_p (t, conv->type)) + if (is_properly_derived_from (conv->type, t)) { /* Represent the derived-to-base conversion. */ conv = build_conv (ck_base, t, conv); @@ -1574,7 +1597,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, [8.5.3/5 dcl.init.ref] is changed to also require direct bindings for const and rvalue references to rvalues of compatible class type. We should also do direct bindings for non-class xvalues. */ - if (related_p && gl_kind) + if ((related_p || compatible_p) && gl_kind) { /* [dcl.init.ref] @@ -2111,6 +2134,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 +3428,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 +3526,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 +6386,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 +6833,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) @@ -6915,9 +6984,9 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, case ck_lvalue: return decay_conversion (expr, complain); - case ck_tsafe: + case ck_fnptr: /* ??? Should the address of a transaction-safe pointer point to the TM - clone, and this conversion look up the primary function? */ + clone, and this conversion look up the primary function? */ return build_nop (totype, expr); case ck_qual: @@ -7139,6 +7208,9 @@ convert_default_arg (tree type, tree arg, tree fn, int parmnum, /* See through clones. */ fn = DECL_ORIGIN (fn); + /* And inheriting ctors. */ + if (flag_new_inheriting_ctors) + fn = strip_inheriting_ctors (fn); /* Detect recursion. */ FOR_EACH_VEC_SAFE_ELT (default_arg_context, i, t) @@ -7800,6 +7872,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 +8080,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; } @@ -8766,10 +8869,15 @@ is_subseq (conversion *ics1, conversion *ics2) ics2 = next_conversion (ics2); + while (ics2->kind == ck_rvalue + || ics2->kind == ck_lvalue) + ics2 = next_conversion (ics2); + if (ics2->kind == ics1->kind && same_type_p (ics2->type, ics1->type) - && same_type_p (next_conversion (ics2)->type, - next_conversion (ics1)->type)) + && (ics1->kind == ck_identity + || same_type_p (next_conversion (ics2)->type, + next_conversion (ics1)->type))) return true; } } @@ -9539,6 +9647,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. |