Implement C++11 inheriting constructors.
* cp-tree.h (cpp0x_warn_str): Add CPP0X_INHERITING_CTORS. (DECL_INHERITED_CTOR_BASE, SET_DECL_INHERITED_CTOR_BASE): New. (special_function_kind): Add sfk_inheriting_constructor. * class.c (add_method): An inheriting ctor is hidden by a user-declared one. (one_inheriting_sig, one_inherited_ctor): New. (add_implicitly_declared_members): Handle inheriting ctors. * error.c (maybe_warn_cpp0x): Handle CPP0X_INHERITING_CTORS. * init.c (emit_mem_initializers): Don't set LOOKUP_DEFAULTED for an inheriting constructor. * method.c (type_has_trivial_fn): Handle sfk_inheriting_constructor. (type_set_nontrivial_flag): Likewise. (add_one_base_init): Split out from... (do_build_copy_constructor): ...here. Handle inheriting constructors. (locate_fn_flags): Handle a list of arg types. (synthesized_method_walk): Handle inheriting constructors. (maybe_explain_implicit_delete): Likewise. (deduce_inheriting_ctor): New. (implicitly_declare_fn): Handle inheriting constructors. * name-lookup.c (push_class_level_binding_1): An inheriting constructor does not declare the base's name. (do_class_using_decl): Allow inheriting constructors. * pt.c (template_parms_to_args): Split from current_template_args. (add_inherited_template_parms): New. (tsubst_decl): Handle inheriting constructors. * tree.c (special_function_p): Handle inheriting constructors. Co-Authored-By: Ville Voutilainen <ville.voutilainen@gmail.com> From-SVN: r192448
This commit is contained in:
parent
d0d4f8c78e
commit
85b5d65a94
23 changed files with 622 additions and 62 deletions
|
@ -1,3 +1,34 @@
|
|||
2012-10-14 Jason Merrill <jason@redhat.com>
|
||||
Ville Voutilainen <ville.voutilainen@gmail.com>
|
||||
|
||||
Implement C++11 inheriting constructors.
|
||||
* cp-tree.h (cpp0x_warn_str): Add CPP0X_INHERITING_CTORS.
|
||||
(DECL_INHERITED_CTOR_BASE, SET_DECL_INHERITED_CTOR_BASE): New.
|
||||
(special_function_kind): Add sfk_inheriting_constructor.
|
||||
* class.c (add_method): An inheriting ctor is hidden by a
|
||||
user-declared one.
|
||||
(one_inheriting_sig, one_inherited_ctor): New.
|
||||
(add_implicitly_declared_members): Handle inheriting ctors.
|
||||
* error.c (maybe_warn_cpp0x): Handle CPP0X_INHERITING_CTORS.
|
||||
* init.c (emit_mem_initializers): Don't set LOOKUP_DEFAULTED
|
||||
for an inheriting constructor.
|
||||
* method.c (type_has_trivial_fn): Handle sfk_inheriting_constructor.
|
||||
(type_set_nontrivial_flag): Likewise.
|
||||
(add_one_base_init): Split out from...
|
||||
(do_build_copy_constructor): ...here. Handle inheriting constructors.
|
||||
(locate_fn_flags): Handle a list of arg types.
|
||||
(synthesized_method_walk): Handle inheriting constructors.
|
||||
(maybe_explain_implicit_delete): Likewise.
|
||||
(deduce_inheriting_ctor): New.
|
||||
(implicitly_declare_fn): Handle inheriting constructors.
|
||||
* name-lookup.c (push_class_level_binding_1): An inheriting constructor
|
||||
does not declare the base's name.
|
||||
(do_class_using_decl): Allow inheriting constructors.
|
||||
* pt.c (template_parms_to_args): Split from current_template_args.
|
||||
(add_inherited_template_parms): New.
|
||||
(tsubst_decl): Handle inheriting constructors.
|
||||
* tree.c (special_function_p): Handle inheriting constructors.
|
||||
|
||||
2012-10-12 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c/54381
|
||||
|
|
|
@ -132,7 +132,7 @@ static void finish_struct_methods (tree);
|
|||
static void maybe_warn_about_overly_private_class (tree);
|
||||
static int method_name_cmp (const void *, const void *);
|
||||
static int resort_method_name_cmp (const void *, const void *);
|
||||
static void add_implicitly_declared_members (tree, int, int);
|
||||
static void add_implicitly_declared_members (tree, tree*, int, int);
|
||||
static tree fixed_type_or_null (tree, int *, int *);
|
||||
static tree build_simple_base_path (tree expr, tree binfo);
|
||||
static tree build_vtbl_ref_1 (tree, tree);
|
||||
|
@ -1087,6 +1087,20 @@ add_method (tree type, tree method, tree using_decl)
|
|||
|| same_type_p (TREE_TYPE (fn_type),
|
||||
TREE_TYPE (method_type))))
|
||||
{
|
||||
if (DECL_INHERITED_CTOR_BASE (method))
|
||||
{
|
||||
if (DECL_INHERITED_CTOR_BASE (fn))
|
||||
{
|
||||
error_at (DECL_SOURCE_LOCATION (method),
|
||||
"%q#D inherited from %qT", method,
|
||||
DECL_INHERITED_CTOR_BASE (method));
|
||||
error_at (DECL_SOURCE_LOCATION (fn),
|
||||
"conflicts with version inherited from %qT",
|
||||
DECL_INHERITED_CTOR_BASE (fn));
|
||||
}
|
||||
/* Otherwise defer to the other function. */
|
||||
return false;
|
||||
}
|
||||
if (using_decl)
|
||||
{
|
||||
if (DECL_CONTEXT (fn) == type)
|
||||
|
@ -2750,6 +2764,51 @@ declare_virt_assop_and_dtor (tree t)
|
|||
NULL, t);
|
||||
}
|
||||
|
||||
/* Declare the inheriting constructor for class T inherited from base
|
||||
constructor CTOR with the parameter array PARMS of size NPARMS. */
|
||||
|
||||
static void
|
||||
one_inheriting_sig (tree t, tree ctor, tree *parms, int nparms)
|
||||
{
|
||||
/* We don't declare an inheriting ctor that would be a default,
|
||||
copy or move ctor. */
|
||||
if (nparms == 0
|
||||
|| (nparms == 1
|
||||
&& TREE_CODE (parms[0]) == REFERENCE_TYPE
|
||||
&& TYPE_MAIN_VARIANT (TREE_TYPE (parms[0])) == t))
|
||||
return;
|
||||
int i;
|
||||
tree parmlist = void_list_node;
|
||||
for (i = nparms - 1; i >= 0; i--)
|
||||
parmlist = tree_cons (NULL_TREE, parms[i], parmlist);
|
||||
tree fn = implicitly_declare_fn (sfk_inheriting_constructor,
|
||||
t, false, ctor, parmlist);
|
||||
if (add_method (t, fn, NULL_TREE))
|
||||
{
|
||||
DECL_CHAIN (fn) = TYPE_METHODS (t);
|
||||
TYPE_METHODS (t) = fn;
|
||||
}
|
||||
}
|
||||
|
||||
/* Declare all the inheriting constructors for class T inherited from base
|
||||
constructor CTOR. */
|
||||
|
||||
static void
|
||||
one_inherited_ctor (tree ctor, tree t)
|
||||
{
|
||||
tree parms = FUNCTION_FIRST_USER_PARMTYPE (ctor);
|
||||
|
||||
tree *new_parms = XALLOCAVEC (tree, list_length (parms));
|
||||
int i = 0;
|
||||
for (; parms && parms != void_list_node; parms = TREE_CHAIN (parms))
|
||||
{
|
||||
if (TREE_PURPOSE (parms))
|
||||
one_inheriting_sig (t, ctor, new_parms, i);
|
||||
new_parms[i++] = TREE_VALUE (parms);
|
||||
}
|
||||
one_inheriting_sig (t, ctor, new_parms, i);
|
||||
}
|
||||
|
||||
/* Create default constructors, assignment operators, and so forth for
|
||||
the type indicated by T, if they are needed. CANT_HAVE_CONST_CTOR,
|
||||
and CANT_HAVE_CONST_ASSIGNMENT are nonzero if, for whatever reason,
|
||||
|
@ -2758,7 +2817,7 @@ declare_virt_assop_and_dtor (tree t)
|
|||
a const reference, respectively. */
|
||||
|
||||
static void
|
||||
add_implicitly_declared_members (tree t,
|
||||
add_implicitly_declared_members (tree t, tree* access_decls,
|
||||
int cant_have_const_cctor,
|
||||
int cant_have_const_assignment)
|
||||
{
|
||||
|
@ -2826,6 +2885,26 @@ add_implicitly_declared_members (tree t,
|
|||
/* We can't be lazy about declaring functions that might override
|
||||
a virtual function from a base class. */
|
||||
declare_virt_assop_and_dtor (t);
|
||||
|
||||
while (*access_decls)
|
||||
{
|
||||
tree using_decl = TREE_VALUE (*access_decls);
|
||||
tree decl = USING_DECL_DECLS (using_decl);
|
||||
if (DECL_SELF_REFERENCE_P (decl))
|
||||
{
|
||||
/* declare, then remove the decl */
|
||||
tree ctor_list = CLASSTYPE_CONSTRUCTORS (TREE_TYPE (decl));
|
||||
location_t loc = input_location;
|
||||
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);
|
||||
*access_decls = TREE_CHAIN (*access_decls);
|
||||
input_location = loc;
|
||||
}
|
||||
else
|
||||
access_decls = &TREE_CHAIN (*access_decls);
|
||||
}
|
||||
}
|
||||
|
||||
/* Subroutine of insert_into_classtype_sorted_fields. Recursively
|
||||
|
@ -4342,7 +4421,8 @@ deduce_noexcept_on_destructor (tree dtor)
|
|||
{
|
||||
tree ctx = DECL_CONTEXT (dtor);
|
||||
tree implicit_fn = implicitly_declare_fn (sfk_destructor, ctx,
|
||||
/*const_p=*/false);
|
||||
/*const_p=*/false,
|
||||
NULL, NULL);
|
||||
tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
|
||||
TREE_TYPE (dtor) = build_exception_variant (TREE_TYPE (dtor), eh_spec);
|
||||
}
|
||||
|
@ -5135,14 +5215,14 @@ check_bases_and_members (tree t)
|
|||
}
|
||||
|
||||
/* Synthesize any needed methods. */
|
||||
add_implicitly_declared_members (t,
|
||||
add_implicitly_declared_members (t, &access_decls,
|
||||
cant_have_const_ctor,
|
||||
no_const_asn_ref);
|
||||
|
||||
/* Check defaulted declarations here so we have cant_have_const_ctor
|
||||
and don't need to worry about clones. */
|
||||
for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
|
||||
if (DECL_DEFAULTED_IN_CLASS_P (fn))
|
||||
if (!DECL_ARTIFICIAL (fn) && DECL_DEFAULTED_IN_CLASS_P (fn))
|
||||
{
|
||||
int copy = copy_fn_p (fn);
|
||||
if (copy > 0)
|
||||
|
|
|
@ -420,6 +420,8 @@ typedef enum cpp0x_warn_str
|
|||
CPP0X_USER_DEFINED_LITERALS,
|
||||
/* delegating constructors */
|
||||
CPP0X_DELEGATING_CTORS,
|
||||
/* inheriting constructors */
|
||||
CPP0X_INHERITING_CTORS,
|
||||
/* C++11 attributes */
|
||||
CPP0X_ATTRIBUTES
|
||||
} cpp0x_warn_str;
|
||||
|
@ -2384,6 +2386,15 @@ struct GTY((variable_size)) lang_decl {
|
|||
#define SET_DECL_THUNKS(NODE,THUNKS) \
|
||||
(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)
|
||||
|
||||
/* Set the inherited base. */
|
||||
#define SET_DECL_INHERITED_CTOR_BASE(NODE,INH) \
|
||||
(LANG_DECL_FN_CHECK (NODE)->context = (INH))
|
||||
|
||||
/* Nonzero if NODE is a thunk, rather than an ordinary function. */
|
||||
#define DECL_THUNK_P(NODE) \
|
||||
(TREE_CODE (NODE) == FUNCTION_DECL \
|
||||
|
@ -4142,7 +4153,8 @@ typedef enum special_function_kind {
|
|||
sfk_deleting_destructor, /* A destructor for complete objects that
|
||||
deletes the object after it has been
|
||||
destroyed. */
|
||||
sfk_conversion /* A conversion operator. */
|
||||
sfk_conversion, /* A conversion operator. */
|
||||
sfk_inheriting_constructor /* An inheriting constructor */
|
||||
} special_function_kind;
|
||||
|
||||
/* The various kinds of linkage. From [basic.link],
|
||||
|
@ -5323,6 +5335,7 @@ extern void use_thunk (tree, bool);
|
|||
extern bool trivial_fn_p (tree);
|
||||
extern bool maybe_explain_implicit_delete (tree);
|
||||
extern void explain_implicit_non_constexpr (tree);
|
||||
extern void deduce_inheriting_ctor (tree);
|
||||
extern void synthesize_method (tree);
|
||||
extern tree lazily_declare_fn (special_function_kind,
|
||||
tree);
|
||||
|
@ -5335,7 +5348,7 @@ extern tree get_default_ctor (tree);
|
|||
extern tree get_dtor (tree, tsubst_flags_t);
|
||||
extern tree locate_ctor (tree);
|
||||
extern tree implicitly_declare_fn (special_function_kind, tree,
|
||||
bool);
|
||||
bool, tree, tree);
|
||||
|
||||
/* In optimize.c */
|
||||
extern bool maybe_clone_body (tree);
|
||||
|
@ -5370,6 +5383,7 @@ extern tree maybe_update_decl_type (tree, tree);
|
|||
extern bool check_default_tmpl_args (tree, tree, bool, bool, int);
|
||||
extern tree push_template_decl (tree);
|
||||
extern tree push_template_decl_real (tree, bool);
|
||||
extern tree add_inherited_template_parms (tree, tree);
|
||||
extern bool redeclare_class_template (tree, tree);
|
||||
extern tree lookup_template_class (tree, tree, tree, tree,
|
||||
int, tsubst_flags_t);
|
||||
|
|
|
@ -3374,6 +3374,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str)
|
|||
"delegating constructors "
|
||||
"only available with -std=c++11 or -std=gnu++11");
|
||||
break;
|
||||
case CPP0X_INHERITING_CTORS:
|
||||
pedwarn (input_location, 0,
|
||||
"inheriting constructors "
|
||||
"only available with -std=c++11 or -std=gnu++11");
|
||||
break;
|
||||
case CPP0X_ATTRIBUTES:
|
||||
pedwarn (input_location, 0,
|
||||
"c++11 attributes "
|
||||
|
|
|
@ -1036,7 +1036,8 @@ emit_mem_initializers (tree mem_inits)
|
|||
return;
|
||||
}
|
||||
|
||||
if (DECL_DEFAULTED_FN (current_function_decl))
|
||||
if (DECL_DEFAULTED_FN (current_function_decl)
|
||||
&& ! DECL_INHERITED_CTOR_BASE (current_function_decl))
|
||||
flags |= LOOKUP_DEFAULTED;
|
||||
|
||||
/* Sort the mem-initializers into the order in which the
|
||||
|
|
212
gcc/cp/method.c
212
gcc/cp/method.c
|
@ -429,6 +429,8 @@ type_has_trivial_fn (tree ctype, special_function_kind sfk)
|
|||
return !TYPE_HAS_COMPLEX_MOVE_ASSIGN (ctype);
|
||||
case sfk_destructor:
|
||||
return !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype);
|
||||
case sfk_inheriting_constructor:
|
||||
return false;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
@ -460,6 +462,7 @@ type_set_nontrivial_flag (tree ctype, special_function_kind sfk)
|
|||
case sfk_destructor:
|
||||
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype) = true;
|
||||
return;
|
||||
case sfk_inheriting_constructor:
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
@ -478,7 +481,46 @@ trivial_fn_p (tree fn)
|
|||
return type_has_trivial_fn (DECL_CONTEXT (fn), special_function_p (fn));
|
||||
}
|
||||
|
||||
/* Generate code for default X(X&) or X(X&&) constructor. */
|
||||
/* 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. */
|
||||
|
||||
static tree
|
||||
add_one_base_init (tree binfo, tree parm, bool move_p, tree inh,
|
||||
tree member_init_list)
|
||||
{
|
||||
tree init;
|
||||
if (inh)
|
||||
{
|
||||
/* An inheriting constructor only has a mem-initializer for
|
||||
the base it inherits from. */
|
||||
if (BINFO_TYPE (binfo) != inh)
|
||||
return member_init_list;
|
||||
|
||||
tree *p = &init;
|
||||
init = NULL_TREE;
|
||||
for (; parm; parm = DECL_CHAIN (parm))
|
||||
{
|
||||
tree exp = convert_from_reference (parm);
|
||||
if (TREE_CODE (TREE_TYPE (parm)) != REFERENCE_TYPE)
|
||||
exp = move (exp);
|
||||
*p = build_tree_list (NULL_TREE, exp);
|
||||
p = &TREE_CHAIN (*p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
init = build_base_path (PLUS_EXPR, parm, binfo, 1,
|
||||
tf_warning_or_error);
|
||||
if (move_p)
|
||||
init = move (init);
|
||||
init = build_tree_list (NULL_TREE, init);
|
||||
}
|
||||
return tree_cons (binfo, init, member_init_list);
|
||||
}
|
||||
|
||||
/* Generate code for default X(X&) or X(X&&) constructor or an inheriting
|
||||
constructor. */
|
||||
|
||||
static void
|
||||
do_build_copy_constructor (tree fndecl)
|
||||
|
@ -486,8 +528,10 @@ 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);
|
||||
|
||||
parm = convert_from_reference (parm);
|
||||
if (!inh)
|
||||
parm = convert_from_reference (parm);
|
||||
|
||||
if (trivial
|
||||
&& is_empty_class (current_class_type))
|
||||
|
@ -516,14 +560,8 @@ do_build_copy_constructor (tree fndecl)
|
|||
for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0;
|
||||
VEC_iterate (tree, vbases, i, binfo); i++)
|
||||
{
|
||||
init = build_base_path (PLUS_EXPR, parm, binfo, 1,
|
||||
tf_warning_or_error);
|
||||
if (move_p)
|
||||
init = move (init);
|
||||
member_init_list
|
||||
= tree_cons (binfo,
|
||||
build_tree_list (NULL_TREE, init),
|
||||
member_init_list);
|
||||
member_init_list = add_one_base_init (binfo, parm, move_p, inh,
|
||||
member_init_list);
|
||||
}
|
||||
|
||||
for (binfo = TYPE_BINFO (current_class_type), i = 0;
|
||||
|
@ -531,15 +569,8 @@ do_build_copy_constructor (tree fndecl)
|
|||
{
|
||||
if (BINFO_VIRTUAL_P (base_binfo))
|
||||
continue;
|
||||
|
||||
init = build_base_path (PLUS_EXPR, parm, base_binfo, 1,
|
||||
tf_warning_or_error);
|
||||
if (move_p)
|
||||
init = move (init);
|
||||
member_init_list
|
||||
= tree_cons (base_binfo,
|
||||
build_tree_list (NULL_TREE, init),
|
||||
member_init_list);
|
||||
member_init_list = add_one_base_init (base_binfo, parm, move_p,
|
||||
inh, member_init_list);
|
||||
}
|
||||
|
||||
for (; fields; fields = DECL_CHAIN (fields))
|
||||
|
@ -549,6 +580,8 @@ do_build_copy_constructor (tree fndecl)
|
|||
|
||||
if (TREE_CODE (field) != FIELD_DECL)
|
||||
continue;
|
||||
if (inh)
|
||||
continue;
|
||||
|
||||
expr_type = TREE_TYPE (field);
|
||||
if (DECL_NAME (field))
|
||||
|
@ -833,8 +866,23 @@ locate_fn_flags (tree type, tree name, tree argtype, int flags,
|
|||
args = make_tree_vector ();
|
||||
if (argtype)
|
||||
{
|
||||
tree arg = build_stub_object (argtype);
|
||||
VEC_quick_push (tree, args, arg);
|
||||
if (TREE_CODE (argtype) == TREE_LIST)
|
||||
{
|
||||
for (tree elt = argtype; elt != void_list_node;
|
||||
elt = TREE_CHAIN (elt))
|
||||
{
|
||||
tree type = TREE_VALUE (elt);
|
||||
if (TREE_CODE (type) != REFERENCE_TYPE)
|
||||
type = cp_build_reference_type (type, /*rval*/true);
|
||||
tree arg = build_stub_object (type);
|
||||
VEC_safe_push (tree, gc, args, arg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tree arg = build_stub_object (argtype);
|
||||
VEC_quick_push (tree, args, arg);
|
||||
}
|
||||
}
|
||||
|
||||
fns = lookup_fnfields (binfo, name, 0);
|
||||
|
@ -1110,7 +1158,8 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
|
|||
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 *no_implicit_p, bool diag)
|
||||
bool *constexpr_p, bool *no_implicit_p, bool diag,
|
||||
tree inherited_base, tree inherited_parms)
|
||||
{
|
||||
tree binfo, base_binfo, scope, fnname, rval, argtype;
|
||||
bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
|
||||
|
@ -1162,6 +1211,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
|
|||
case sfk_constructor:
|
||||
case sfk_move_constructor:
|
||||
case sfk_copy_constructor:
|
||||
case sfk_inheriting_constructor:
|
||||
ctor_p = true;
|
||||
fnname = complete_ctor_identifier;
|
||||
break;
|
||||
|
@ -1170,6 +1220,9 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
|
|||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
gcc_assert ((sfk == sfk_inheriting_constructor)
|
||||
== (inherited_base != NULL_TREE));
|
||||
|
||||
/* If that user-written default constructor would satisfy the
|
||||
requirements of a constexpr constructor (7.1.5), the
|
||||
implicitly-defined default constructor is constexpr. */
|
||||
|
@ -1181,6 +1234,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
|
|||
{
|
||||
case sfk_constructor:
|
||||
case sfk_destructor:
|
||||
case sfk_inheriting_constructor:
|
||||
copy_arg_p = false;
|
||||
break;
|
||||
|
||||
|
@ -1231,7 +1285,9 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
|
|||
|
||||
scope = push_scope (ctype);
|
||||
|
||||
flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
|
||||
flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE;
|
||||
if (!inherited_base)
|
||||
flags |= LOOKUP_DEFAULTED;
|
||||
|
||||
complain = diag ? tf_warning_or_error : tf_none;
|
||||
|
||||
|
@ -1252,7 +1308,11 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
|
|||
|
||||
if (copy_arg_p)
|
||||
argtype = build_stub_type (basetype, quals, move_p);
|
||||
else if (basetype == inherited_base)
|
||||
argtype = inherited_parms;
|
||||
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
|
||||
if (inherited_base)
|
||||
argtype = NULL_TREE;
|
||||
|
||||
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
|
||||
constexpr_p, no_implicit_p, diag, basetype);
|
||||
|
@ -1405,14 +1465,16 @@ maybe_explain_implicit_delete (tree decl)
|
|||
}
|
||||
if (!informed)
|
||||
{
|
||||
tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl));
|
||||
tree parms = FUNCTION_FIRST_USER_PARMTYPE (decl);
|
||||
tree parm_type = TREE_VALUE (parms);
|
||||
bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
|
||||
tree scope = push_scope (ctype);
|
||||
inform (0, "%q+#D is implicitly deleted because the default "
|
||||
"definition would be ill-formed:", decl);
|
||||
pop_scope (scope);
|
||||
synthesized_method_walk (ctype, sfk, const_p,
|
||||
NULL, NULL, NULL, NULL, NULL, true);
|
||||
NULL, NULL, NULL, NULL, NULL, true,
|
||||
DECL_INHERITED_CTOR_BASE (decl), parms);
|
||||
}
|
||||
|
||||
input_location = loc;
|
||||
|
@ -1432,7 +1494,27 @@ explain_implicit_non_constexpr (tree decl)
|
|||
bool dummy;
|
||||
synthesized_method_walk (DECL_CLASS_CONTEXT (decl),
|
||||
special_function_p (decl), const_p,
|
||||
NULL, NULL, NULL, &dummy, NULL, true);
|
||||
NULL, NULL, NULL, &dummy, NULL, true,
|
||||
NULL_TREE, NULL_TREE);
|
||||
}
|
||||
|
||||
/* DECL is an instantiation of an inheriting constructor template. Deduce
|
||||
the correct exception-specification and deletedness for this particular
|
||||
specialization. */
|
||||
|
||||
void
|
||||
deduce_inheriting_ctor (tree decl)
|
||||
{
|
||||
gcc_assert (DECL_INHERITED_CTOR_BASE (decl));
|
||||
tree spec;
|
||||
bool trivial, constexpr_, deleted, no_implicit;
|
||||
synthesized_method_walk (DECL_CONTEXT (decl), sfk_inheriting_constructor,
|
||||
false, &spec, &trivial, &deleted, &constexpr_,
|
||||
&no_implicit, /*diag*/false,
|
||||
DECL_INHERITED_CTOR_BASE (decl),
|
||||
FUNCTION_FIRST_USER_PARMTYPE (decl));
|
||||
DECL_DELETED_FN (decl) = deleted;
|
||||
TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), spec);
|
||||
}
|
||||
|
||||
/* Implicitly declare the special function indicated by KIND, as a
|
||||
|
@ -1442,7 +1524,9 @@ explain_implicit_non_constexpr (tree decl)
|
|||
FUNCTION_DECL for the implicitly declared function. */
|
||||
|
||||
tree
|
||||
implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
|
||||
implicitly_declare_fn (special_function_kind kind, tree type,
|
||||
bool const_p, tree inherited_ctor,
|
||||
tree inherited_parms)
|
||||
{
|
||||
tree fn;
|
||||
tree parameter_types = void_list_node;
|
||||
|
@ -1499,6 +1583,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
|
|||
case sfk_copy_assignment:
|
||||
case sfk_move_constructor:
|
||||
case sfk_move_assignment:
|
||||
case sfk_inheriting_constructor:
|
||||
{
|
||||
bool move_p;
|
||||
if (kind == sfk_copy_assignment
|
||||
|
@ -1510,23 +1595,44 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
|
|||
else
|
||||
name = constructor_name (type);
|
||||
|
||||
if (const_p)
|
||||
rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
|
||||
if (kind == sfk_inheriting_constructor)
|
||||
parameter_types = inherited_parms;
|
||||
else
|
||||
rhs_parm_type = type;
|
||||
move_p = (kind == sfk_move_assignment
|
||||
|| kind == sfk_move_constructor);
|
||||
rhs_parm_type = cp_build_reference_type (rhs_parm_type, move_p);
|
||||
{
|
||||
if (const_p)
|
||||
rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
|
||||
else
|
||||
rhs_parm_type = type;
|
||||
move_p = (kind == sfk_move_assignment
|
||||
|| kind == sfk_move_constructor);
|
||||
rhs_parm_type = cp_build_reference_type (rhs_parm_type, move_p);
|
||||
|
||||
parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
|
||||
parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
|
||||
&deleted_p, &constexpr_p, &no_implicit_p, false);
|
||||
tree inherited_base = (inherited_ctor
|
||||
? DECL_CONTEXT (inherited_ctor)
|
||||
: NULL_TREE);
|
||||
if (inherited_ctor && TREE_CODE (inherited_ctor) == TEMPLATE_DECL)
|
||||
{
|
||||
/* For an inheriting constructor template, just copy these flags from
|
||||
the inherited constructor template for now. */
|
||||
raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (inherited_ctor));
|
||||
trivial_p = false;
|
||||
deleted_p = DECL_DELETED_FN (DECL_TEMPLATE_RESULT (inherited_ctor));
|
||||
constexpr_p
|
||||
= DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT (inherited_ctor));
|
||||
no_implicit_p = false;
|
||||
}
|
||||
else
|
||||
synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
|
||||
&deleted_p, &constexpr_p, &no_implicit_p, false,
|
||||
inherited_base, inherited_parms);
|
||||
/* Don't bother marking a deleted constructor as constexpr. */
|
||||
if (deleted_p)
|
||||
constexpr_p = false;
|
||||
|
@ -1544,9 +1650,10 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
|
|||
if (raises)
|
||||
fn_type = build_exception_variant (fn_type, raises);
|
||||
fn = build_lang_decl (FUNCTION_DECL, name, fn_type);
|
||||
DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type));
|
||||
if (kind != sfk_inheriting_constructor)
|
||||
DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type));
|
||||
if (kind == sfk_constructor || kind == sfk_copy_constructor
|
||||
|| kind == sfk_move_constructor)
|
||||
|| kind == sfk_move_constructor || kind == sfk_inheriting_constructor)
|
||||
DECL_CONSTRUCTOR_P (fn) = 1;
|
||||
else if (kind == sfk_destructor)
|
||||
DECL_DESTRUCTOR_P (fn) = 1;
|
||||
|
@ -1575,6 +1682,27 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
|
|||
DECL_PARM_INDEX (decl) = DECL_PARM_LEVEL (decl) = 1;
|
||||
DECL_ARGUMENTS (fn) = decl;
|
||||
}
|
||||
else if (kind == sfk_inheriting_constructor)
|
||||
{
|
||||
tree *p = &DECL_ARGUMENTS (fn);
|
||||
for (tree parm = inherited_parms; 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);
|
||||
DECL_NONCONVERTING_P (fn) = DECL_NONCONVERTING_P (inherited_ctor);
|
||||
/* A constructor so declared has the same access as the corresponding
|
||||
constructor in X. */
|
||||
TREE_PRIVATE (fn) = TREE_PRIVATE (inherited_ctor);
|
||||
TREE_PROTECTED (fn) = TREE_PROTECTED (inherited_ctor);
|
||||
/* Copy constexpr from the inherited constructor even if the
|
||||
inheriting constructor doesn't satisfy the requirements. */
|
||||
constexpr_p
|
||||
= DECL_DECLARED_CONSTEXPR_P (STRIP_TEMPLATE (inherited_ctor));
|
||||
}
|
||||
/* Add the "this" parameter. */
|
||||
this_parm = build_this_parm (fn_type, TYPE_UNQUALIFIED);
|
||||
DECL_CHAIN (this_parm) = DECL_ARGUMENTS (fn);
|
||||
|
@ -1600,6 +1728,9 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
|
|||
/* Restore PROCESSING_TEMPLATE_DECL. */
|
||||
processing_template_decl = saved_processing_template_decl;
|
||||
|
||||
if (inherited_ctor && TREE_CODE (inherited_ctor) == TEMPLATE_DECL)
|
||||
fn = add_inherited_template_parms (fn, inherited_ctor);
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
|
@ -1613,7 +1744,8 @@ defaulted_late_check (tree fn)
|
|||
tree ctx = DECL_CONTEXT (fn);
|
||||
special_function_kind kind = special_function_p (fn);
|
||||
bool fn_const_p = (copy_fn_p (fn) == 2);
|
||||
tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p);
|
||||
tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p,
|
||||
NULL, NULL);
|
||||
|
||||
if (!same_type_p (TREE_TYPE (TREE_TYPE (fn)),
|
||||
TREE_TYPE (TREE_TYPE (implicit_fn)))
|
||||
|
@ -1766,7 +1898,7 @@ lazily_declare_fn (special_function_kind sfk, tree type)
|
|||
}
|
||||
|
||||
/* Declare the function. */
|
||||
fn = implicitly_declare_fn (sfk, type, const_p);
|
||||
fn = implicitly_declare_fn (sfk, type, const_p, NULL, NULL);
|
||||
|
||||
/* [class.copy]/8 If the class definition declares a move constructor or
|
||||
move assignment operator, the implicitly declared copy constructor is
|
||||
|
|
|
@ -3026,6 +3026,14 @@ push_class_level_binding_1 (tree name, tree x)
|
|||
&& TREE_TYPE (decl) == error_mark_node)
|
||||
decl = TREE_VALUE (decl);
|
||||
|
||||
if (TREE_CODE (decl) == USING_DECL
|
||||
&& TREE_CODE (USING_DECL_SCOPE (decl)) == TEMPLATE_TYPE_PARM
|
||||
&& DECL_NAME (decl) == TYPE_IDENTIFIER (USING_DECL_SCOPE (decl)))
|
||||
/* This using-declaration declares constructors that inherit from the
|
||||
constructors for the template parameter. It does not redeclare the
|
||||
name of the template parameter. */
|
||||
return true;
|
||||
|
||||
if (!check_template_shadow (decl))
|
||||
return false;
|
||||
|
||||
|
@ -3218,10 +3226,7 @@ do_class_using_decl (tree scope, tree name)
|
|||
return NULL_TREE;
|
||||
}
|
||||
if (MAYBE_CLASS_TYPE_P (scope) && constructor_name_p (name, scope))
|
||||
{
|
||||
error ("%<%T::%D%> names constructor", scope, name);
|
||||
return NULL_TREE;
|
||||
}
|
||||
maybe_warn_cpp0x (CPP0X_INHERITING_CTORS);
|
||||
if (constructor_name_p (name, current_class_type))
|
||||
{
|
||||
error ("%<%T::%D%> names constructor in %qT",
|
||||
|
|
58
gcc/cp/pt.c
58
gcc/cp/pt.c
|
@ -3847,17 +3847,16 @@ arg_from_parm_pack_p (tree arg_pack, tree parm_pack)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Within the declaration of a template, return all levels of template
|
||||
parameters that apply. The template parameters are represented as
|
||||
a TREE_VEC, in the form documented in cp-tree.h for template
|
||||
arguments. */
|
||||
/* Given a set of template parameters, return them as a set of template
|
||||
arguments. The template parameters are represented as a TREE_VEC, in
|
||||
the form documented in cp-tree.h for template arguments. */
|
||||
|
||||
static tree
|
||||
current_template_args (void)
|
||||
template_parms_to_args (tree parms)
|
||||
{
|
||||
tree header;
|
||||
tree args = NULL_TREE;
|
||||
int length = TMPL_PARMS_DEPTH (current_template_parms);
|
||||
int length = TMPL_PARMS_DEPTH (parms);
|
||||
int l = length;
|
||||
|
||||
/* If there is only one level of template parameters, we do not
|
||||
|
@ -3866,7 +3865,7 @@ current_template_args (void)
|
|||
if (length > 1)
|
||||
args = make_tree_vec (length);
|
||||
|
||||
for (header = current_template_parms; header; header = TREE_CHAIN (header))
|
||||
for (header = parms; header; header = TREE_CHAIN (header))
|
||||
{
|
||||
tree a = copy_node (TREE_VALUE (header));
|
||||
int i;
|
||||
|
@ -3903,6 +3902,15 @@ current_template_args (void)
|
|||
return args;
|
||||
}
|
||||
|
||||
/* Within the declaration of a template, return the currently active
|
||||
template parameters as an argument TREE_VEC. */
|
||||
|
||||
static tree
|
||||
current_template_args (void)
|
||||
{
|
||||
return template_parms_to_args (current_template_parms);
|
||||
}
|
||||
|
||||
/* Update the declared TYPE by doing any lookups which were thought to be
|
||||
dependent, but are not now that we know the SCOPE of the declarator. */
|
||||
|
||||
|
@ -4904,6 +4912,29 @@ push_template_decl (tree decl)
|
|||
return push_template_decl_real (decl, false);
|
||||
}
|
||||
|
||||
/* FN is an inheriting constructor that inherits from the constructor
|
||||
template INHERITED; turn FN into a constructor template with a matching
|
||||
template header. */
|
||||
|
||||
tree
|
||||
add_inherited_template_parms (tree fn, tree inherited)
|
||||
{
|
||||
tree inner_parms
|
||||
= INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (inherited));
|
||||
inner_parms = copy_node (inner_parms);
|
||||
tree parms
|
||||
= tree_cons (size_int (processing_template_decl + 1),
|
||||
inner_parms, current_template_parms);
|
||||
tree tmpl = build_template_decl (fn, parms, /*member*/true);
|
||||
tree args = template_parms_to_args (parms);
|
||||
DECL_TEMPLATE_INFO (fn) = build_template_info (tmpl, args);
|
||||
TREE_TYPE (tmpl) = TREE_TYPE (fn);
|
||||
DECL_TEMPLATE_RESULT (tmpl) = fn;
|
||||
DECL_ARTIFICIAL (tmpl) = true;
|
||||
DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
|
||||
return tmpl;
|
||||
}
|
||||
|
||||
/* Called when a class template TYPE is redeclared with the indicated
|
||||
template PARMS, e.g.:
|
||||
|
||||
|
@ -10136,6 +10167,8 @@ 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))
|
||||
deduce_inheriting_ctor (r);
|
||||
/* If this is an instantiation of a member template, clone it.
|
||||
If it isn't, that'll be handled by
|
||||
clone_constructors_and_destructors. */
|
||||
|
@ -10336,9 +10369,14 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
|
|||
if (DECL_DEPENDENT_P (t)
|
||||
|| uses_template_parms (USING_DECL_SCOPE (t)))
|
||||
{
|
||||
r = do_class_using_decl
|
||||
(tsubst_copy (USING_DECL_SCOPE (t), args, complain, in_decl),
|
||||
tsubst_copy (DECL_NAME (t), args, complain, in_decl));
|
||||
tree scope = USING_DECL_SCOPE (t);
|
||||
tree inst_scope = tsubst_copy (USING_DECL_SCOPE (t), args,
|
||||
complain, in_decl);
|
||||
tree name = tsubst_copy (DECL_NAME (t), args, complain, in_decl);
|
||||
if (TREE_CODE (scope) == TEMPLATE_TYPE_PARM
|
||||
&& name == TYPE_IDENTIFIER (scope))
|
||||
name = TYPE_IDENTIFIER (inst_scope);
|
||||
r = do_class_using_decl (inst_scope, name);
|
||||
if (!r)
|
||||
r = error_mark_node;
|
||||
else
|
||||
|
|
|
@ -3337,6 +3337,8 @@ 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))
|
||||
return sfk_inheriting_constructor;
|
||||
if (DECL_COPY_CONSTRUCTOR_P (decl))
|
||||
return sfk_copy_constructor;
|
||||
if (DECL_MOVE_CONSTRUCTOR_P (decl))
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
2012-10-14 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* g++.dg/cpp0x/inh-ctor1.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor2.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor3.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor4.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor5.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor6.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor7.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor8.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor9.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor10.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor11.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor12.C: New.
|
||||
* g++.dg/cpp0x/inh-ctor13.C: New.
|
||||
|
||||
2012-10-14 Steven Bosscher <steven@gcc.gnu.org>
|
||||
|
||||
PR rtl-optimization/54919
|
||||
|
|
17
gcc/testsuite/g++.dg/cpp0x/inh-ctor1.C
Normal file
17
gcc/testsuite/g++.dg/cpp0x/inh-ctor1.C
Normal file
|
@ -0,0 +1,17 @@
|
|||
// { dg-options -std=c++11 }
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
constexpr A(int i): i(i) {}
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
using A::A;
|
||||
};
|
||||
|
||||
constexpr B b(42);
|
||||
|
||||
#define SA(X) static_assert((X),#X)
|
||||
SA(b.i == 42);
|
14
gcc/testsuite/g++.dg/cpp0x/inh-ctor10.C
Normal file
14
gcc/testsuite/g++.dg/cpp0x/inh-ctor10.C
Normal file
|
@ -0,0 +1,14 @@
|
|||
// { dg-options "-std=c++11" }
|
||||
|
||||
struct A
|
||||
{
|
||||
template <class... Ts> A(Ts...);
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
using A::A;
|
||||
};
|
||||
|
||||
B b1(42);
|
||||
B b2(1.0, 42, (void*)0);
|
14
gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C
Normal file
14
gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C
Normal file
|
@ -0,0 +1,14 @@
|
|||
// { dg-options "-std=c++11" }
|
||||
|
||||
struct A
|
||||
{
|
||||
A(int, ...);
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
using A::A;
|
||||
};
|
||||
|
||||
B b1(42);
|
||||
B b2(42, 1.0); // { dg-error "no match" }
|
26
gcc/testsuite/g++.dg/cpp0x/inh-ctor12.C
Normal file
26
gcc/testsuite/g++.dg/cpp0x/inh-ctor12.C
Normal file
|
@ -0,0 +1,26 @@
|
|||
// { dg-options "-std=c++11" }
|
||||
// { dg-do run }
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
template <class T>
|
||||
A(T t) noexcept : i(t) {}
|
||||
};
|
||||
|
||||
struct C
|
||||
{
|
||||
C() { throw 42; }
|
||||
};
|
||||
|
||||
struct B: A, C
|
||||
{
|
||||
using A::A;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
try { B b(24); }
|
||||
catch (int) { return 0; }
|
||||
__builtin_abort();
|
||||
}
|
22
gcc/testsuite/g++.dg/cpp0x/inh-ctor13.C
Normal file
22
gcc/testsuite/g++.dg/cpp0x/inh-ctor13.C
Normal file
|
@ -0,0 +1,22 @@
|
|||
// { dg-options "-std=c++11" }
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
template <class T> A(T t);
|
||||
};
|
||||
|
||||
struct C
|
||||
{
|
||||
C() = delete; // { dg-error "declared here" }
|
||||
};
|
||||
|
||||
struct B: A, C
|
||||
{
|
||||
using A::A; // { dg-error "C::C" }
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
B b(24); // { dg-error "B::B" }
|
||||
}
|
19
gcc/testsuite/g++.dg/cpp0x/inh-ctor2.C
Normal file
19
gcc/testsuite/g++.dg/cpp0x/inh-ctor2.C
Normal file
|
@ -0,0 +1,19 @@
|
|||
// { dg-options -std=c++11 }
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
constexpr A(int, int i = num): i(i) {}
|
||||
private:
|
||||
static const int num = 42;
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
using A::A;
|
||||
};
|
||||
|
||||
constexpr B b(24);
|
||||
|
||||
#define SA(X) static_assert((X),#X)
|
||||
SA(b.i == 42);
|
17
gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C
Normal file
17
gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C
Normal file
|
@ -0,0 +1,17 @@
|
|||
// { dg-options -std=c++11 }
|
||||
|
||||
struct B1 {
|
||||
B1(int);
|
||||
};
|
||||
struct B2 {
|
||||
B2(int);
|
||||
};
|
||||
struct D1 : B1, B2 {
|
||||
using B1::B1; // { dg-error "inherited" }
|
||||
using B2::B2; // { dg-error "inherited" }
|
||||
}; // ill-formed: attempts to declare D1(int) twice
|
||||
struct D2 : B1, B2 {
|
||||
using B1::B1;
|
||||
using B2::B2;
|
||||
D2(int); // OK: user declaration supersedes both implicit declarations
|
||||
};
|
18
gcc/testsuite/g++.dg/cpp0x/inh-ctor4.C
Normal file
18
gcc/testsuite/g++.dg/cpp0x/inh-ctor4.C
Normal file
|
@ -0,0 +1,18 @@
|
|||
// From N3337
|
||||
// { dg-options -std=c++11 }
|
||||
|
||||
struct B1 {
|
||||
B1(int);
|
||||
};
|
||||
struct B2 {
|
||||
B2(int = 13, int = 42);
|
||||
};
|
||||
struct D1 : B1 {
|
||||
using B1::B1;
|
||||
};
|
||||
struct D2 : B2 {
|
||||
using B2::B2;
|
||||
};
|
||||
|
||||
D1 d1(1);
|
||||
D2 d2a(2), d2b(3,4);
|
21
gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C
Normal file
21
gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C
Normal file
|
@ -0,0 +1,21 @@
|
|||
// { dg-options "-std=c++11" }
|
||||
|
||||
struct B1 {
|
||||
B1(int) { }
|
||||
};
|
||||
struct B2 {
|
||||
B2(double) { }
|
||||
};
|
||||
struct D1 : B1 { // { dg-error "no match" }
|
||||
using B1::B1; // implicitly declares D1(int)
|
||||
int x;
|
||||
};
|
||||
void test() {
|
||||
D1 d(6); // OK: d.x is not initialized
|
||||
D1 e; // { dg-error "deleted" } D1 has no default constructor
|
||||
}
|
||||
struct D2 : B2 {
|
||||
using B2::B2; // { dg-error "no match" } implicitly declares D2(double)
|
||||
B1 b;
|
||||
};
|
||||
D2 f(1.0); // { dg-error "deleted" } B1 has no default constructor
|
15
gcc/testsuite/g++.dg/cpp0x/inh-ctor6.C
Normal file
15
gcc/testsuite/g++.dg/cpp0x/inh-ctor6.C
Normal file
|
@ -0,0 +1,15 @@
|
|||
// { dg-options "-std=c++11" }
|
||||
|
||||
extern "C" int printf (const char *, ...);
|
||||
template< class T >
|
||||
struct D : T {
|
||||
using T::T;
|
||||
// declares all constructors from class T
|
||||
~D() { printf ("Destroying wrapper\n"); }
|
||||
};
|
||||
|
||||
struct A {
|
||||
A(int);
|
||||
};
|
||||
|
||||
D<A> d(42);
|
18
gcc/testsuite/g++.dg/cpp0x/inh-ctor7.C
Normal file
18
gcc/testsuite/g++.dg/cpp0x/inh-ctor7.C
Normal file
|
@ -0,0 +1,18 @@
|
|||
// { dg-options "-std=c++11" }
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
template <class T>
|
||||
constexpr A(T t): i(t) {}
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
using A::A;
|
||||
};
|
||||
|
||||
constexpr B b(42);
|
||||
|
||||
#define SA(X) static_assert((X),#X)
|
||||
SA(b.i == 42);
|
20
gcc/testsuite/g++.dg/cpp0x/inh-ctor8.C
Normal file
20
gcc/testsuite/g++.dg/cpp0x/inh-ctor8.C
Normal file
|
@ -0,0 +1,20 @@
|
|||
// { dg-options "-std=c++11" }
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
explicit A(int i): i(i) {}
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
using A::A;
|
||||
};
|
||||
|
||||
void f(B);
|
||||
|
||||
int main()
|
||||
{
|
||||
f(B(42)); // OK
|
||||
f(42); // { dg-error "could not convert" }
|
||||
}
|
15
gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C
Normal file
15
gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C
Normal file
|
@ -0,0 +1,15 @@
|
|||
// { dg-options "-std=c++11" }
|
||||
|
||||
class A
|
||||
{
|
||||
int i;
|
||||
protected:
|
||||
A(int i): i(i) {}
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
using A::A; // { dg-error "protected" }
|
||||
};
|
||||
|
||||
B b(42); // { dg-error "this context" }
|
Loading…
Add table
Reference in a new issue