Implement defaulted/deleted functions as per N2346
Implement defaulted/deleted functions as per N2346 * cp-tree.h (struct lang_decl_flags): Add defaulted_p bitfield. (DECL_DELETED_FN): New macro. (DECL_DEFAULTED_FN): New macro. * class.c (user_provided_p): New fn. (defaultable_fn_p): New fn. (type_has_user_provided_constructor): New fn. (type_has_user_provided_default_constructor): New fn. (check_methods): A defaulted fn is still trivial. (check_bases_and_members): Likewise. * decl.c (grok_special_member_properties): Likewise. (duplicate_decls): Complain about redeclaring a function as deleted. (start_decl): initialized==2 means deleted. (cp_finish_decl): Handle deleted/defaulted semantics. * decl2.c (grokfield): Likewise. (mark_used): Check DECL_DEFAULTED_FN instead of DECL_ARTIFICIAL. Complain about using a deleted fn. * init.c (build_value_init_1): Use type_has_user_provided_constructor. (perform_member_init): Check for a user-provided default constructor even if TYPE_NEEDS_CONSTRUCTING. (build_new_1): Likewise. * call.c (build_over_call): Don't call mark_used twice. * method.c (implicitly_declare_fn): Set DECL_DEFAULTED_FN. * search.c (check_final_overrider): Check for deleted mismatch. * parser.c (cp_parser_init_declarator): Tell start_decl about =delete. (cp_parser_pure_specifier): Handle =default and =delete. * error.c (maybe_warn_cpp0x): Suggest -std=gnu++0x as well. From-SVN: r138123
This commit is contained in:
parent
c3005b0f0c
commit
b87d79e640
|
@ -1,3 +1,34 @@
|
||||||
|
2008-07-23 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
|
Implement defaulted/deleted functions as per N2346
|
||||||
|
* cp-tree.h (struct lang_decl_flags): Add defaulted_p bitfield.
|
||||||
|
(DECL_DELETED_FN): New macro.
|
||||||
|
(DECL_DEFAULTED_FN): New macro.
|
||||||
|
* class.c (user_provided_p): New fn.
|
||||||
|
(defaultable_fn_p): New fn.
|
||||||
|
(type_has_user_provided_constructor): New fn.
|
||||||
|
(type_has_user_provided_default_constructor): New fn.
|
||||||
|
(check_methods): A defaulted fn is still trivial.
|
||||||
|
(check_bases_and_members): Likewise.
|
||||||
|
* decl.c (grok_special_member_properties): Likewise.
|
||||||
|
(duplicate_decls): Complain about redeclaring a function as deleted.
|
||||||
|
(start_decl): initialized==2 means deleted.
|
||||||
|
(cp_finish_decl): Handle deleted/defaulted semantics.
|
||||||
|
* decl2.c (grokfield): Likewise.
|
||||||
|
(mark_used): Check DECL_DEFAULTED_FN instead of DECL_ARTIFICIAL.
|
||||||
|
Complain about using a deleted fn.
|
||||||
|
* init.c (build_value_init_1): Use type_has_user_provided_constructor.
|
||||||
|
(perform_member_init): Check for a user-provided default constructor
|
||||||
|
even if TYPE_NEEDS_CONSTRUCTING.
|
||||||
|
(build_new_1): Likewise.
|
||||||
|
* call.c (build_over_call): Don't call mark_used twice.
|
||||||
|
* method.c (implicitly_declare_fn): Set DECL_DEFAULTED_FN.
|
||||||
|
* search.c (check_final_overrider): Check for deleted mismatch.
|
||||||
|
* parser.c (cp_parser_init_declarator): Tell start_decl about =delete.
|
||||||
|
(cp_parser_pure_specifier): Handle =default and =delete.
|
||||||
|
|
||||||
|
* error.c (maybe_warn_cpp0x): Suggest -std=gnu++0x as well.
|
||||||
|
|
||||||
2008-07-23 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
|
2008-07-23 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
|
||||||
|
|
||||||
PR 35058
|
PR 35058
|
||||||
|
|
|
@ -5090,6 +5090,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
|
||||||
int is_method = 0;
|
int is_method = 0;
|
||||||
int nargs;
|
int nargs;
|
||||||
tree *argarray;
|
tree *argarray;
|
||||||
|
bool already_used = false;
|
||||||
|
|
||||||
/* In a template, there is no need to perform all of the work that
|
/* In a template, there is no need to perform all of the work that
|
||||||
is normally done. We are only interested in the type of the call
|
is normally done. We are only interested in the type of the call
|
||||||
|
@ -5310,7 +5311,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
|
||||||
/* [class.copy]: the copy constructor is implicitly defined even if
|
/* [class.copy]: the copy constructor is implicitly defined even if
|
||||||
the implementation elided its use. */
|
the implementation elided its use. */
|
||||||
if (TYPE_HAS_COMPLEX_INIT_REF (DECL_CONTEXT (fn)))
|
if (TYPE_HAS_COMPLEX_INIT_REF (DECL_CONTEXT (fn)))
|
||||||
|
{
|
||||||
mark_used (fn);
|
mark_used (fn);
|
||||||
|
already_used = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* If we're creating a temp and we already have one, don't create a
|
/* If we're creating a temp and we already have one, don't create a
|
||||||
new one. If we're not creating a temp but we get one, use
|
new one. If we're not creating a temp but we get one, use
|
||||||
|
@ -5370,6 +5374,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!already_used)
|
||||||
mark_used (fn);
|
mark_used (fn);
|
||||||
|
|
||||||
if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
|
if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
|
||||||
|
|
111
gcc/cp/class.c
111
gcc/cp/class.c
|
@ -3045,7 +3045,7 @@ check_field_decls (tree t, tree *access_decls,
|
||||||
|
|
||||||
/* Core issue 80: A nonstatic data member is required to have a
|
/* Core issue 80: A nonstatic data member is required to have a
|
||||||
different name from the class iff the class has a
|
different name from the class iff the class has a
|
||||||
user-defined constructor. */
|
user-declared constructor. */
|
||||||
if (constructor_name_p (DECL_NAME (x), t)
|
if (constructor_name_p (DECL_NAME (x), t)
|
||||||
&& TYPE_HAS_USER_CONSTRUCTOR (t))
|
&& TYPE_HAS_USER_CONSTRUCTOR (t))
|
||||||
permerror ("field %q+#D with same name as class", x);
|
permerror ("field %q+#D with same name as class", x);
|
||||||
|
@ -3767,8 +3767,8 @@ check_methods (tree t)
|
||||||
if (DECL_PURE_VIRTUAL_P (x))
|
if (DECL_PURE_VIRTUAL_P (x))
|
||||||
VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (t), x);
|
VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (t), x);
|
||||||
}
|
}
|
||||||
/* All user-declared destructors are non-trivial. */
|
/* All user-provided destructors are non-trivial. */
|
||||||
if (DECL_DESTRUCTOR_P (x))
|
if (DECL_DESTRUCTOR_P (x) && !DECL_DEFAULTED_FN (x))
|
||||||
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
|
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4067,6 +4067,86 @@ type_has_user_nondefault_constructor (tree t)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns true iff FN is a user-provided function, i.e. user-declared
|
||||||
|
and not defaulted at its first declaration. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
user_provided_p (tree fn)
|
||||||
|
{
|
||||||
|
if (TREE_CODE (fn) == TEMPLATE_DECL)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return (!DECL_ARTIFICIAL (fn)
|
||||||
|
&& !(DECL_DEFAULTED_FN (fn)
|
||||||
|
&& DECL_INITIALIZED_IN_CLASS_P (fn)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true iff class T has a user-provided constructor. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
type_has_user_provided_constructor (tree t)
|
||||||
|
{
|
||||||
|
tree fns;
|
||||||
|
|
||||||
|
if (!TYPE_HAS_USER_CONSTRUCTOR (t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* This can happen in error cases; avoid crashing. */
|
||||||
|
if (!CLASSTYPE_METHOD_VEC (t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
|
||||||
|
if (user_provided_p (OVL_CURRENT (fns)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true iff class T has a user-provided default constructor. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
type_has_user_provided_default_constructor (tree t)
|
||||||
|
{
|
||||||
|
tree fns;
|
||||||
|
|
||||||
|
if (!TYPE_HAS_USER_CONSTRUCTOR (t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
|
||||||
|
{
|
||||||
|
tree fn = OVL_CURRENT (fns);
|
||||||
|
if (user_provided_p (fn)
|
||||||
|
&& (skip_artificial_parms_for (fn, DECL_ARGUMENTS (fn))
|
||||||
|
== NULL_TREE))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if FN can be explicitly defaulted. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
defaultable_fn_p (tree fn)
|
||||||
|
{
|
||||||
|
if (DECL_CONSTRUCTOR_P (fn))
|
||||||
|
{
|
||||||
|
if (skip_artificial_parms_for (fn, DECL_ARGUMENTS (fn))
|
||||||
|
== NULL_TREE)
|
||||||
|
return true;
|
||||||
|
else if (copy_fn_p (fn) > 0)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (DECL_DESTRUCTOR_P (fn))
|
||||||
|
return true;
|
||||||
|
else if (DECL_ASSIGNMENT_OPERATOR_P (fn))
|
||||||
|
return copy_fn_p (fn);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Remove all zero-width bit-fields from T. */
|
/* Remove all zero-width bit-fields from T. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -4158,6 +4238,8 @@ check_bases_and_members (tree t)
|
||||||
should take a non-const reference argument. */
|
should take a non-const reference argument. */
|
||||||
int no_const_asn_ref;
|
int no_const_asn_ref;
|
||||||
tree access_decls;
|
tree access_decls;
|
||||||
|
bool saved_complex_asn_ref;
|
||||||
|
bool saved_nontrivial_dtor;
|
||||||
|
|
||||||
/* By default, we use const reference arguments and generate default
|
/* By default, we use const reference arguments and generate default
|
||||||
constructors. */
|
constructors. */
|
||||||
|
@ -4171,6 +4253,12 @@ check_bases_and_members (tree t)
|
||||||
/* Check all the method declarations. */
|
/* Check all the method declarations. */
|
||||||
check_methods (t);
|
check_methods (t);
|
||||||
|
|
||||||
|
/* Save the initial values of these flags which only indicate whether
|
||||||
|
or not the class has user-provided functions. As we analyze the
|
||||||
|
bases and members we can set these flags for other reasons. */
|
||||||
|
saved_complex_asn_ref = TYPE_HAS_COMPLEX_ASSIGN_REF (t);
|
||||||
|
saved_nontrivial_dtor = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t);
|
||||||
|
|
||||||
/* Check all the data member declarations. We cannot call
|
/* Check all the data member declarations. We cannot call
|
||||||
check_field_decls until we have called check_bases check_methods,
|
check_field_decls until we have called check_bases check_methods,
|
||||||
as check_field_decls depends on TYPE_HAS_NONTRIVIAL_DESTRUCTOR
|
as check_field_decls depends on TYPE_HAS_NONTRIVIAL_DESTRUCTOR
|
||||||
|
@ -4186,30 +4274,27 @@ check_bases_and_members (tree t)
|
||||||
|
|
||||||
/* Do some bookkeeping that will guide the generation of implicitly
|
/* Do some bookkeeping that will guide the generation of implicitly
|
||||||
declared member functions. */
|
declared member functions. */
|
||||||
TYPE_HAS_COMPLEX_INIT_REF (t)
|
TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_CONTAINS_VPTR_P (t);
|
||||||
|= (TYPE_HAS_INIT_REF (t) || TYPE_CONTAINS_VPTR_P (t));
|
|
||||||
/* We need to call a constructor for this class if it has a
|
/* We need to call a constructor for this class if it has a
|
||||||
user-declared constructor, or if the default constructor is going
|
user-provided constructor, or if the default constructor is going
|
||||||
to initialize the vptr. (This is not an if-and-only-if;
|
to initialize the vptr. (This is not an if-and-only-if;
|
||||||
TYPE_NEEDS_CONSTRUCTING is set elsewhere if bases or members
|
TYPE_NEEDS_CONSTRUCTING is set elsewhere if bases or members
|
||||||
themselves need constructing.) */
|
themselves need constructing.) */
|
||||||
TYPE_NEEDS_CONSTRUCTING (t)
|
TYPE_NEEDS_CONSTRUCTING (t)
|
||||||
|= (TYPE_HAS_USER_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
|
|= (type_has_user_provided_constructor (t) || TYPE_CONTAINS_VPTR_P (t));
|
||||||
/* [dcl.init.aggr]
|
/* [dcl.init.aggr]
|
||||||
|
|
||||||
An aggregate is an array or a class with no user-declared
|
An aggregate is an array or a class with no user-provided
|
||||||
constructors ... and no virtual functions.
|
constructors ... and no virtual functions.
|
||||||
|
|
||||||
Again, other conditions for being an aggregate are checked
|
Again, other conditions for being an aggregate are checked
|
||||||
elsewhere. */
|
elsewhere. */
|
||||||
CLASSTYPE_NON_AGGREGATE (t)
|
CLASSTYPE_NON_AGGREGATE (t)
|
||||||
|= (TYPE_HAS_USER_CONSTRUCTOR (t) || TYPE_POLYMORPHIC_P (t));
|
|= (type_has_user_provided_constructor (t) || TYPE_POLYMORPHIC_P (t));
|
||||||
CLASSTYPE_NON_POD_P (t)
|
CLASSTYPE_NON_POD_P (t)
|
||||||
|= (CLASSTYPE_NON_AGGREGATE (t)
|
|= (CLASSTYPE_NON_AGGREGATE (t)
|
||||||
|| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
|
|| saved_nontrivial_dtor || saved_complex_asn_ref);
|
||||||
|| TYPE_HAS_ASSIGN_REF (t));
|
TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_CONTAINS_VPTR_P (t);
|
||||||
TYPE_HAS_COMPLEX_ASSIGN_REF (t)
|
|
||||||
|= TYPE_HAS_ASSIGN_REF (t) || TYPE_CONTAINS_VPTR_P (t);
|
|
||||||
TYPE_HAS_COMPLEX_DFLT (t)
|
TYPE_HAS_COMPLEX_DFLT (t)
|
||||||
|= (TYPE_HAS_DEFAULT_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
|
|= (TYPE_HAS_DEFAULT_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
|
||||||
|
|
||||||
|
|
|
@ -1609,7 +1609,7 @@ struct lang_decl_flags GTY(())
|
||||||
unsigned repo_available_p : 1;
|
unsigned repo_available_p : 1;
|
||||||
unsigned hidden_friend_p : 1;
|
unsigned hidden_friend_p : 1;
|
||||||
unsigned threadprivate_p : 1;
|
unsigned threadprivate_p : 1;
|
||||||
/* One unused bit. */
|
unsigned defaulted_p : 1;
|
||||||
|
|
||||||
union lang_decl_u {
|
union lang_decl_u {
|
||||||
/* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
|
/* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
|
||||||
|
@ -2626,6 +2626,14 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
|
||||||
#define CP_DECL_THREADPRIVATE_P(DECL) \
|
#define CP_DECL_THREADPRIVATE_P(DECL) \
|
||||||
(DECL_LANG_SPECIFIC (VAR_DECL_CHECK (DECL))->decl_flags.threadprivate_p)
|
(DECL_LANG_SPECIFIC (VAR_DECL_CHECK (DECL))->decl_flags.threadprivate_p)
|
||||||
|
|
||||||
|
/* Nonzero if DECL was declared with '= delete'. */
|
||||||
|
#define DECL_DELETED_FN(DECL) \
|
||||||
|
(DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->decl_flags.threadprivate_p)
|
||||||
|
|
||||||
|
/* Nonzero if DECL was declared with '= default'. */
|
||||||
|
#define DECL_DEFAULTED_FN(DECL) \
|
||||||
|
(DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->decl_flags.defaulted_p)
|
||||||
|
|
||||||
/* Record whether a typedef for type `int' was actually `signed int'. */
|
/* Record whether a typedef for type `int' was actually `signed int'. */
|
||||||
#define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP)
|
#define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP)
|
||||||
|
|
||||||
|
@ -4171,6 +4179,9 @@ extern void check_for_override (tree, tree);
|
||||||
extern void push_class_stack (void);
|
extern void push_class_stack (void);
|
||||||
extern void pop_class_stack (void);
|
extern void pop_class_stack (void);
|
||||||
extern bool type_has_user_nondefault_constructor (tree);
|
extern bool type_has_user_nondefault_constructor (tree);
|
||||||
|
extern bool type_has_user_provided_constructor (tree);
|
||||||
|
extern bool type_has_user_provided_default_constructor (tree);
|
||||||
|
extern bool defaultable_fn_p (tree);
|
||||||
|
|
||||||
/* in cvt.c */
|
/* in cvt.c */
|
||||||
extern tree convert_to_reference (tree, tree, int, int, tree);
|
extern tree convert_to_reference (tree, tree, int, int, tree);
|
||||||
|
|
|
@ -1613,6 +1613,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
|
||||||
warning (OPT_Wredundant_decls, "redundant redeclaration of %qD in same scope", newdecl);
|
warning (OPT_Wredundant_decls, "redundant redeclaration of %qD in same scope", newdecl);
|
||||||
warning (OPT_Wredundant_decls, "previous declaration of %q+D", olddecl);
|
warning (OPT_Wredundant_decls, "previous declaration of %q+D", olddecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DECL_DELETED_FN (newdecl))
|
||||||
|
{
|
||||||
|
error ("deleted definition of %qD", newdecl);
|
||||||
|
error ("after previous declaration %q+D", olddecl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deal with C++: must preserve virtual function table size. */
|
/* Deal with C++: must preserve virtual function table size. */
|
||||||
|
@ -3931,13 +3937,14 @@ groktypename (cp_decl_specifier_seq *type_specifiers,
|
||||||
grokfield.) The DECL corresponding to the DECLARATOR is returned.
|
grokfield.) The DECL corresponding to the DECLARATOR is returned.
|
||||||
If an error occurs, the error_mark_node is returned instead.
|
If an error occurs, the error_mark_node is returned instead.
|
||||||
|
|
||||||
DECLSPECS are the decl-specifiers for the declaration. INITIALIZED
|
DECLSPECS are the decl-specifiers for the declaration. INITIALIZED is 1
|
||||||
is true if an explicit initializer is present, but false if this is
|
if an explicit initializer is present, or 2 for an explicitly defaulted
|
||||||
a variable implicitly initialized via a default constructor.
|
function, or 3 for an explicitly deleted function, but 0 if this is a
|
||||||
ATTRIBUTES and PREFIX_ATTRIBUTES are GNU attributes associated with
|
variable implicitly initialized via a default constructor. ATTRIBUTES
|
||||||
this declaration. *PUSHED_SCOPE_P is set to the scope entered in
|
and PREFIX_ATTRIBUTES are GNU attributes associated with this
|
||||||
this function, if any; if set, the caller is responsible for
|
declaration. *PUSHED_SCOPE_P is set to the scope entered in this
|
||||||
calling pop_scope. */
|
function, if any; if set, the caller is responsible for calling
|
||||||
|
pop_scope. */
|
||||||
|
|
||||||
tree
|
tree
|
||||||
start_decl (const cp_declarator *declarator,
|
start_decl (const cp_declarator *declarator,
|
||||||
|
@ -3991,12 +3998,15 @@ start_decl (const cp_declarator *declarator,
|
||||||
switch (TREE_CODE (decl))
|
switch (TREE_CODE (decl))
|
||||||
{
|
{
|
||||||
case TYPE_DECL:
|
case TYPE_DECL:
|
||||||
error ("typedef %qD is initialized (use __typeof__ instead)", decl);
|
error ("typedef %qD is initialized (use decltype instead)", decl);
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
|
|
||||||
case FUNCTION_DECL:
|
case FUNCTION_DECL:
|
||||||
error ("function %q#D is initialized like a variable", decl);
|
if (initialized == 3)
|
||||||
return error_mark_node;
|
/* We'll handle the rest of the semantics later, but we need to
|
||||||
|
set this now so it's visible to duplicate_decls. */
|
||||||
|
DECL_DELETED_FN (decl) = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -5686,10 +5696,38 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
|
||||||
else
|
else
|
||||||
abstract_virtuals_error (decl, type);
|
abstract_virtuals_error (decl, type);
|
||||||
|
|
||||||
if (TREE_CODE (decl) == FUNCTION_DECL
|
if (TREE_TYPE (decl) == error_mark_node)
|
||||||
|| TREE_TYPE (decl) == error_mark_node)
|
|
||||||
/* No initialization required. */
|
/* No initialization required. */
|
||||||
;
|
;
|
||||||
|
else if (TREE_CODE (decl) == FUNCTION_DECL)
|
||||||
|
{
|
||||||
|
if (init)
|
||||||
|
{
|
||||||
|
if (init == ridpointers[(int)RID_DELETE])
|
||||||
|
{
|
||||||
|
/* fixme check this is 1st decl */
|
||||||
|
DECL_DELETED_FN (decl) = 1;
|
||||||
|
DECL_DECLARED_INLINE_P (decl) = 1;
|
||||||
|
DECL_INITIAL (decl) = error_mark_node;
|
||||||
|
}
|
||||||
|
else if (init == ridpointers[(int)RID_DEFAULT])
|
||||||
|
{
|
||||||
|
if (!defaultable_fn_p (decl))
|
||||||
|
error ("%qD cannot be defaulted", decl);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* An out-of-class default definition is defined at
|
||||||
|
the point where it is explicitly defaulted. */
|
||||||
|
DECL_DEFAULTED_FN (decl) = 1;
|
||||||
|
if (DECL_INITIAL (decl) == error_mark_node)
|
||||||
|
synthesize_method (decl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error ("function %q#D is initialized like a variable", decl);
|
||||||
|
}
|
||||||
|
/* else no initialization required. */
|
||||||
|
}
|
||||||
else if (DECL_EXTERNAL (decl)
|
else if (DECL_EXTERNAL (decl)
|
||||||
&& ! (DECL_LANG_SPECIFIC (decl)
|
&& ! (DECL_LANG_SPECIFIC (decl)
|
||||||
&& DECL_NOT_REALLY_EXTERN (decl)))
|
&& DECL_NOT_REALLY_EXTERN (decl)))
|
||||||
|
@ -7361,7 +7399,7 @@ check_var_type (tree identifier, tree type)
|
||||||
Don't make a DECL node; just return the ..._TYPE node.
|
Don't make a DECL node; just return the ..._TYPE node.
|
||||||
FIELD for a struct or union field; make a FIELD_DECL.
|
FIELD for a struct or union field; make a FIELD_DECL.
|
||||||
BITFIELD for a field with specified width.
|
BITFIELD for a field with specified width.
|
||||||
INITIALIZED is 1 if the decl has an initializer.
|
INITIALIZED is as for start_decl.
|
||||||
|
|
||||||
ATTRLIST is a pointer to the list of attributes, which may be NULL
|
ATTRLIST is a pointer to the list of attributes, which may be NULL
|
||||||
if there are none; *ATTRLIST may be modified if attributes from inside
|
if there are none; *ATTRLIST may be modified if attributes from inside
|
||||||
|
@ -7459,6 +7497,9 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
else if (decl_context == BITFIELD)
|
else if (decl_context == BITFIELD)
|
||||||
bitfield = 1, decl_context = FIELD;
|
bitfield = 1, decl_context = FIELD;
|
||||||
|
|
||||||
|
if (initialized > 1)
|
||||||
|
funcdef_flag = true;
|
||||||
|
|
||||||
/* Look inside a declarator for the name being declared
|
/* Look inside a declarator for the name being declared
|
||||||
and get it as a string, for an error message. */
|
and get it as a string, for an error message. */
|
||||||
for (id_declarator = declarator;
|
for (id_declarator = declarator;
|
||||||
|
@ -9670,6 +9711,8 @@ grok_special_member_properties (tree decl)
|
||||||
are no other parameters or else all other parameters have
|
are no other parameters or else all other parameters have
|
||||||
default arguments. */
|
default arguments. */
|
||||||
TYPE_HAS_INIT_REF (class_type) = 1;
|
TYPE_HAS_INIT_REF (class_type) = 1;
|
||||||
|
if (!DECL_DEFAULTED_FN (decl))
|
||||||
|
TYPE_HAS_COMPLEX_INIT_REF (class_type) = 1;
|
||||||
if (ctor > 1)
|
if (ctor > 1)
|
||||||
TYPE_HAS_CONST_INIT_REF (class_type) = 1;
|
TYPE_HAS_CONST_INIT_REF (class_type) = 1;
|
||||||
}
|
}
|
||||||
|
@ -9691,6 +9734,8 @@ grok_special_member_properties (tree decl)
|
||||||
if (assop)
|
if (assop)
|
||||||
{
|
{
|
||||||
TYPE_HAS_ASSIGN_REF (class_type) = 1;
|
TYPE_HAS_ASSIGN_REF (class_type) = 1;
|
||||||
|
if (!DECL_DEFAULTED_FN (decl))
|
||||||
|
TYPE_HAS_COMPLEX_ASSIGN_REF (class_type) = 1;
|
||||||
if (assop != 1)
|
if (assop != 1)
|
||||||
TYPE_HAS_CONST_ASSIGN_REF (class_type) = 1;
|
TYPE_HAS_CONST_ASSIGN_REF (class_type) = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -821,7 +821,25 @@ grokfield (const cp_declarator *declarator,
|
||||||
{
|
{
|
||||||
/* Initializers for functions are rejected early in the parser.
|
/* Initializers for functions are rejected early in the parser.
|
||||||
If we get here, it must be a pure specifier for a method. */
|
If we get here, it must be a pure specifier for a method. */
|
||||||
if (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE)
|
if (init == ridpointers[(int)RID_DELETE])
|
||||||
|
{
|
||||||
|
DECL_DELETED_FN (value) = 1;
|
||||||
|
DECL_DECLARED_INLINE_P (value) = 1;
|
||||||
|
DECL_INITIAL (value) = error_mark_node;
|
||||||
|
}
|
||||||
|
else if (init == ridpointers[(int)RID_DEFAULT])
|
||||||
|
{
|
||||||
|
if (!defaultable_fn_p (value))
|
||||||
|
error ("%qD cannot be defaulted", value);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DECL_DEFAULTED_FN (value) = 1;
|
||||||
|
DECL_INITIALIZED_IN_CLASS_P (value) = 1;
|
||||||
|
DECL_DECLARED_INLINE_P (value) = 1;
|
||||||
|
DECL_INLINE (value) = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE)
|
||||||
{
|
{
|
||||||
gcc_assert (error_operand_p (init) || integer_zerop (init));
|
gcc_assert (error_operand_p (init) || integer_zerop (init));
|
||||||
DECL_PURE_VIRTUAL_P (value) = 1;
|
DECL_PURE_VIRTUAL_P (value) = 1;
|
||||||
|
@ -3739,7 +3757,7 @@ mark_used (tree decl)
|
||||||
/* Is it a synthesized method that needs to be synthesized? */
|
/* Is it a synthesized method that needs to be synthesized? */
|
||||||
if (TREE_CODE (decl) == FUNCTION_DECL
|
if (TREE_CODE (decl) == FUNCTION_DECL
|
||||||
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
|
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
|
||||||
&& DECL_ARTIFICIAL (decl)
|
&& DECL_DEFAULTED_FN (decl)
|
||||||
&& !DECL_THUNK_P (decl)
|
&& !DECL_THUNK_P (decl)
|
||||||
&& ! DECL_INITIAL (decl)
|
&& ! DECL_INITIAL (decl)
|
||||||
/* Kludge: don't synthesize for default args. Unfortunately this
|
/* Kludge: don't synthesize for default args. Unfortunately this
|
||||||
|
@ -3752,6 +3770,12 @@ mark_used (tree decl)
|
||||||
/* If we've already synthesized the method we don't need to
|
/* If we've already synthesized the method we don't need to
|
||||||
do the instantiation test below. */
|
do the instantiation test below. */
|
||||||
}
|
}
|
||||||
|
else if (TREE_CODE (decl) == FUNCTION_DECL
|
||||||
|
&& DECL_DELETED_FN (decl))
|
||||||
|
{
|
||||||
|
error ("deleted function %q+D", decl);
|
||||||
|
error ("used here");
|
||||||
|
}
|
||||||
else if ((DECL_NON_THUNK_FUNCTION_P (decl) || TREE_CODE (decl) == VAR_DECL)
|
else if ((DECL_NON_THUNK_FUNCTION_P (decl) || TREE_CODE (decl) == VAR_DECL)
|
||||||
&& DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
|
&& DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
|
||||||
&& (!DECL_EXPLICIT_INSTANTIATION (decl)
|
&& (!DECL_EXPLICIT_INSTANTIATION (decl)
|
||||||
|
|
|
@ -2685,7 +2685,7 @@ maybe_warn_cpp0x (const char* str)
|
||||||
/* We really want to suppress this warning in system headers,
|
/* We really want to suppress this warning in system headers,
|
||||||
because libstdc++ uses variadic templates even when we aren't
|
because libstdc++ uses variadic templates even when we aren't
|
||||||
in C++0x mode. */
|
in C++0x mode. */
|
||||||
pedwarn (0, "%s only available with -std=c++0x", str);
|
pedwarn (0, "%s only available with -std=c++0x or -std=gnu++0x", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Warn about the use of variadic templates when appropriate. */
|
/* Warn about the use of variadic templates when appropriate. */
|
||||||
|
|
|
@ -346,7 +346,7 @@ build_value_init_1 (tree type, bool have_ctor)
|
||||||
|
|
||||||
if (CLASS_TYPE_P (type))
|
if (CLASS_TYPE_P (type))
|
||||||
{
|
{
|
||||||
if (TYPE_HAS_USER_CONSTRUCTOR (type) && !have_ctor)
|
if (type_has_user_provided_constructor (type) && !have_ctor)
|
||||||
return build_cplus_new
|
return build_cplus_new
|
||||||
(type,
|
(type,
|
||||||
build_special_member_call (NULL_TREE, complete_ctor_identifier,
|
build_special_member_call (NULL_TREE, complete_ctor_identifier,
|
||||||
|
@ -516,9 +516,18 @@ perform_member_init (tree member, tree init)
|
||||||
tf_warning_or_error));
|
tf_warning_or_error));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (CP_TYPE_CONST_P (type)
|
||||||
|
&& init == NULL_TREE
|
||||||
|
&& !type_has_user_provided_default_constructor (type))
|
||||||
|
/* TYPE_NEEDS_CONSTRUCTING can be set just because we have a
|
||||||
|
vtable; still give this diagnostic. */
|
||||||
|
permerror ("%Juninitialized member %qD with %<const%> type %qT",
|
||||||
|
current_function_decl, member, type);
|
||||||
finish_expr_stmt (build_aggr_init (decl, init, 0,
|
finish_expr_stmt (build_aggr_init (decl, init, 0,
|
||||||
tf_warning_or_error));
|
tf_warning_or_error));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (init == NULL_TREE)
|
if (init == NULL_TREE)
|
||||||
|
@ -1883,7 +1892,9 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
|
|
||||||
is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || init);
|
is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || init);
|
||||||
if (CP_TYPE_CONST_P (elt_type) && !is_initialized)
|
|
||||||
|
if (CP_TYPE_CONST_P (elt_type) && !init
|
||||||
|
&& !type_has_user_provided_default_constructor (elt_type))
|
||||||
{
|
{
|
||||||
if (complain & tf_error)
|
if (complain & tf_error)
|
||||||
error ("uninitialized const in %<new%> of %q#T", elt_type);
|
error ("uninitialized const in %<new%> of %q#T", elt_type);
|
||||||
|
|
|
@ -1056,7 +1056,10 @@ write_unqualified_name (const tree decl)
|
||||||
else if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_DESTRUCTOR_P (decl))
|
else if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_DESTRUCTOR_P (decl))
|
||||||
write_special_name_destructor (decl);
|
write_special_name_destructor (decl);
|
||||||
else if (DECL_NAME (decl) == NULL_TREE)
|
else if (DECL_NAME (decl) == NULL_TREE)
|
||||||
|
{
|
||||||
|
gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
|
||||||
write_source_name (DECL_ASSEMBLER_NAME (decl));
|
write_source_name (DECL_ASSEMBLER_NAME (decl));
|
||||||
|
}
|
||||||
else if (DECL_CONV_FN_P (decl))
|
else if (DECL_CONV_FN_P (decl))
|
||||||
{
|
{
|
||||||
/* Conversion operator. Handle it right here.
|
/* Conversion operator. Handle it right here.
|
||||||
|
|
|
@ -1108,6 +1108,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
|
||||||
rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
|
rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
|
||||||
DECL_IN_AGGR_P (fn) = 1;
|
DECL_IN_AGGR_P (fn) = 1;
|
||||||
DECL_ARTIFICIAL (fn) = 1;
|
DECL_ARTIFICIAL (fn) = 1;
|
||||||
|
DECL_DEFAULTED_FN (fn) = 1;
|
||||||
DECL_NOT_REALLY_EXTERN (fn) = 1;
|
DECL_NOT_REALLY_EXTERN (fn) = 1;
|
||||||
DECL_DECLARED_INLINE_P (fn) = 1;
|
DECL_DECLARED_INLINE_P (fn) = 1;
|
||||||
DECL_INLINE (fn) = 1;
|
DECL_INLINE (fn) = 1;
|
||||||
|
|
|
@ -12378,7 +12378,7 @@ cp_parser_init_declarator (cp_parser* parser,
|
||||||
tree initializer;
|
tree initializer;
|
||||||
tree decl = NULL_TREE;
|
tree decl = NULL_TREE;
|
||||||
tree scope;
|
tree scope;
|
||||||
bool is_initialized;
|
int is_initialized;
|
||||||
/* Only valid if IS_INITIALIZED is true. In that case, CPP_EQ if
|
/* Only valid if IS_INITIALIZED is true. In that case, CPP_EQ if
|
||||||
initialized with "= ..", CPP_OPEN_PAREN if initialized with
|
initialized with "= ..", CPP_OPEN_PAREN if initialized with
|
||||||
"(...)". */
|
"(...)". */
|
||||||
|
@ -12514,8 +12514,18 @@ cp_parser_init_declarator (cp_parser* parser,
|
||||||
|| token->type == CPP_OPEN_PAREN
|
|| token->type == CPP_OPEN_PAREN
|
||||||
|| token->type == CPP_OPEN_BRACE)
|
|| token->type == CPP_OPEN_BRACE)
|
||||||
{
|
{
|
||||||
is_initialized = true;
|
is_initialized = 1;
|
||||||
initialization_kind = token->type;
|
initialization_kind = token->type;
|
||||||
|
|
||||||
|
if (token->type == CPP_EQ
|
||||||
|
&& function_declarator_p (declarator))
|
||||||
|
{
|
||||||
|
cp_token *t2 = cp_lexer_peek_nth_token (parser->lexer, 2);
|
||||||
|
if (t2->keyword == RID_DEFAULT)
|
||||||
|
is_initialized = 2;
|
||||||
|
else if (t2->keyword == RID_DELETE)
|
||||||
|
is_initialized = 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -12527,7 +12537,7 @@ cp_parser_init_declarator (cp_parser* parser,
|
||||||
cp_parser_error (parser, "expected initializer");
|
cp_parser_error (parser, "expected initializer");
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
is_initialized = false;
|
is_initialized = 0;
|
||||||
initialization_kind = CPP_EOF;
|
initialization_kind = CPP_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15681,6 +15691,15 @@ cp_parser_pure_specifier (cp_parser* parser)
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
/* Look for the `0' token. */
|
/* Look for the `0' token. */
|
||||||
token = cp_lexer_consume_token (parser->lexer);
|
token = cp_lexer_consume_token (parser->lexer);
|
||||||
|
|
||||||
|
/* Accept = default or = delete in c++0x mode. */
|
||||||
|
if (token->keyword == RID_DEFAULT
|
||||||
|
|| token->keyword == RID_DELETE)
|
||||||
|
{
|
||||||
|
maybe_warn_cpp0x ("defaulted and deleted functions");
|
||||||
|
return token->u.value;
|
||||||
|
}
|
||||||
|
|
||||||
/* c_lex_with_flags marks a single digit '0' with PURE_ZERO. */
|
/* c_lex_with_flags marks a single digit '0' with PURE_ZERO. */
|
||||||
if (token->type != CPP_NUMBER || !(token->flags & PURE_ZERO))
|
if (token->type != CPP_NUMBER || !(token->flags & PURE_ZERO))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1912,6 +1912,20 @@ check_final_overrider (tree overrider, tree basefn)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DECL_DELETED_FN (basefn) != DECL_DELETED_FN (overrider))
|
||||||
|
{
|
||||||
|
if (DECL_DELETED_FN (overrider))
|
||||||
|
{
|
||||||
|
error ("deleted function %q+D", overrider);
|
||||||
|
error ("overriding non-deleted function %q+D", basefn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error ("non-deleted function %q+D", overrider);
|
||||||
|
error ("overriding deleted function %q+D", basefn);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
// Positive test for defaulted/deleted fns
|
||||||
|
// { dg-do run }
|
||||||
|
// { dg-options "-std=c++0x" }
|
||||||
|
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
A() = default;
|
||||||
|
A(const A&) = delete;
|
||||||
|
A& operator=(const A&) = default;
|
||||||
|
~A();
|
||||||
|
};
|
||||||
|
|
||||||
|
A::~A() = default;
|
||||||
|
|
||||||
|
void f() = delete;
|
||||||
|
|
||||||
|
struct B
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
B() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
A a1, a2;
|
||||||
|
B b = {1};
|
||||||
|
a1 = a2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fns defaulted in class defn are trivial
|
||||||
|
struct C
|
||||||
|
{
|
||||||
|
C() = default;
|
||||||
|
C(const C&) = default;
|
||||||
|
C& operator=(const C&) = default;
|
||||||
|
~C() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
union U
|
||||||
|
{
|
||||||
|
C c;
|
||||||
|
};
|
|
@ -0,0 +1,66 @@
|
||||||
|
// Negative test for defaulted/deleted fns.
|
||||||
|
// { dg-options "-std=c++0x" }
|
||||||
|
|
||||||
|
void f(); // { dg-error "previous" }
|
||||||
|
void f() = delete; // { dg-error "deleted" }
|
||||||
|
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
A() { } // { dg-error "previous" }
|
||||||
|
void f() = default; // { dg-error "default" }
|
||||||
|
};
|
||||||
|
|
||||||
|
A::A() = default; // { dg-error "redefinition" }
|
||||||
|
|
||||||
|
void g() {} // { dg-error "previous" }
|
||||||
|
void g() = delete; // { dg-error "redefinition" }
|
||||||
|
|
||||||
|
struct B
|
||||||
|
{
|
||||||
|
B() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
const B b; // { dg-error "uninitialized const" }
|
||||||
|
|
||||||
|
struct C
|
||||||
|
{
|
||||||
|
virtual void f() = delete; // { dg-error "overriding deleted" }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct D: public C
|
||||||
|
{
|
||||||
|
virtual void f(); // { dg-error "non-deleted function" }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct E
|
||||||
|
{
|
||||||
|
const B b;
|
||||||
|
E() { } // { dg-error "uninitialized" }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct F
|
||||||
|
{
|
||||||
|
F() = default;
|
||||||
|
F(const F&) = delete; // { dg-error "deleted" }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct G
|
||||||
|
{
|
||||||
|
G();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ctor defaulted after class defn is not trivial
|
||||||
|
G::G() = default;
|
||||||
|
|
||||||
|
union U
|
||||||
|
{
|
||||||
|
G g; // { dg-error "constructor" }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
F f;
|
||||||
|
F f2(f); // { dg-error "used" }
|
||||||
|
B* b = new const B; // { dg-error "uninitialized const" }
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// Bug: 23225
|
// Bug: 23225
|
||||||
|
|
||||||
void Dispatcher()
|
void Dispatcher()
|
||||||
(__builtin_offsetof (ArgsType, largeMsgLen))
|
(__builtin_offsetof (ArgsType, largeMsgLen)) // { dg-error "initialize|end of input" }
|
||||||
/* { dg-error "function " "function" { target *-*-* } 4 } */
|
|
||||||
|
|
|
@ -35,4 +35,4 @@ struct C
|
||||||
typename N::A f7; // { dg-error "15: error: invalid use of template-name 'N::A' without an argument list" }
|
typename N::A f7; // { dg-error "15: error: invalid use of template-name 'N::A' without an argument list" }
|
||||||
};
|
};
|
||||||
|
|
||||||
// { dg-bogus "bogus excess errors in declaration" "bogus excess errors in declaration" { xfail *-*-* } 17 }
|
// { dg-bogus "bogus excess errors in declaration" "bogus excess errors in declaration" { target *-*-* } 17 }
|
||||||
|
|
|
@ -5,5 +5,5 @@ struct A
|
||||||
template<int> void foo(X); // { dg-error "declared" }
|
template<int> void foo(X); // { dg-error "declared" }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int> void f()(0); // { dg-error "initialized" }
|
template<int> void f()(0); // { dg-error "initialize" }
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
// nested type.
|
// nested type.
|
||||||
|
|
||||||
template <typename> struct A
|
template <typename> struct A
|
||||||
{ // { dg-error "candidates" }
|
{ // { not-dg-error "candidates" }
|
||||||
template <typename> A(typename A::X) {} // { dg-error "no type" }
|
template <typename> A(typename A::X) {} // { dg-error "no type" }
|
||||||
};
|
};
|
||||||
|
|
||||||
A<void> a; // { dg-error "instantiated|no match" }
|
A<void> a; // { not-dg-error "instantiated|no match" }
|
||||||
|
// We currently don't give the "no match" error because we don't add the
|
||||||
|
// invalid constructor template to TYPE_METHODS.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Origin: Carl Nygard <cnygard@bellatlantic.net>
|
// Origin: Carl Nygard <cnygard@bellatlantic.net>
|
||||||
|
|
||||||
template <class RT>
|
template <class RT>
|
||||||
class Test { // { dg-error "" } in instantiation
|
class Test {
|
||||||
public:
|
public:
|
||||||
Test(const RT& c = RT()) {} // { dg-error "" } reference to void
|
Test(const RT& c = RT()) {} // { dg-error "" } reference to void
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue