This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH to implement defaulted/deleted functions
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 24 Jul 2008 15:14:01 -0400
- Subject: C++ PATCH to implement defaulted/deleted functions
bkoz asked me to implement this stuff for the atomics library. While
working on it I realized that it wouldn't actually help; apparently
there's an open issue in the library working group about this. But I
went ahead and finished it anyway, can't hurt to have another C++0x
feature taken care of.
Tested x86_64-pc-linux-gnu, applied to trunk.
2008-07-23 Jason Merrill <jason@redhat.com>
* 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.
Index: cp/init.c
===================================================================
*** cp/init.c (revision 138106)
--- cp/init.c (working copy)
*************** build_value_init_1 (tree type, bool have
*** 346,352 ****
if (CLASS_TYPE_P (type))
{
! if (TYPE_HAS_USER_CONSTRUCTOR (type) && !have_ctor)
return build_cplus_new
(type,
build_special_member_call (NULL_TREE, complete_ctor_identifier,
--- 346,352 ----
if (CLASS_TYPE_P (type))
{
! if (type_has_user_provided_constructor (type) && !have_ctor)
return build_cplus_new
(type,
build_special_member_call (NULL_TREE, complete_ctor_identifier,
*************** perform_member_init (tree member, tree i
*** 516,523 ****
tf_warning_or_error));
}
else
! finish_expr_stmt (build_aggr_init (decl, init, 0,
! tf_warning_or_error));
}
else
{
--- 516,532 ----
tf_warning_or_error));
}
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,
! tf_warning_or_error));
! }
}
else
{
*************** build_new_1 (tree placement, tree type,
*** 1883,1889 ****
return error_mark_node;
is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || init);
! if (CP_TYPE_CONST_P (elt_type) && !is_initialized)
{
if (complain & tf_error)
error ("uninitialized const in %<new%> of %q#T", elt_type);
--- 1892,1900 ----
return error_mark_node;
is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || init);
!
! if (CP_TYPE_CONST_P (elt_type) && !init
! && !type_has_user_provided_default_constructor (elt_type))
{
if (complain & tf_error)
error ("uninitialized const in %<new%> of %q#T", elt_type);
Index: cp/class.c
===================================================================
*** cp/class.c (revision 138106)
--- cp/class.c (working copy)
*************** check_field_decls (tree t, tree *access_
*** 3045,3051 ****
/* Core issue 80: A nonstatic data member is required to have a
different name from the class iff the class has a
! user-defined constructor. */
if (constructor_name_p (DECL_NAME (x), t)
&& TYPE_HAS_USER_CONSTRUCTOR (t))
permerror ("field %q+#D with same name as class", x);
--- 3045,3051 ----
/* Core issue 80: A nonstatic data member is required to have a
different name from the class iff the class has a
! user-declared constructor. */
if (constructor_name_p (DECL_NAME (x), t)
&& TYPE_HAS_USER_CONSTRUCTOR (t))
permerror ("field %q+#D with same name as class", x);
*************** check_methods (tree t)
*** 3767,3774 ****
if (DECL_PURE_VIRTUAL_P (x))
VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (t), x);
}
! /* All user-declared destructors are non-trivial. */
! if (DECL_DESTRUCTOR_P (x))
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
}
}
--- 3767,3774 ----
if (DECL_PURE_VIRTUAL_P (x))
VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (t), x);
}
! /* All user-provided destructors are non-trivial. */
! if (DECL_DESTRUCTOR_P (x) && !DECL_DEFAULTED_FN (x))
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
}
}
*************** type_has_user_nondefault_constructor (tr
*** 4067,4072 ****
--- 4067,4152 ----
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. */
static void
*************** check_bases_and_members (tree t)
*** 4158,4163 ****
--- 4238,4245 ----
should take a non-const reference argument. */
int no_const_asn_ref;
tree access_decls;
+ bool saved_complex_asn_ref;
+ bool saved_nontrivial_dtor;
/* By default, we use const reference arguments and generate default
constructors. */
*************** check_bases_and_members (tree t)
*** 4171,4176 ****
--- 4253,4264 ----
/* Check all the method declarations. */
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_field_decls until we have called check_bases check_methods,
as check_field_decls depends on TYPE_HAS_NONTRIVIAL_DESTRUCTOR
*************** check_bases_and_members (tree t)
*** 4186,4215 ****
/* Do some bookkeeping that will guide the generation of implicitly
declared member functions. */
! TYPE_HAS_COMPLEX_INIT_REF (t)
! |= (TYPE_HAS_INIT_REF (t) || TYPE_CONTAINS_VPTR_P (t));
/* We need to call a constructor for this class if it has a
! user-declared constructor, or if the default constructor is going
to initialize the vptr. (This is not an if-and-only-if;
TYPE_NEEDS_CONSTRUCTING is set elsewhere if bases or members
themselves need constructing.) */
TYPE_NEEDS_CONSTRUCTING (t)
! |= (TYPE_HAS_USER_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
/* [dcl.init.aggr]
! An aggregate is an array or a class with no user-declared
constructors ... and no virtual functions.
Again, other conditions for being an aggregate are checked
elsewhere. */
CLASSTYPE_NON_AGGREGATE (t)
! |= (TYPE_HAS_USER_CONSTRUCTOR (t) || TYPE_POLYMORPHIC_P (t));
CLASSTYPE_NON_POD_P (t)
|= (CLASSTYPE_NON_AGGREGATE (t)
! || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
! || TYPE_HAS_ASSIGN_REF (t));
! TYPE_HAS_COMPLEX_ASSIGN_REF (t)
! |= TYPE_HAS_ASSIGN_REF (t) || TYPE_CONTAINS_VPTR_P (t);
TYPE_HAS_COMPLEX_DFLT (t)
|= (TYPE_HAS_DEFAULT_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
--- 4274,4300 ----
/* Do some bookkeeping that will guide the generation of implicitly
declared member functions. */
! TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_CONTAINS_VPTR_P (t);
/* We need to call a constructor for this class if it has a
! user-provided constructor, or if the default constructor is going
to initialize the vptr. (This is not an if-and-only-if;
TYPE_NEEDS_CONSTRUCTING is set elsewhere if bases or members
themselves need constructing.) */
TYPE_NEEDS_CONSTRUCTING (t)
! |= (type_has_user_provided_constructor (t) || TYPE_CONTAINS_VPTR_P (t));
/* [dcl.init.aggr]
! An aggregate is an array or a class with no user-provided
constructors ... and no virtual functions.
Again, other conditions for being an aggregate are checked
elsewhere. */
CLASSTYPE_NON_AGGREGATE (t)
! |= (type_has_user_provided_constructor (t) || TYPE_POLYMORPHIC_P (t));
CLASSTYPE_NON_POD_P (t)
|= (CLASSTYPE_NON_AGGREGATE (t)
! || saved_nontrivial_dtor || saved_complex_asn_ref);
! TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_CONTAINS_VPTR_P (t);
TYPE_HAS_COMPLEX_DFLT (t)
|= (TYPE_HAS_DEFAULT_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
Index: cp/decl.c
===================================================================
*** cp/decl.c (revision 138106)
--- cp/decl.c (working copy)
*************** duplicate_decls (tree newdecl, tree oldd
*** 1613,1618 ****
--- 1613,1624 ----
warning (OPT_Wredundant_decls, "redundant redeclaration of %qD in same scope", newdecl);
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. */
*************** groktypename (cp_decl_specifier_seq *typ
*** 3931,3943 ****
grokfield.) The DECL corresponding to the DECLARATOR is returned.
If an error occurs, the error_mark_node is returned instead.
! DECLSPECS are the decl-specifiers for the declaration. INITIALIZED
! is true if an explicit initializer is present, but false if this is
! a variable implicitly initialized via a default constructor.
! ATTRIBUTES and PREFIX_ATTRIBUTES are GNU attributes associated with
! this declaration. *PUSHED_SCOPE_P is set to the scope entered in
! this function, if any; if set, the caller is responsible for
! calling pop_scope. */
tree
start_decl (const cp_declarator *declarator,
--- 3937,3950 ----
grokfield.) The DECL corresponding to the DECLARATOR is returned.
If an error occurs, the error_mark_node is returned instead.
! DECLSPECS are the decl-specifiers for the declaration. INITIALIZED is 1
! if an explicit initializer is present, or 2 for an explicitly defaulted
! function, or 3 for an explicitly deleted function, but 0 if this is a
! variable implicitly initialized via a default constructor. ATTRIBUTES
! and PREFIX_ATTRIBUTES are GNU attributes associated with this
! declaration. *PUSHED_SCOPE_P is set to the scope entered in this
! function, if any; if set, the caller is responsible for calling
! pop_scope. */
tree
start_decl (const cp_declarator *declarator,
*************** start_decl (const cp_declarator *declara
*** 3991,4002 ****
switch (TREE_CODE (decl))
{
case TYPE_DECL:
! error ("typedef %qD is initialized (use __typeof__ instead)", decl);
return error_mark_node;
case FUNCTION_DECL:
! error ("function %q#D is initialized like a variable", decl);
! return error_mark_node;
default:
break;
--- 3998,4012 ----
switch (TREE_CODE (decl))
{
case TYPE_DECL:
! error ("typedef %qD is initialized (use decltype instead)", decl);
return error_mark_node;
case FUNCTION_DECL:
! if (initialized == 3)
! /* 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:
break;
*************** cp_finish_decl (tree decl, tree init, bo
*** 5686,5695 ****
else
abstract_virtuals_error (decl, type);
! if (TREE_CODE (decl) == FUNCTION_DECL
! || TREE_TYPE (decl) == error_mark_node)
/* No initialization required. */
;
else if (DECL_EXTERNAL (decl)
&& ! (DECL_LANG_SPECIFIC (decl)
&& DECL_NOT_REALLY_EXTERN (decl)))
--- 5696,5733 ----
else
abstract_virtuals_error (decl, type);
! if (TREE_TYPE (decl) == error_mark_node)
/* 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)
&& ! (DECL_LANG_SPECIFIC (decl)
&& DECL_NOT_REALLY_EXTERN (decl)))
*************** check_var_type (tree identifier, tree ty
*** 7361,7367 ****
Don't make a DECL node; just return the ..._TYPE node.
FIELD for a struct or union field; make a FIELD_DECL.
BITFIELD for a field with specified width.
! INITIALIZED is 1 if the decl has an initializer.
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
--- 7399,7405 ----
Don't make a DECL node; just return the ..._TYPE node.
FIELD for a struct or union field; make a FIELD_DECL.
BITFIELD for a field with specified width.
! INITIALIZED is as for start_decl.
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
*************** grokdeclarator (const cp_declarator *dec
*** 7459,7464 ****
--- 7497,7505 ----
else if (decl_context == BITFIELD)
bitfield = 1, decl_context = FIELD;
+ if (initialized > 1)
+ funcdef_flag = true;
+
/* Look inside a declarator for the name being declared
and get it as a string, for an error message. */
for (id_declarator = declarator;
*************** grok_special_member_properties (tree dec
*** 9670,9675 ****
--- 9711,9718 ----
are no other parameters or else all other parameters have
default arguments. */
TYPE_HAS_INIT_REF (class_type) = 1;
+ if (!DECL_DEFAULTED_FN (decl))
+ TYPE_HAS_COMPLEX_INIT_REF (class_type) = 1;
if (ctor > 1)
TYPE_HAS_CONST_INIT_REF (class_type) = 1;
}
*************** grok_special_member_properties (tree dec
*** 9691,9696 ****
--- 9734,9741 ----
if (assop)
{
TYPE_HAS_ASSIGN_REF (class_type) = 1;
+ if (!DECL_DEFAULTED_FN (decl))
+ TYPE_HAS_COMPLEX_ASSIGN_REF (class_type) = 1;
if (assop != 1)
TYPE_HAS_CONST_ASSIGN_REF (class_type) = 1;
}
Index: cp/call.c
===================================================================
*** cp/call.c (revision 138106)
--- cp/call.c (working copy)
*************** build_over_call (struct z_candidate *can
*** 5090,5095 ****
--- 5090,5096 ----
int is_method = 0;
int nargs;
tree *argarray;
+ bool already_used = false;
/* 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
*************** build_over_call (struct z_candidate *can
*** 5310,5316 ****
/* [class.copy]: the copy constructor is implicitly defined even if
the implementation elided its use. */
if (TYPE_HAS_COMPLEX_INIT_REF (DECL_CONTEXT (fn)))
! mark_used (fn);
/* 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
--- 5311,5320 ----
/* [class.copy]: the copy constructor is implicitly defined even if
the implementation elided its use. */
if (TYPE_HAS_COMPLEX_INIT_REF (DECL_CONTEXT (fn)))
! {
! mark_used (fn);
! already_used = true;
! }
/* 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
*************** build_over_call (struct z_candidate *can
*** 5370,5376 ****
return val;
}
! mark_used (fn);
if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
{
--- 5374,5381 ----
return val;
}
! if (!already_used)
! mark_used (fn);
if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
{
Index: cp/method.c
===================================================================
*** cp/method.c (revision 138106)
--- cp/method.c (working copy)
*************** implicitly_declare_fn (special_function_
*** 1108,1113 ****
--- 1108,1114 ----
rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
DECL_IN_AGGR_P (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
+ DECL_DEFAULTED_FN (fn) = 1;
DECL_NOT_REALLY_EXTERN (fn) = 1;
DECL_DECLARED_INLINE_P (fn) = 1;
DECL_INLINE (fn) = 1;
Index: cp/error.c
===================================================================
*** cp/error.c (revision 138106)
--- cp/error.c (working copy)
*************** maybe_warn_cpp0x (const char* str)
*** 2685,2691 ****
/* We really want to suppress this warning in system headers,
because libstdc++ uses variadic templates even when we aren't
in C++0x mode. */
! pedwarn (0, "%s only available with -std=c++0x", str);
}
/* Warn about the use of variadic templates when appropriate. */
--- 2685,2691 ----
/* We really want to suppress this warning in system headers,
because libstdc++ uses variadic templates even when we aren't
in C++0x mode. */
! pedwarn (0, "%s only available with -std=c++0x or -std=gnu++0x", str);
}
/* Warn about the use of variadic templates when appropriate. */
Index: cp/mangle.c
===================================================================
*** cp/mangle.c (revision 138106)
--- cp/mangle.c (working copy)
*************** write_unqualified_name (const tree decl)
*** 1056,1062 ****
else if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_DESTRUCTOR_P (decl))
write_special_name_destructor (decl);
else if (DECL_NAME (decl) == NULL_TREE)
! write_source_name (DECL_ASSEMBLER_NAME (decl));
else if (DECL_CONV_FN_P (decl))
{
/* Conversion operator. Handle it right here.
--- 1056,1065 ----
else if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_DESTRUCTOR_P (decl))
write_special_name_destructor (decl);
else if (DECL_NAME (decl) == NULL_TREE)
! {
! gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
! write_source_name (DECL_ASSEMBLER_NAME (decl));
! }
else if (DECL_CONV_FN_P (decl))
{
/* Conversion operator. Handle it right here.
Index: cp/cp-tree.h
===================================================================
*** cp/cp-tree.h (revision 138106)
--- cp/cp-tree.h (working copy)
*************** struct lang_decl_flags GTY(())
*** 1609,1615 ****
unsigned repo_available_p : 1;
unsigned hidden_friend_p : 1;
unsigned threadprivate_p : 1;
! /* One unused bit. */
union lang_decl_u {
/* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
--- 1609,1615 ----
unsigned repo_available_p : 1;
unsigned hidden_friend_p : 1;
unsigned threadprivate_p : 1;
! unsigned defaulted_p : 1;
union lang_decl_u {
/* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
*************** more_aggr_init_expr_args_p (const aggr_i
*** 2626,2631 ****
--- 2626,2639 ----
#define CP_DECL_THREADPRIVATE_P(DECL) \
(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'. */
#define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP)
*************** extern void check_for_override (tree,
*** 4171,4176 ****
--- 4179,4187 ----
extern void push_class_stack (void);
extern void pop_class_stack (void);
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 */
extern tree convert_to_reference (tree, tree, int, int, tree);
Index: cp/search.c
===================================================================
*** cp/search.c (revision 138106)
--- cp/search.c (working copy)
*************** check_final_overrider (tree overrider, t
*** 1912,1917 ****
--- 1912,1931 ----
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;
}
Index: cp/decl2.c
===================================================================
*** cp/decl2.c (revision 138106)
--- cp/decl2.c (working copy)
*************** grokfield (const cp_declarator *declarat
*** 821,827 ****
{
/* Initializers for functions are rejected early in the parser.
If we get here, it must be a pure specifier for a method. */
! if (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE)
{
gcc_assert (error_operand_p (init) || integer_zerop (init));
DECL_PURE_VIRTUAL_P (value) = 1;
--- 821,845 ----
{
/* Initializers for functions are rejected early in the parser.
If we get here, it must be a pure specifier for a method. */
! 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));
DECL_PURE_VIRTUAL_P (value) = 1;
*************** mark_used (tree decl)
*** 3739,3745 ****
/* Is it a synthesized method that needs to be synthesized? */
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
! && DECL_ARTIFICIAL (decl)
&& !DECL_THUNK_P (decl)
&& ! DECL_INITIAL (decl)
/* Kludge: don't synthesize for default args. Unfortunately this
--- 3757,3763 ----
/* Is it a synthesized method that needs to be synthesized? */
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
! && DECL_DEFAULTED_FN (decl)
&& !DECL_THUNK_P (decl)
&& ! DECL_INITIAL (decl)
/* Kludge: don't synthesize for default args. Unfortunately this
*************** mark_used (tree decl)
*** 3752,3757 ****
--- 3770,3781 ----
/* If we've already synthesized the method we don't need to
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)
&& DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
&& (!DECL_EXPLICIT_INSTANTIATION (decl)
Index: cp/parser.c
===================================================================
*** cp/parser.c (revision 138106)
--- cp/parser.c (working copy)
*************** cp_parser_init_declarator (cp_parser* pa
*** 12378,12384 ****
tree initializer;
tree decl = NULL_TREE;
tree scope;
! bool is_initialized;
/* Only valid if IS_INITIALIZED is true. In that case, CPP_EQ if
initialized with "= ..", CPP_OPEN_PAREN if initialized with
"(...)". */
--- 12378,12384 ----
tree initializer;
tree decl = NULL_TREE;
tree scope;
! int is_initialized;
/* Only valid if IS_INITIALIZED is true. In that case, CPP_EQ if
initialized with "= ..", CPP_OPEN_PAREN if initialized with
"(...)". */
*************** cp_parser_init_declarator (cp_parser* pa
*** 12514,12521 ****
|| token->type == CPP_OPEN_PAREN
|| token->type == CPP_OPEN_BRACE)
{
! is_initialized = true;
initialization_kind = token->type;
}
else
{
--- 12514,12531 ----
|| token->type == CPP_OPEN_PAREN
|| token->type == CPP_OPEN_BRACE)
{
! is_initialized = 1;
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
{
*************** cp_parser_init_declarator (cp_parser* pa
*** 12527,12533 ****
cp_parser_error (parser, "expected initializer");
return error_mark_node;
}
! is_initialized = false;
initialization_kind = CPP_EOF;
}
--- 12537,12543 ----
cp_parser_error (parser, "expected initializer");
return error_mark_node;
}
! is_initialized = 0;
initialization_kind = CPP_EOF;
}
*************** cp_parser_pure_specifier (cp_parser* par
*** 15681,15686 ****
--- 15691,15705 ----
return error_mark_node;
/* Look for the `0' token. */
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. */
if (token->type != CPP_NUMBER || !(token->flags & PURE_ZERO))
{
Index: testsuite/g++.old-deja/g++.pt/error2.C
===================================================================
*** testsuite/g++.old-deja/g++.pt/error2.C (revision 138106)
--- testsuite/g++.old-deja/g++.pt/error2.C (working copy)
***************
*** 2,8 ****
// Origin: Carl Nygard <cnygard@bellatlantic.net>
template <class RT>
! class Test { // { dg-error "" } in instantiation
public:
Test(const RT& c = RT()) {} // { dg-error "" } reference to void
};
--- 2,8 ----
// Origin: Carl Nygard <cnygard@bellatlantic.net>
template <class RT>
! class Test {
public:
Test(const RT& c = RT()) {} // { dg-error "" } reference to void
};
Index: testsuite/g++.dg/parse/crash27.C
===================================================================
*** testsuite/g++.dg/parse/crash27.C (revision 138106)
--- testsuite/g++.dg/parse/crash27.C (working copy)
***************
*** 1,5 ****
// Bug: 23225
void Dispatcher()
! (__builtin_offsetof (ArgsType, largeMsgLen))
! /* { dg-error "function " "function" { target *-*-* } 4 } */
--- 1,4 ----
// Bug: 23225
void Dispatcher()
! (__builtin_offsetof (ArgsType, largeMsgLen)) // { dg-error "initialize|end of input" }
Index: testsuite/g++.dg/parse/error15.C
===================================================================
*** testsuite/g++.dg/parse/error15.C (revision 138106)
--- testsuite/g++.dg/parse/error15.C (working copy)
*************** struct C
*** 35,38 ****
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 }
--- 35,38 ----
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" { target *-*-* } 17 }
Index: testsuite/g++.dg/cpp0x/defaulted1.C
===================================================================
*** testsuite/g++.dg/cpp0x/defaulted1.C (revision 0)
--- testsuite/g++.dg/cpp0x/defaulted1.C (revision 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;
+ };
Index: testsuite/g++.dg/cpp0x/defaulted2.C
===================================================================
*** testsuite/g++.dg/cpp0x/defaulted2.C (revision 0)
--- testsuite/g++.dg/cpp0x/defaulted2.C (revision 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" }
+ }
+
Index: testsuite/g++.dg/template/crash60.C
===================================================================
*** testsuite/g++.dg/template/crash60.C (revision 138106)
--- testsuite/g++.dg/template/crash60.C (working copy)
*************** struct A
*** 5,9 ****
template<int> void foo(X); // { dg-error "declared" }
};
! template<int> void f()(0); // { dg-error "initialized" }
--- 5,9 ----
template<int> void foo(X); // { dg-error "declared" }
};
! template<int> void f()(0); // { dg-error "initialize" }
Index: testsuite/g++.dg/template/crash7.C
===================================================================
*** testsuite/g++.dg/template/crash7.C (revision 138106)
--- testsuite/g++.dg/template/crash7.C (working copy)
***************
*** 6,13 ****
// nested type.
template <typename> struct A
! { // { dg-error "candidates" }
template <typename> A(typename A::X) {} // { dg-error "no type" }
};
! A<void> a; // { dg-error "instantiated|no match" }
--- 6,15 ----
// nested type.
template <typename> struct A
! { // { not-dg-error "candidates" }
template <typename> A(typename A::X) {} // { dg-error "no type" }
};
! 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.