+2016-11-01 Jason Merrill <jason@redhat.com>
+
+ * tree-inline.c (copy_tree_body_r): Only copy the taken branch of
+ a COND_EXPR with constant condition.
+
2016-11-01 Jakub Jelinek <jakub@redhat.com>
* dwarf2out.c (gen_variable_die): Remove again origin_die variable
+2016-11-01 Jason Merrill <jason@redhat.com>
+
+ * c.opt (-fnew-inheriting-ctors): New.
+ * c-opts.c: Default to on for ABI 11+.
+
2016-10-31 Jakub Jelinek <jakub@redhat.com>
PR c++/77948
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
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.
; 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
+2016-11-01 Jason Merrill <jason@redhat.com>
+
+ 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 <jakub@redhat.com>
* cp-objcp-common.c (cp_decl_dwarf_attribute): Handle DW_AT_inline.
rr_bad_arg_conversion,
rr_template_unification,
rr_invalid_copy,
+ rr_inherited_ctor,
rr_constraint_failure
};
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.
}
}
+ /* 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,
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)
{
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
{
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);
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)
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. */
}
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;
}
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.
bool complete_p;
bool insert_p = false;
tree current_fns;
- tree fns;
if (method == error_mark_node)
return false;
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;
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
== 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. */
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);
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;
/* 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);
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. */
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))
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;
}
}
}
+ /* 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;
{
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
{
(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. */
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);
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)
{
}
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
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,
/* 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;
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 <special-name>.
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. */
{
/* 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;
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);
{
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);
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. */
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;
}
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
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;
/* 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);
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);
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;
}
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);
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),
"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)),
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));
}
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);
}
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)
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;
{
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));
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. */
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);
{
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';
(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))
{
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);
else
{
decl_map->put (parm, clone_parm);
- clone_parm = DECL_CHAIN (clone_parm);
+ if (clone_parm)
+ clone_parm = DECL_CHAIN (clone_parm);
}
}
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
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,
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;
}
}
+ /* 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:
/* 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;
-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
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}
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
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 "" }
// { dg-do compile { target c++11 } }
+// { dg-options -fno-new-inheriting-ctors }
struct A
{
--- /dev/null
+// { 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 *-*-* } }
// 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
--- /dev/null
+// 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
// { dg-do compile { target c++11 } }
+// { dg-options -fno-new-inheriting-ctors }
struct B1 {
B1(int);
--- /dev/null
+// { 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" }
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
struct B: A
{
- using A::A; // { dg-message "protected" }
+ using A::A;
};
B b(42); // { dg-error "this context" }
--- /dev/null
+// { dg-do compile { target c++11 } }
+
+struct A { };
+struct B: A { };
+struct C: B { using A::A; }; // { dg-error "direct" }
--- /dev/null
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+
+struct B1 {
+ template <class... Ts>
+ 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
--- /dev/null
+// 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" } }
--- /dev/null
+// 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
--- /dev/null
+// 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
--- /dev/null
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct A {
+ template<typename T> 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>(long),
+ // which called A(int) due to substitution failure
+ // in A<long>(long).
+
+// { dg-final { scan-assembler "_ZN1BC1Ei" } }
--- /dev/null
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+ A(int = 0);
+};
+
+struct B: A
+{
+ B();
+ using A::A;
+};
+
+B b1(1);
+B b;
--- /dev/null
+// { 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);
--- /dev/null
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+ A(int = 0);
+};
+
+struct B: A
+{
+ B();
+ using A::A;
+};
+
+B b1(1);
+B b;
--- /dev/null
+// { 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" }
+}
--- /dev/null
+// { 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};
--- /dev/null
+// { 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 "" }
--- /dev/null
+// { 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()};
+}
--- /dev/null
+// { 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);
+}
--- /dev/null
+// Core 1715
+// { dg-do compile { target c++11 } }
+// { dg-options -fno-new-inheriting-ctors }
+
+template<class T> struct S {
+private:
+ typedef int X;
+ friend struct B;
+};
+
+struct B {
+ template<class T> B(T, typename T::X);
+};
+
+struct D: B {
+ using B::B; // { dg-prune-output "private" }
+};
+
+S<int> s;
+B b(s, 2); // Okay, thanks to friendship.
+D d(s, 2); // { dg-error "" } was an error before P0136
--- /dev/null
+// Core 1715
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+template<class T> struct S {
+private:
+ typedef int X;
+ friend struct B;
+};
+
+struct B {
+ template<class T> B(T, typename T::X);
+};
+
+struct D: B {
+ using B::B;
+};
+
+S<int> s;
+B b(s, 2); // Okay, thanks to friendship.
+D d(s, 2); // Now OK as well.
--- /dev/null
+// 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
+}
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
*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
+2016-11-01 Jason Merrill <jason@redhat.com>
+
+ * cp-demangle.c (d_ctor_dtor_name): Handle inheriting constructor.
+
2016-10-31 Mark Wielaard <mjw@redhat.com>
* cplus-dem.c (ada_demangle): Initialize demangled to NULL and
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))
{
default:
return NULL;
}
+
d_advance (di, 2);
+
+ if (inheriting)
+ cplus_demangle_type (di);
+
return d_make_ctor (di, kind, di->last_name);
}
__10%0__S4_0T0T0
%0<>::%0(%0<>)
+
+# Inheriting constructor
+_ZN1DCI11BEi
+D::B(int)