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:
Jason Merrill 2008-07-24 15:15:00 -04:00 committed by Jason Merrill
parent c3005b0f0c
commit b87d79e640
19 changed files with 406 additions and 47 deletions

View File

@ -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

View File

@ -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,7 +5374,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
return val; return val;
} }
mark_used (fn); if (!already_used)
mark_used (fn);
if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0) if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
{ {

View File

@ -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));

View File

@ -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);

View File

@ -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;
} }

View File

@ -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)

View File

@ -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. */

View File

@ -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,8 +516,17 @@ perform_member_init (tree member, tree init)
tf_warning_or_error)); tf_warning_or_error));
} }
else else
finish_expr_stmt (build_aggr_init (decl, init, 0, {
tf_warning_or_error)); 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,
tf_warning_or_error));
}
} }
else else
{ {
@ -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);

View File

@ -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)
write_source_name (DECL_ASSEMBLER_NAME (decl)); {
gcc_assert (DECL_ASSEMBLER_NAME_SET_P (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.

View File

@ -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;

View File

@ -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))
{ {

View File

@ -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;
} }

View File

@ -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;
};

View File

@ -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" }
}

View File

@ -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 } */

View File

@ -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 }

View File

@ -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" }

View File

@ -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.

View File

@ -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
}; };