From: Jason Merrill Date: Wed, 2 Nov 2016 01:50:29 +0000 (-0400) Subject: Implement P0136R1, Rewording inheriting constructors. X-Git-Tag: releases/gcc-7.1.0~3488 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=31f7f784fe7fa68bca218df43ec8965569d6cb5d;p=thirdparty%2Fgcc.git Implement P0136R1, Rewording inheriting constructors. gcc/c-family/ * c.opt (-fnew-inheriting-ctors): New. * c-opts.c: Default to on for ABI 11+. gcc/cp/ * call.c (enum rejection_reason_code): Add rr_inherited_ctor. (inherited_ctor_rejection): New. (add_function_candidate): Reject inherited ctors for copying. (enforce_access): Use strip_inheriting_ctors. (print_z_candidate): Likewise. Handle rr_inherited_ctor. (convert_like_real): Avoid copying inheriting ctor parameters. (build_over_call): Likewise. A base ctor inheriting from vbase has no parms. Sorry about varargs. (joust): A local constructor beats inherited with the same convs. * class.c (add_method): Handle hiding inheriting ctors. (one_inherited_ctor): Handle new semantics. (add_implicitly_declared_members): Pass using_decl down. (build_clone): A base ctor inheriting from vbase has no parms. * cp-tree.h (DECL_INHERITED_CTOR): Store this instead of the base. (SET_DECL_INHERITED_CTOR): Likewise. (DECL_INHERITED_CTOR_BASE): Adjust. * constexpr.c: Adjust. * error.c (dump_function_decl): Decorate inheriting ctors. * init.c (emit_mem_initializers): Suppress access control in inheriting ctor. * mangle.c (write_special_name_constructor): Handle new inheriting ctor mangling. * method.c (strip_inheriting_ctors, inherited_ctor_binfo) (ctor_omit_inherited_parms, binfo_inherited_from): New. (synthesized_method_walk): Use binfo_inherited_from. Suppress access control in inheriting ctor. (deduce_inheriting_ctor): Deleted if ambiguous ctor inheritance. (maybe_explain_implicit_delete): Explain ambigous ctor inheritance. (add_one_base_init, do_build_copy_constructor): Adjust. (locate_fn_flags, explain_implicit_non_constexpr): Adjust. (implicitly_declare_fn): Adjust. (get_inherited_ctor): Remove. * name-lookup.c (do_class_using_decl): Check for indirect ctor inheritance. * optimize.c (cdtor_comdat_group): Adjust for new mangling. (maybe_clone_body): Handle omitted parms in base clone. (maybe_thunk_body): Don't thunk if base clone omits parms. * pt.c (tsubst_decl): Adjust. (instantiate_template_1): Suppress access control in inheriting ctor. (fn_type_unification): Do deduction with inherited ctor. * tree.c (special_function_p): Adjust. gcc/ * tree-inline.c (copy_tree_body_r): Only copy the taken branch of a COND_EXPR with constant condition. libiberty/ * cp-demangle.c (d_ctor_dtor_name): Handle inheriting constructor. From-SVN: r241765 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 730dcd343b54..3a7b71dea6a6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2016-11-01 Jason Merrill + + * tree-inline.c (copy_tree_body_r): Only copy the taken branch of + a COND_EXPR with constant condition. + 2016-11-01 Jakub Jelinek * dwarf2out.c (gen_variable_die): Remove again origin_die variable diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 645741803022..efec6e167380 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2016-11-01 Jason Merrill + + * c.opt (-fnew-inheriting-ctors): New. + * c-opts.c: Default to on for ABI 11+. + 2016-10-31 Jakub Jelinek PR c++/77948 diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 4a0b9952fa69..de260e7dcee8 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -902,6 +902,12 @@ c_common_post_options (const char **pfilename) if (flag_abi_version == 0) flag_abi_version = 11; + /* By default, enable the new inheriting constructor semantics along with ABI + 11. New and old should coexist fine, but it is a change in what + artificial symbols are generated. */ + if (!global_options_set.x_flag_new_inheriting_ctors) + flag_new_inheriting_ctors = abi_version_at_least (11); + if (cxx_dialect >= cxx11) { /* If we're allowing C++0x constructs, don't warn about C++98 diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 7e86dbf6bb7b..7d8a7265752b 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1362,6 +1362,10 @@ fimplicit-templates C++ ObjC++ Var(flag_implicit_templates) Init(1) Emit implicit instantiations of templates. +fnew-inheriting-ctors +C++ ObjC++ Var(flag_new_inheriting_ctors) Init(1) +Implement C++17 inheriting constructor semantics. + ffriend-injection C++ ObjC++ Var(flag_friend_injection) Inject friend functions into enclosing namespace. diff --git a/gcc/common.opt b/gcc/common.opt index 2c2f7ad7aa99..097cae660de4 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -907,7 +907,8 @@ Driver Undocumented ; identity, such as ia32 calling convention attributes (stdcall, etc.) ; Default in G++ 6 (set in c_common_post_options). ; -; 11: The version of the ABI that corrects mangling of sizeof... expressions. +; 11: The version of the ABI that corrects mangling of sizeof... expressions +; and introduces new inheriting constructor handling. ; Default in G++ 7. ; ; Additional positive integers will be assigned as new versions of diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d9ea36b9eb83..5eabdc2c8866 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,49 @@ +2016-11-01 Jason Merrill + + Implement P0136R1, Rewording inheriting constructors. + * call.c (enum rejection_reason_code): Add rr_inherited_ctor. + (inherited_ctor_rejection): New. + (add_function_candidate): Reject inherited ctors for copying. + (enforce_access): Use strip_inheriting_ctors. + (print_z_candidate): Likewise. Handle rr_inherited_ctor. + (convert_like_real): Avoid copying inheriting ctor parameters. + (build_over_call): Likewise. A base ctor inheriting from vbase + has no parms. Sorry about varargs. + (joust): A local constructor beats inherited with the same convs. + * class.c (add_method): Handle hiding inheriting ctors. + (one_inherited_ctor): Handle new semantics. + (add_implicitly_declared_members): Pass using_decl down. + (build_clone): A base ctor inheriting from vbase has no parms. + * cp-tree.h (DECL_INHERITED_CTOR): Store this instead of the base. + (SET_DECL_INHERITED_CTOR): Likewise. + (DECL_INHERITED_CTOR_BASE): Adjust. + * constexpr.c: Adjust. + * error.c (dump_function_decl): Decorate inheriting ctors. + * init.c (emit_mem_initializers): Suppress access control in + inheriting ctor. + * mangle.c (write_special_name_constructor): Handle new inheriting + ctor mangling. + * method.c (strip_inheriting_ctors, inherited_ctor_binfo) + (ctor_omit_inherited_parms, binfo_inherited_from): New. + (synthesized_method_walk): Use binfo_inherited_from. Suppress + access control in inheriting ctor. + (deduce_inheriting_ctor): Deleted if ambiguous ctor inheritance. + (maybe_explain_implicit_delete): Explain ambigous ctor inheritance. + (add_one_base_init, do_build_copy_constructor): Adjust. + (locate_fn_flags, explain_implicit_non_constexpr): Adjust. + (implicitly_declare_fn): Adjust. + (get_inherited_ctor): Remove. + * name-lookup.c (do_class_using_decl): Check for indirect ctor + inheritance. + * optimize.c (cdtor_comdat_group): Adjust for new mangling. + (maybe_clone_body): Handle omitted parms in base clone. + (maybe_thunk_body): Don't thunk if base clone omits parms. + * pt.c (tsubst_decl): Adjust. + (instantiate_template_1): Suppress access control in inheriting + ctor. + (fn_type_unification): Do deduction with inherited ctor. + * tree.c (special_function_p): Adjust. + 2016-11-01 Jakub Jelinek * cp-objcp-common.c (cp_decl_dwarf_attribute): Handle DW_AT_inline. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4c19d2ffcd38..27aa7fdd74b3 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) ", msg, candidate->fn, + inform (cloc, "%s%D(%T, %T, %T) ", 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) ", msg, candidate->fn, + inform (cloc, "%s%D(%T, %T) ", msg, fn, candidate->convs[0]->type, candidate->convs[1]->type); else - inform (cloc, "%s%D(%T) ", msg, candidate->fn, + inform (cloc, "%s%D(%T) ", msg, fn, candidate->convs[0]->type); } - else if (TYPE_P (candidate->fn)) - inform (cloc, "%s%T ", msg, candidate->fn); + else if (TYPE_P (fn)) + inform (cloc, "%s%T ", msg, fn); else if (candidate->viable == -1) - inform (cloc, "%s%#D ", msg, candidate->fn); - else if (DECL_DELETED_FN (candidate->fn)) - inform (cloc, "%s%#D ", msg, candidate->fn); + inform (cloc, "%s%#D ", msg, fn); + else if (DECL_DELETED_FN (fn)) + inform (cloc, "%s%#D ", 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. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 1a379348e5f5..c6b4ed6af339 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1016,7 +1016,6 @@ add_method (tree type, tree method, tree using_decl) bool complete_p; bool insert_p = false; tree current_fns; - tree fns; if (method == error_mark_node) return false; @@ -1083,8 +1082,9 @@ add_method (tree type, tree method, tree using_decl) current_fns = insert_p ? NULL_TREE : (*method_vec)[slot]; /* Check to see if we've already got this method. */ - for (fns = current_fns; fns; fns = OVL_NEXT (fns)) + for (tree *p = ¤t_fns; *p; ) { + tree fns = *p; tree fn = OVL_CURRENT (fns); tree fn_type; tree method_type; @@ -1092,12 +1092,14 @@ add_method (tree type, tree method, tree using_decl) tree parms2; if (TREE_CODE (fn) != TREE_CODE (method)) - continue; + goto cont; /* Two using-declarations can coexist, we'll complain about ambiguity in overload resolution. */ - if (using_decl && TREE_CODE (fns) == OVERLOAD && OVL_USED (fns)) - continue; + if (using_decl && TREE_CODE (fns) == OVERLOAD && OVL_USED (fns) + /* Except handle inherited constructors specially. */ + && ! DECL_CONSTRUCTOR_P (fn)) + goto cont; /* [over.load] Member function declarations with the same name and the same parameter types cannot be @@ -1131,7 +1133,7 @@ add_method (tree type, tree method, tree using_decl) == FUNCTION_REF_QUALIFIED (method_type)) && (type_memfn_quals (fn_type) != type_memfn_quals (method_type) || type_memfn_rqual (fn_type) != type_memfn_rqual (method_type))) - continue; + goto cont; /* For templates, the return type and template parameters must be identical. */ @@ -1140,7 +1142,7 @@ add_method (tree type, tree method, tree using_decl) TREE_TYPE (method_type)) || !comp_template_parms (DECL_TEMPLATE_PARMS (fn), DECL_TEMPLATE_PARMS (method)))) - continue; + goto cont; if (! DECL_STATIC_FUNCTION_P (fn)) parms1 = TREE_CHAIN (parms1); @@ -1178,18 +1180,38 @@ add_method (tree type, tree method, tree using_decl) mangle_decl (method); } cgraph_node::record_function_versions (fn, method); - continue; + goto cont; } - if (DECL_INHERITED_CTOR_BASE (method)) + if (DECL_INHERITED_CTOR (method)) { - if (DECL_INHERITED_CTOR_BASE (fn)) + if (DECL_INHERITED_CTOR (fn)) { + tree basem = DECL_INHERITED_CTOR_BASE (method); + tree basef = DECL_INHERITED_CTOR_BASE (fn); + if (flag_new_inheriting_ctors) + { + if (basem == basef) + { + /* Inheriting the same constructor along different + paths, combine them. */ + SET_DECL_INHERITED_CTOR + (fn, ovl_cons (DECL_INHERITED_CTOR (method), + DECL_INHERITED_CTOR (fn))); + /* Adjust deletedness and such. */ + deduce_inheriting_ctor (fn); + /* And discard the new one. */ + return false; + } + else + /* Inherited ctors can coexist until overload + resolution. */ + goto cont; + } error_at (DECL_SOURCE_LOCATION (method), - "%q#D inherited from %qT", method, - DECL_INHERITED_CTOR_BASE (method)); + "%q#D", method); error_at (DECL_SOURCE_LOCATION (fn), "conflicts with version inherited from %qT", - DECL_INHERITED_CTOR_BASE (fn)); + basef); } /* Otherwise defer to the other function. */ return false; @@ -1200,6 +1222,13 @@ add_method (tree type, tree method, tree using_decl) /* Defer to the local function. */ return false; } + else if (flag_new_inheriting_ctors + && DECL_INHERITED_CTOR (fn)) + { + /* Hide the inherited constructor. */ + *p = OVL_NEXT (fns); + continue; + } else { error ("%q+#D cannot be overloaded", method); @@ -1212,6 +1241,12 @@ add_method (tree type, tree method, tree using_decl) will crash while processing the definitions. */ return false; } + + cont: + if (TREE_CODE (fns) == OVERLOAD) + p = &OVL_CHAIN (fns); + else + break; } /* A class should never have more than one destructor. */ @@ -3308,10 +3343,19 @@ one_inheriting_sig (tree t, tree ctor, tree *parms, int nparms) constructor CTOR. */ static void -one_inherited_ctor (tree ctor, tree t) +one_inherited_ctor (tree ctor, tree t, tree using_decl) { tree parms = FUNCTION_FIRST_USER_PARMTYPE (ctor); + if (flag_new_inheriting_ctors) + { + ctor = implicitly_declare_fn (sfk_inheriting_constructor, + t, /*const*/false, ctor, parms); + add_method (t, ctor, using_decl); + TYPE_HAS_USER_CONSTRUCTOR (t) = true; + return; + } + tree *new_parms = XALLOCAVEC (tree, list_length (parms)); int i = 0; for (; parms && parms != void_list_node; parms = TREE_CHAIN (parms)) @@ -3412,7 +3456,7 @@ add_implicitly_declared_members (tree t, tree* access_decls, input_location = DECL_SOURCE_LOCATION (using_decl); if (ctor_list) for (; ctor_list; ctor_list = OVL_NEXT (ctor_list)) - one_inherited_ctor (OVL_CURRENT (ctor_list), t); + one_inherited_ctor (OVL_CURRENT (ctor_list), t, using_decl); *access_decls = TREE_CHAIN (*access_decls); input_location = loc; } @@ -4772,6 +4816,11 @@ build_clone (tree fn, tree name) } } + /* A base constructor inheriting from a virtual base doesn't get the + arguments. */ + if (ctor_omit_inherited_parms (fn)) + DECL_CHAIN (DECL_CHAIN (DECL_ARGUMENTS (clone))) = NULL_TREE; + for (parms = DECL_ARGUMENTS (clone); parms; parms = DECL_CHAIN (parms)) { DECL_CONTEXT (parms) = clone; diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 1ebd647e7d1c..43457d2463fc 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -171,13 +171,13 @@ is_valid_constexpr_fn (tree fun, bool complain) { bool ret = true; - if (DECL_INHERITED_CTOR_BASE (fun) + if (DECL_INHERITED_CTOR (fun) && TREE_CODE (fun) == TEMPLATE_DECL) { ret = false; if (complain) error ("inherited constructor %qD is not constexpr", - get_inherited_ctor (fun)); + DECL_INHERITED_CTOR (fun)); } else { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 45224dcfc429..d3a5aeb785ba 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2730,12 +2730,21 @@ struct GTY(()) lang_decl { (LANG_DECL_FN_CHECK (NODE)->context = (THUNKS)) /* If NODE, a FUNCTION_DECL, is a C++11 inheriting constructor, then this - is the base it inherits from. */ -#define DECL_INHERITED_CTOR_BASE(NODE) \ - (DECL_CONSTRUCTOR_P (NODE) ? LANG_DECL_FN_CHECK (NODE)->context : NULL_TREE) + is the constructor it inherits from. */ +#define DECL_INHERITED_CTOR(NODE) \ + (DECL_DECLARES_FUNCTION_P (NODE) && DECL_CONSTRUCTOR_P (NODE) \ + ? LANG_DECL_FN_CHECK (NODE)->context : NULL_TREE) + +/* And this is the base that constructor comes from. */ +#define DECL_INHERITED_CTOR_BASE(NODE) \ + (DECL_INHERITED_CTOR (NODE) \ + ? DECL_CONTEXT (flag_new_inheriting_ctors \ + ? strip_inheriting_ctors (NODE) \ + : DECL_INHERITED_CTOR (NODE)) \ + : NULL_TREE) /* Set the inherited base. */ -#define SET_DECL_INHERITED_CTOR_BASE(NODE,INH) \ +#define SET_DECL_INHERITED_CTOR(NODE,INH) \ (LANG_DECL_FN_CHECK (NODE)->context = (INH)) /* Nonzero if NODE is a thunk, rather than an ordinary function. */ @@ -6036,7 +6045,9 @@ extern tree get_copy_ctor (tree, tsubst_flags_t); extern tree get_copy_assign (tree); extern tree get_default_ctor (tree); extern tree get_dtor (tree, tsubst_flags_t); -extern tree get_inherited_ctor (tree); +extern tree strip_inheriting_ctors (tree); +extern tree inherited_ctor_binfo (tree); +extern bool ctor_omit_inherited_parms (tree); extern tree locate_ctor (tree); extern tree implicitly_declare_fn (special_function_kind, tree, bool, tree, tree); diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 917a448ad34f..aa92a7e6a6b5 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1617,6 +1617,13 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) pp_cxx_requires_clause (pp, reqs); dump_substitution (pp, t, template_parms, template_args, flags); + + if (tree base = DECL_INHERITED_CTOR_BASE (t)) + { + pp_cxx_ws_string (pp, "[inherited from"); + dump_type (pp, base, TFF_PLAIN_IDENTIFIER); + pp_character (pp, ']'); + } } else if (template_args) { diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 2418a9d48c19..5eba4c3e18cf 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1117,7 +1117,7 @@ emit_mem_initializers (tree mem_inits) } if (DECL_DEFAULTED_FN (current_function_decl) - && ! DECL_INHERITED_CTOR_BASE (current_function_decl)) + && ! DECL_INHERITED_CTOR (current_function_decl)) flags |= LOOKUP_DEFAULTED; /* Sort the mem-initializers into the order in which the @@ -1138,6 +1138,13 @@ emit_mem_initializers (tree mem_inits) if (arguments == error_mark_node) continue; + /* Suppress access control when calling the inherited ctor. */ + bool inherited_base = (DECL_INHERITED_CTOR (current_function_decl) + && flag_new_inheriting_ctors + && arguments); + if (inherited_base) + push_deferring_access_checks (dk_deferred); + if (arguments == NULL_TREE) { /* If these initializations are taking place in a copy constructor, @@ -1172,6 +1179,9 @@ emit_mem_initializers (tree mem_inits) /* C++14 DR1658 Means we do not have to construct vbases of abstract classes. */ construct_virtual_base (subobject, arguments); + + if (inherited_base) + pop_deferring_access_checks (); } in_base_initializer = 0; diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index cb2f260c2d1f..f3b2fe3ee8de 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1786,18 +1786,25 @@ write_identifier (const char *identifier) static void write_special_name_constructor (const tree ctor) { + write_char ('C'); + bool new_inh = (flag_new_inheriting_ctors + && DECL_INHERITED_CTOR (ctor)); + if (new_inh) + write_char ('I'); if (DECL_BASE_CONSTRUCTOR_P (ctor)) - write_string ("C2"); + write_char ('2'); /* This is the old-style "[unified]" constructor. In some cases, we may emit this function and call it from the clones in order to share code and save space. */ else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor)) - write_string ("C4"); + write_char ('4'); else { gcc_assert (DECL_COMPLETE_CONSTRUCTOR_P (ctor)); - write_string ("C1"); + write_char ('1'); } + if (new_inh) + write_type (DECL_INHERITED_CTOR_BASE (ctor)); } /* Handle destructor productions of non-terminal . diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 73a670b59c86..73d42b19d55a 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -492,6 +492,118 @@ forward_parm (tree parm) return exp; } +/* Strip all inheriting constructors, if any, to return the original + constructor from a (possibly indirect) base class. */ + +tree +strip_inheriting_ctors (tree fn) +{ + gcc_assert (flag_new_inheriting_ctors); + while (tree inh = DECL_INHERITED_CTOR (fn)) + { + inh = OVL_CURRENT (inh); + fn = inh; + } + return fn; +} + +/* Find the binfo for the base subobject of BINFO being initialized by + inherited constructor FNDECL (a member of a direct base of BINFO). */ + +static tree inherited_ctor_binfo (tree, tree); +static tree +inherited_ctor_binfo_1 (tree binfo, tree fndecl) +{ + tree base = DECL_CONTEXT (fndecl); + tree base_binfo; + for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + if (BINFO_TYPE (base_binfo) == base) + return inherited_ctor_binfo (base_binfo, fndecl); + + gcc_unreachable(); +} + +/* Find the binfo for the base subobject of BINFO being initialized by + inheriting constructor FNDECL (a member of BINFO), or BINFO if FNDECL is not + an inheriting constructor. */ + +static tree +inherited_ctor_binfo (tree binfo, tree fndecl) +{ + tree inh = DECL_INHERITED_CTOR (fndecl); + if (!inh) + return binfo; + + tree results = NULL_TREE; + for (; inh; inh = OVL_NEXT (inh)) + { + tree one = inherited_ctor_binfo_1 (binfo, OVL_CURRENT (inh)); + if (!results) + results = one; + else if (one != results) + results = tree_cons (NULL_TREE, one, results); + } + return results; +} + +/* Find the binfo for the base subobject being initialized by inheriting + constructor FNDECL, or NULL_TREE if FNDECL is not an inheriting + constructor. */ + +tree +inherited_ctor_binfo (tree fndecl) +{ + if (!DECL_INHERITED_CTOR (fndecl)) + return NULL_TREE; + tree binfo = TYPE_BINFO (DECL_CONTEXT (fndecl)); + return inherited_ctor_binfo (binfo, fndecl); +} + +/* True if we should omit all user-declared parameters from constructor FN, + because it is a base clone of a ctor inherited from a virtual base. */ + +bool +ctor_omit_inherited_parms (tree fn) +{ + if (!flag_new_inheriting_ctors) + /* We only optimize away the parameters in the new model. */ + return false; + if (!DECL_BASE_CONSTRUCTOR_P (fn) + || !CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn))) + return false; + tree binfo = inherited_ctor_binfo (fn); + for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo)) + if (BINFO_VIRTUAL_P (binfo)) + return true; + return false; +} + +/* True iff constructor(s) INH inherited into BINFO initializes INIT_BINFO. + This can be true for multiple virtual bases as well as one direct + non-virtual base. */ + +static bool +binfo_inherited_from (tree binfo, tree init_binfo, tree inh) +{ + /* inh is an OVERLOAD if we inherited the same constructor along + multiple paths, check all of them. */ + for (; inh; inh = OVL_NEXT (inh)) + { + tree fn = OVL_CURRENT (inh); + tree base = DECL_CONTEXT (fn); + tree base_binfo = NULL_TREE; + for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + if (BINFO_TYPE (base_binfo) == base) + break; + if (base_binfo == init_binfo + || (flag_new_inheriting_ctors + && binfo_inherited_from (base_binfo, init_binfo, + DECL_INHERITED_CTOR (fn)))) + return true; + } + return false; +} + /* Subroutine of do_build_copy_constructor: Add a mem-initializer for BINFO given the parameter or parameters PARM, possibly inherited constructor base INH, or move flag MOVE_P. */ @@ -505,7 +617,7 @@ add_one_base_init (tree binfo, tree parm, bool move_p, tree inh, { /* An inheriting constructor only has a mem-initializer for the base it inherits from. */ - if (BINFO_TYPE (binfo) != inh) + if (!binfo_inherited_from (TYPE_BINFO (current_class_type), binfo, inh)) return member_init_list; tree *p = &init; @@ -537,7 +649,7 @@ do_build_copy_constructor (tree fndecl) tree parm = FUNCTION_FIRST_USER_PARM (fndecl); bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl); bool trivial = trivial_fn_p (fndecl); - tree inh = DECL_INHERITED_CTOR_BASE (fndecl); + tree inh = DECL_INHERITED_CTOR (fndecl); if (!inh) parm = convert_from_reference (parm); @@ -901,7 +1013,7 @@ locate_fn_flags (tree type, tree name, tree argtype, int flags, { if (TREE_CODE (argtype) == TREE_LIST) { - for (tree elt = argtype; elt != void_list_node; + for (tree elt = argtype; elt && elt != void_list_node; elt = TREE_CHAIN (elt)) { tree type = TREE_VALUE (elt); @@ -996,25 +1108,6 @@ get_copy_assign (tree type) return fn; } -/* Locate the inherited constructor of constructor CTOR. */ - -tree -get_inherited_ctor (tree ctor) -{ - gcc_assert (DECL_INHERITED_CTOR_BASE (ctor)); - - push_deferring_access_checks (dk_no_check); - tree fn = locate_fn_flags (DECL_INHERITED_CTOR_BASE (ctor), - complete_ctor_identifier, - FUNCTION_FIRST_USER_PARMTYPE (ctor), - LOOKUP_NORMAL|LOOKUP_SPECULATIVE, - tf_none); - pop_deferring_access_checks (); - if (fn == error_mark_node) - return NULL_TREE; - return fn; -} - /* walk_tree helper function for is_trivially_xible. If *TP is a call, return it if it calls something other than a trivial special member function. */ @@ -1330,7 +1423,7 @@ static void synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, tree *spec_p, bool *trivial_p, bool *deleted_p, bool *constexpr_p, bool diag, - tree inherited_base, tree inherited_parms) + tree inheriting_ctor, tree inherited_parms) { tree binfo, base_binfo, scope, fnname, rval, argtype; bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor; @@ -1389,7 +1482,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, } gcc_assert ((sfk == sfk_inheriting_constructor) - == (inherited_base != NULL_TREE)); + == (inheriting_ctor != NULL_TREE)); /* If that user-written default constructor would satisfy the requirements of a constexpr constructor (7.1.5), the @@ -1465,7 +1558,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, scope = push_scope (ctype); flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE; - if (!inherited_base) + if (!inheriting_ctor) flags |= LOOKUP_DEFAULTED; complain = diag ? tf_warning_or_error : tf_none; @@ -1485,13 +1578,25 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, /* We'll handle virtual bases below. */ continue; + bool inherited_binfo = false; + if (copy_arg_p) argtype = build_stub_type (basetype, quals, move_p); - else if (basetype == inherited_base) - argtype = inherited_parms; + else if ((inherited_binfo + = binfo_inherited_from (binfo, base_binfo, inheriting_ctor))) + { + /* Don't check access on the inherited constructor. */ + argtype = inherited_parms; + if (flag_new_inheriting_ctors) + push_deferring_access_checks (dk_deferred); + } rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); - if (inherited_base) - argtype = NULL_TREE; + if (inherited_binfo) + { + if (flag_new_inheriting_ctors) + pop_deferring_access_checks (); + argtype = NULL_TREE; + } process_subob_fn (rval, spec_p, trivial_p, deleted_p, constexpr_p, diag, basetype); @@ -1547,9 +1652,24 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, FOR_EACH_VEC_ELT (*vbases, i, base_binfo) { tree basetype = BINFO_TYPE (base_binfo); + bool inherited_binfo = false; + if (copy_arg_p) argtype = build_stub_type (basetype, quals, move_p); + else if ((inherited_binfo + = binfo_inherited_from (binfo, base_binfo, inheriting_ctor))) + { + argtype = inherited_parms; + if (flag_new_inheriting_ctors) + push_deferring_access_checks (dk_deferred); + } rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); + if (inherited_binfo) + { + if (flag_new_inheriting_ctors) + pop_deferring_access_checks (); + argtype = NULL_TREE; + } process_subob_fn (rval, spec_p, trivial_p, deleted_p, constexpr_p, diag, basetype); @@ -1598,7 +1718,7 @@ get_defaulted_eh_spec (tree decl) bool const_p = CP_TYPE_CONST_P (non_reference (parm_type)); tree spec = empty_except_spec; synthesized_method_walk (ctype, sfk, const_p, &spec, NULL, NULL, - NULL, false, DECL_INHERITED_CTOR_BASE (decl), + NULL, false, DECL_INHERITED_CTOR (decl), parms); return spec; } @@ -1657,6 +1777,17 @@ maybe_explain_implicit_delete (tree decl) decl, ctype); informed = true; } + else if (sfk == sfk_inheriting_constructor) + { + tree binfo = inherited_ctor_binfo (decl); + if (TREE_CODE (binfo) != TREE_BINFO) + { + inform (DECL_SOURCE_LOCATION (decl), + "%q#D inherits from multiple base subobjects", + decl); + informed = true; + } + } if (!informed) { tree parms = FUNCTION_FIRST_USER_PARMTYPE (decl); @@ -1668,7 +1799,7 @@ maybe_explain_implicit_delete (tree decl) synthesized_method_walk (ctype, sfk, const_p, &raises, NULL, &deleted_p, NULL, false, - DECL_INHERITED_CTOR_BASE (decl), parms); + DECL_INHERITED_CTOR (decl), parms); if (deleted_p) { inform (DECL_SOURCE_LOCATION (decl), @@ -1676,7 +1807,7 @@ maybe_explain_implicit_delete (tree decl) "definition would be ill-formed:", decl); synthesized_method_walk (ctype, sfk, const_p, NULL, NULL, NULL, NULL, true, - DECL_INHERITED_CTOR_BASE (decl), parms); + DECL_INHERITED_CTOR (decl), parms); } else if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)), @@ -1709,7 +1840,7 @@ explain_implicit_non_constexpr (tree decl) synthesized_method_walk (DECL_CLASS_CONTEXT (decl), special_function_p (decl), const_p, NULL, NULL, NULL, &dummy, true, - DECL_INHERITED_CTOR_BASE (decl), + DECL_INHERITED_CTOR (decl), FUNCTION_FIRST_USER_PARMTYPE (decl)); } @@ -1720,14 +1851,17 @@ explain_implicit_non_constexpr (tree decl) void deduce_inheriting_ctor (tree decl) { - gcc_assert (DECL_INHERITED_CTOR_BASE (decl)); + gcc_assert (DECL_INHERITED_CTOR (decl)); tree spec; bool trivial, constexpr_, deleted; synthesized_method_walk (DECL_CONTEXT (decl), sfk_inheriting_constructor, false, &spec, &trivial, &deleted, &constexpr_, /*diag*/false, - DECL_INHERITED_CTOR_BASE (decl), + DECL_INHERITED_CTOR (decl), FUNCTION_FIRST_USER_PARMTYPE (decl)); + if (TREE_CODE (inherited_ctor_binfo (decl)) != TREE_BINFO) + /* Inherited the same constructor from different base subobjects. */ + deleted = true; DECL_DELETED_FN (decl) = deleted; TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), spec); } @@ -1828,9 +1962,6 @@ implicitly_declare_fn (special_function_kind kind, tree type, gcc_unreachable (); } - tree inherited_base = (inherited_ctor - ? DECL_CONTEXT (inherited_ctor) - : NULL_TREE); bool trivial_p = false; if (inherited_ctor && TREE_CODE (inherited_ctor) == TEMPLATE_DECL) @@ -1846,12 +1977,12 @@ implicitly_declare_fn (special_function_kind kind, tree type, raises = unevaluated_noexcept_spec (); synthesized_method_walk (type, kind, const_p, NULL, &trivial_p, &deleted_p, &constexpr_p, false, - inherited_base, inherited_parms); + inherited_ctor, inherited_parms); } else synthesized_method_walk (type, kind, const_p, &raises, &trivial_p, &deleted_p, &constexpr_p, false, - inherited_base, inherited_parms); + inherited_ctor, inherited_parms); /* Don't bother marking a deleted constructor as constexpr. */ if (deleted_p) constexpr_p = false; @@ -1902,7 +2033,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, { tree *p = &DECL_ARGUMENTS (fn); int index = 1; - for (tree parm = inherited_parms; parm != void_list_node; + for (tree parm = inherited_parms; parm && parm != void_list_node; parm = TREE_CHAIN (parm)) { *p = cp_build_parm_decl (NULL_TREE, TREE_VALUE (parm)); @@ -1912,7 +2043,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, DECL_CONTEXT (*p) = fn; p = &DECL_CHAIN (*p); } - SET_DECL_INHERITED_CTOR_BASE (fn, inherited_base); + SET_DECL_INHERITED_CTOR (fn, inherited_ctor); DECL_NONCONVERTING_P (fn) = DECL_NONCONVERTING_P (inherited_ctor); /* A constructor so declared has the same access as the corresponding constructor in X. */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 023ed87098f1..e574c271194a 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3421,6 +3421,12 @@ do_class_using_decl (tree scope, tree name) return NULL_TREE; } } + else if (name == ctor_identifier + && BINFO_INHERITANCE_CHAIN (BINFO_INHERITANCE_CHAIN (binfo))) + { + error ("cannot inherit constructors from indirect base %qT", scope); + return NULL_TREE; + } else if (!name_dependent_p) { decl = lookup_member (binfo, name, 0, false, tf_warning_or_error); diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index e2032c1d90ef..b926ef7ad6ca 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -166,7 +166,8 @@ cdtor_comdat_group (tree complete, tree base) { gcc_assert (!diff_seen && idx > 0 - && (p[idx - 1] == 'C' || p[idx - 1] == 'D') + && (p[idx - 1] == 'C' || p[idx - 1] == 'D' + || p[idx - 1] == 'I') && p[idx] == '1' && q[idx] == '2'); grp_name[idx] = '5'; @@ -259,6 +260,11 @@ maybe_thunk_body (tree fn, bool force) (for non-vague linkage ctors) or the COMDAT group (otherwise). */ populate_clone_array (fn, fns); + + /* Don't use thunks if the base clone omits inherited parameters. */ + if (ctor_omit_inherited_parms (fns[0])) + return 0; + DECL_ABSTRACT_P (fn) = false; if (!DECL_WEAK (fn)) { @@ -490,7 +496,7 @@ maybe_clone_body (tree fn) parm = DECL_CHAIN (parm); if (DECL_HAS_VTT_PARM_P (clone)) clone_parm = DECL_CHAIN (clone_parm); - for (; parm; + for (; parm && clone_parm; parm = DECL_CHAIN (parm), clone_parm = DECL_CHAIN (clone_parm)) /* Update this parameter. */ update_cloned_parm (parm, clone_parm, first); @@ -616,7 +622,8 @@ maybe_clone_body (tree fn) else { decl_map->put (parm, clone_parm); - clone_parm = DECL_CHAIN (clone_parm); + if (clone_parm) + clone_parm = DECL_CHAIN (clone_parm); } } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 73522131b634..e5134487816b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12056,7 +12056,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) maybe_retrofit_in_chrg (r); if (DECL_CONSTRUCTOR_P (r)) grok_ctor_properties (ctx, r); - if (DECL_INHERITED_CTOR_BASE (r)) + if (DECL_INHERITED_CTOR (r)) deduce_inheriting_ctor (r); /* If this is an instantiation of a member template, clone it. If it isn't, that'll be handled by @@ -17663,11 +17663,16 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain) DECL_TI_ARGS (fndecl) = targ_ptr; /* Now we know the specialization, compute access previously - deferred. */ - push_access_scope (fndecl); - if (!perform_deferred_access_checks (complain)) - access_ok = false; - pop_access_scope (fndecl); + deferred. Do no access control for inheriting constructors, + as we already checked access for the inherited constructor. */ + if (!(flag_new_inheriting_ctors + && DECL_INHERITED_CTOR (fndecl))) + { + push_access_scope (fndecl); + if (!perform_deferred_access_checks (complain)) + access_ok = false; + pop_access_scope (fndecl); + } pop_deferring_access_checks (); /* If we've just instantiated the main entry point for a function, @@ -17825,6 +17830,11 @@ fn_type_unification (tree fn, static int deduction_depth; struct pending_template *old_last_pend = last_pending_template; struct tinst_level *old_error_tinst = last_error_tinst_level; + + tree orig_fn = fn; + if (flag_new_inheriting_ctors) + fn = strip_inheriting_ctors (fn); + tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (fn); tree tinst; tree r = error_mark_node; @@ -18113,6 +18123,11 @@ fn_type_unification (tree fn, } } + /* After doing deduction with the inherited constructor, actually return an + instantiation of the inheriting constructor. */ + if (orig_fn != fn) + decl = instantiate_template (orig_fn, targs, complain); + r = decl; fail: diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 03eef0030d07..ac15d67eafb2 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -4282,7 +4282,7 @@ special_function_p (const_tree decl) /* Rather than doing all this stuff with magic names, we should probably have a field of type `special_function_kind' in DECL_LANG_SPECIFIC. */ - if (DECL_INHERITED_CTOR_BASE (decl)) + if (DECL_INHERITED_CTOR (decl)) return sfk_inheriting_constructor; if (DECL_COPY_CONSTRUCTOR_P (decl)) return sfk_copy_constructor; diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index fd783bf862df..ad9304fdeff0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -199,6 +199,7 @@ in the following sections. -fno-implicit-templates @gol -fno-implicit-inline-templates @gol -fno-implement-inlines -fms-extensions @gol +-fnew-inheriting-ctors @gol -fno-nonansi-builtins -fnothrow-opt -fno-operator-names @gol -fno-optional-diags -fpermissive @gol -fno-pretty-templates @gol @@ -2220,6 +2221,10 @@ Version 10, which first appeared in G++ 6.1, adds mangling of attributes that affect type identity, such as ia32 calling convention attributes (e.g. @samp{stdcall}). +Version 11, which first appeared in G++ 7, corrects the mangling of +sizeof... expressions. It also implies +@option{-fnew-inheriting-ctors}. + See also @option{-Wabi}. @item -fabi-compat-version=@var{n} @@ -2413,6 +2418,13 @@ errors if these functions are not inlined everywhere they are called. Disable Wpedantic warnings about constructs used in MFC, such as implicit int and getting a pointer to member function via non-standard syntax. +@item -fnew-inheriting-ctors +@opindex fnew-inheriting-ctors +Enable the P0136 adjustment to the semantics of C++11 constructor +inheritance. This is part of C++17 but also considered to be a Defect +Report against C++11 and C++14. This flag is enabled by default +unless @option{-fabi-version=10} or lower is specified. + @item -fno-nonansi-builtins @opindex fno-nonansi-builtins Disable built-in declarations of functions that are not mandated by diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C index ee8757f4dcf4..98691101e860 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C @@ -9,7 +9,7 @@ struct A struct B : A { - using A::A; // { dg-error "A::i" } + using A::A; // { dg-prune-output "A::i" } }; -constexpr B b(0); // { dg-error "B::B" } +constexpr B b(0); // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C index 228e8ec66091..4fc67a4a56a5 100644 --- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C @@ -1,4 +1,5 @@ // { dg-do compile { target c++11 } } +// { dg-options -fno-new-inheriting-ctors } struct A { diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor11a.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11a.C new file mode 100644 index 000000000000..61b251eb0ba1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11a.C @@ -0,0 +1,15 @@ +// { dg-do compile { target c++11 } } +// { dg-options -fnew-inheriting-ctors } + +struct A +{ + A(int, ...); +}; + +struct B: A +{ + using A::A; +}; + +B b1(42); +B b2(42, 1.0); // { dg-bogus "ellipsis" "" { xfail *-*-* } } diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C index c2d33bff4ffe..a0b518c19d34 100644 --- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C @@ -2,6 +2,7 @@ // constructors was a deliberate choice. // { dg-do compile { target c++11 } } +// { dg-options -fno-new-inheriting-ctors } struct A { A(int); }; struct B: public A diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor15a.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15a.C new file mode 100644 index 000000000000..a9abb8428a1a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15a.C @@ -0,0 +1,14 @@ +// P0136 caused us to start inheriting base copy constructors. +// { dg-do compile { target c++11 } } +// { dg-options -fnew-inheriting-ctors } + +struct A { A(int); }; +struct B: public A +{ + using A::A; +}; + +A a (42); + +B b1 (24); // inherited +B b2 (a); // also inherited now diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C index e8dc84d32ec8..8cbeed660479 100644 --- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C @@ -1,4 +1,5 @@ // { dg-do compile { target c++11 } } +// { dg-options -fno-new-inheriting-ctors } struct B1 { B1(int); diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor3a.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3a.C new file mode 100644 index 000000000000..c9b4ea114121 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3a.C @@ -0,0 +1,21 @@ +// { dg-do compile { target c++11 } } +// { dg-options -fnew-inheriting-ctors } + +struct B1 { + B1(int); +}; +struct B2 { + B2(int); +}; +struct D1 : B1, B2 { + using B1::B1; + using B2::B2; +}; // ambiguous +struct D2 : B1, B2 { + using B1::B1; + using B2::B2; + D2(int); // OK: user declaration supersedes both implicit declarations +}; + +D2 d2(42); +D1 d1(42); // { dg-error "ambiguous" } diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C index 8c79c833a322..d0038c16a142 100644 --- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C @@ -15,7 +15,7 @@ void test() { D1 e; // { dg-error "deleted" } D1 has no default constructor } struct D2 : B2 { - using B2::B2; // { dg-error "no match" } implicitly declares D2(double) + using B2::B2; // { dg-error "B1::B1" } B1 b; }; D2 f(1.0); // { dg-error "deleted" } B1 has no default constructor diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C index 676605db9e93..5bfdd499d46c 100644 --- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C +++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C @@ -9,7 +9,7 @@ protected: struct B: A { - using A::A; // { dg-message "protected" } + using A::A; }; B b(42); // { dg-error "this context" } diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor1.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor1.C new file mode 100644 index 000000000000..bf9df415c059 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor1.C @@ -0,0 +1,5 @@ +// { dg-do compile { target c++11 } } + +struct A { }; +struct B: A { }; +struct C: B { using A::A; }; // { dg-error "direct" } diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor22.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor22.C new file mode 100644 index 000000000000..02ec58a3e8e0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor22.C @@ -0,0 +1,33 @@ +// Testcase from P0136 +// { dg-do compile { target c++11 } } + +struct B1 { + template + B1(int, Ts...) { } +}; + +struct B2 { + B2(double) { } +}; + +int get(); + +struct D1 : B1 { // { dg-message "B1::B1" } + using B1::B1; // inherits B1(int, ...) + int x; + int y = get(); +}; + +void test() { + D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4), + // then d.x is default-initialized (no initialization is performed), + // then d.y is initialized by calling get() + D1 e; // { dg-error "" } D1 has a deleted default constructor +} + +struct D2 : B2 { + using B2::B2; // { dg-message "B1::B1" } + B1 b; +}; + +D2 f(1.0); // { dg-error "" } B1 has no default constructor diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C new file mode 100644 index 000000000000..0c862f7573f4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C @@ -0,0 +1,19 @@ +// Testcase from P0136 +// { dg-do compile { target c++11 } } +// { dg-options "-fnew-inheriting-ctors -fdump-tree-gimple" } + +struct W { W(int); }; +struct V: W { using W::W; }; +struct X : virtual V { using V::V; X() = delete; }; +struct Y : X { using X::X; }; +struct Z : Y, virtual V { using Y::Y; }; +Z z(0); // OK: initialization of Y does not invoke default constructor of X + +// Check that we're passing this and __vtt along to the Y inheriting +// constructor, but not the int parameter. +// { dg-final { scan-assembler "_ZN1YCI21WEi" } } +// { dg-final { scan-tree-dump "Y::Y ._2, _3.;" "gimple" } } + +// And that we *are* passing the int along to V::V. +// { dg-final { scan-assembler "_ZN1VCI21WEi" } } +// { dg-final { scan-tree-dump "V::V .this, _1.;" "gimple" } } diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor24.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor24.C new file mode 100644 index 000000000000..21450196da0e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor24.C @@ -0,0 +1,27 @@ +// Testcase from P0136 +// { dg-do compile { target c++11 } } +// { dg-options -fnew-inheriting-ctors } + +struct A { A(int); }; +struct B : A { using A::A; }; + +struct C1 : B { using B::B; }; +struct C2 : B { using B::B; }; + +struct D1 : C1, C2 { + using C1::C1; + using C2::C2; +}; + +struct V1 : virtual B { using B::B; }; +struct V2 : virtual B { using B::B; }; + +struct D2 : V1, V2 { + using V1::V1; + using V2::V2; +}; + +D1 d1(0); // { dg-error "" } ambiguous +D2 d2(0); // OK: initializes virtual B base class, which initializes the A base + // class then initializes the V1 and V2 base classes as if by a + // defaulted default constructor diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor25.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor25.C new file mode 100644 index 000000000000..66cd2dabb0d2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor25.C @@ -0,0 +1,9 @@ +// Testcase from P0136 +// { dg-do compile { target c++11 } } + +struct M { M(); M(int); }; +struct N : M { using M::M; }; +struct O : M {}; +struct P : N, O { using N::N; using O::O; }; +P p(0); // OK: use M(0) to initialize N's base class, + // use M() to initialize O's base class diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor26.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor26.C new file mode 100644 index 000000000000..28dc33227a88 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor26.C @@ -0,0 +1,17 @@ +// Testcase from P0136 +// { dg-do compile { target c++11 } } +// { dg-options -fnew-inheriting-ctors } + +struct A { + template A(T, typename T::type = 0); + A(int); +}; +struct B : A { + using A::A; + B(int); +}; +B b(42L); // now calls B(int), used to call B(long), + // which called A(int) due to substitution failure + // in A(long). + +// { dg-final { scan-assembler "_ZN1BC1Ei" } } diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor27.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor27.C new file mode 100644 index 000000000000..97f26346b78a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor27.C @@ -0,0 +1,15 @@ +// { dg-do compile { target c++11 } } + +struct A +{ + A(int = 0); +}; + +struct B: A +{ + B(); + using A::A; +}; + +B b1(1); +B b; diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor28.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor28.C new file mode 100644 index 000000000000..55e1d8c943f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor28.C @@ -0,0 +1,7 @@ +// { dg-do compile { target c++11 } } +// { dg-options -fnew-inheriting-ctors } + +struct V { V(int); }; +struct W : virtual V { using V::V; }; +struct X : virtual W, virtual V { using W::W; }; +X x(0); diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor29.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor29.C new file mode 100644 index 000000000000..97f26346b78a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor29.C @@ -0,0 +1,15 @@ +// { dg-do compile { target c++11 } } + +struct A +{ + A(int = 0); +}; + +struct B: A +{ + B(); + using A::A; +}; + +B b1(1); +B b; diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor30.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor30.C new file mode 100644 index 000000000000..494dd91bb80c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor30.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++11 } } + +struct A +{ + A(double); +}; + +struct B: A +{ + B(short); + using A::A; +}; + +int main() +{ + B b(1); // { dg-error "ambiguous" } +} diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor31.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor31.C new file mode 100644 index 000000000000..3ce080d115b0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor31.C @@ -0,0 +1,15 @@ +// { dg-do compile { target c++11 } } + +struct B; +struct A +{ + A(const B&, int = 0); +}; + +struct B: A +{ + using A::A; +}; + +extern B b; +B b2{b}; diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor32.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor32.C new file mode 100644 index 000000000000..7ce85b0af2ed --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor32.C @@ -0,0 +1,16 @@ +// { dg-do compile { target c++11 } } + +struct B; +struct A +{ + A(const B&, int = 0); +}; + +struct B: A +{ + using A::A; + B(B&); +}; + +extern const B b; +B b2{b}; // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor33.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor33.C new file mode 100644 index 000000000000..0e8520745a96 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor33.C @@ -0,0 +1,23 @@ +// { dg-do link { target c++11 } } +// { dg-options -fnew-inheriting-ctors } + +struct A +{ + A() { } + A(const A&); // should never be called +}; + +struct B +{ + B(A) { } +}; + +struct C: B +{ + using B::B; +}; + +int main() +{ + C c{A()}; +} diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor34.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor34.C new file mode 100644 index 000000000000..f47b2a4dc2fc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor34.C @@ -0,0 +1,18 @@ +// { dg-do compile { target c++11 } } +// { dg-options -fnew-inheriting-ctors } + +class A +{ + A(int); + friend void f(); +}; + +struct B: A +{ + using A::A; +}; + +void f() +{ + B b(42); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor35.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35.C new file mode 100644 index 000000000000..87f4452c6665 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35.C @@ -0,0 +1,21 @@ +// Core 1715 +// { dg-do compile { target c++11 } } +// { dg-options -fno-new-inheriting-ctors } + +template struct S { +private: + typedef int X; + friend struct B; +}; + +struct B { + template B(T, typename T::X); +}; + +struct D: B { + using B::B; // { dg-prune-output "private" } +}; + +S s; +B b(s, 2); // Okay, thanks to friendship. +D d(s, 2); // { dg-error "" } was an error before P0136 diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor35a.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35a.C new file mode 100644 index 000000000000..47f69de41b80 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35a.C @@ -0,0 +1,21 @@ +// Core 1715 +// { dg-do compile { target c++11 } } +// { dg-options -fnew-inheriting-ctors } + +template struct S { +private: + typedef int X; + friend struct B; +}; + +struct B { + template B(T, typename T::X); +}; + +struct D: B { + using B::B; +}; + +S s; +B b(s, 2); // Okay, thanks to friendship. +D d(s, 2); // Now OK as well. diff --git a/gcc/testsuite/g++.dg/cpp1z/using1.C b/gcc/testsuite/g++.dg/cpp1z/using1.C new file mode 100644 index 000000000000..1ed939d45fd4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/using1.C @@ -0,0 +1,23 @@ +// Test for hiding of used base functions when all the conversion sequences are +// equivalent, needed to avoid a regression on inherited default ctors. + +struct A +{ + void f(short,int=0); + void g(char,int=0); +}; + +struct B:A +{ + using A::f; + void f(short); + using A::g; + void g(short); +}; + +int main() +{ + B().f(1); // OK, derived f hides base f for single arg + B().f(1,2); // OK, base f can still be called with two args + B().g(1); // { dg-error "" } signatures differ, ambiguous +} diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index de5e57570801..6899d2a8736c 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1045,6 +1045,7 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data) copy_body_data *id = (copy_body_data *) data; tree fn = id->src_fn; tree new_block; + bool copied = false; /* Begin by recognizing trees that we'll completely rewrite for the inlining context. Our output for these trees is completely @@ -1241,10 +1242,40 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data) *walk_subtrees = 0; return NULL; } + else if (TREE_CODE (*tp) == COND_EXPR) + { + tree cond = TREE_OPERAND (*tp, 0); + walk_tree (&cond, copy_tree_body_r, data, NULL); + tree folded = fold (cond); + if (TREE_CODE (folded) == INTEGER_CST) + { + /* Only copy the taken branch; for a C++ base constructor clone + inherited from a virtual base, copying the other branch leads + to references to parameters that were optimized away. */ + tree branch = (integer_nonzerop (folded) + ? TREE_OPERAND (*tp, 1) + : TREE_OPERAND (*tp, 2)); + tree type = TREE_TYPE (*tp); + if (VOID_TYPE_P (type) + || type == TREE_TYPE (branch)) + { + *tp = branch; + return copy_tree_body_r (tp, walk_subtrees, data); + } + } + /* Avoid copying the condition twice. */ + copy_tree_r (tp, walk_subtrees, NULL); + TREE_OPERAND (*tp, 0) = cond; + walk_tree (&TREE_OPERAND (*tp, 1), copy_tree_body_r, data, NULL); + walk_tree (&TREE_OPERAND (*tp, 2), copy_tree_body_r, data, NULL); + *walk_subtrees = 0; + copied = true; + } /* Here is the "usual case". Copy this tree node, and then tweak some special cases. */ - copy_tree_r (tp, walk_subtrees, NULL); + if (!copied) + copy_tree_r (tp, walk_subtrees, NULL); /* If EXPR has block defined, map it to newly constructed block. When inlining we want EXPRs without block appear in the block diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 73cbcc41c60c..bb4dee41a550 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,7 @@ +2016-11-01 Jason Merrill + + * cp-demangle.c (d_ctor_dtor_name): Handle inheriting constructor. + 2016-10-31 Mark Wielaard * cplus-dem.c (ada_demangle): Initialize demangled to NULL and diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index a843dc38f98c..46382ccee22e 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -2168,6 +2168,13 @@ d_ctor_dtor_name (struct d_info *di) case 'C': { enum gnu_v3_ctor_kinds kind; + int inheriting = 0; + + if (d_peek_next_char (di) == 'I') + { + inheriting = 1; + d_advance (di, 1); + } switch (d_peek_next_char (di)) { @@ -2189,7 +2196,12 @@ d_ctor_dtor_name (struct d_info *di) default: return NULL; } + d_advance (di, 2); + + if (inheriting) + cplus_demangle_type (di); + return d_make_ctor (di, kind, di->last_name); } diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected index a5a658a70959..a56776355bfe 100644 --- a/libiberty/testsuite/demangle-expected +++ b/libiberty/testsuite/demangle-expected @@ -4592,3 +4592,7 @@ __t2m05B500000000000000000_ __10%0__S4_0T0T0 %0<>::%0(%0<>) + +# Inheriting constructor +_ZN1DCI11BEi +D::B(int)