From b87d79e640b3e9ab1e126bb6d87472b2a261a640 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 24 Jul 2008 15:15:00 -0400 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 31 ++++++ gcc/cp/call.c | 9 +- gcc/cp/class.c | 111 ++++++++++++++++++--- gcc/cp/cp-tree.h | 13 ++- gcc/cp/decl.c | 71 ++++++++++--- gcc/cp/decl2.c | 28 +++++- gcc/cp/error.c | 2 +- gcc/cp/init.c | 19 +++- gcc/cp/mangle.c | 5 +- gcc/cp/method.c | 1 + gcc/cp/parser.c | 25 ++++- gcc/cp/search.c | 14 +++ gcc/testsuite/g++.dg/cpp0x/defaulted1.C | 43 ++++++++ gcc/testsuite/g++.dg/cpp0x/defaulted2.C | 66 ++++++++++++ gcc/testsuite/g++.dg/parse/crash27.C | 3 +- gcc/testsuite/g++.dg/parse/error15.C | 2 +- gcc/testsuite/g++.dg/template/crash60.C | 2 +- gcc/testsuite/g++.dg/template/crash7.C | 6 +- gcc/testsuite/g++.old-deja/g++.pt/error2.C | 2 +- 19 files changed, 406 insertions(+), 47 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3757dcfe905..c9eaf0f055a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,34 @@ +2008-07-23 Jason Merrill + + 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 PR 35058 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 7cff6adb3a9..2304b5da71b 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5090,6 +5090,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) 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 @@ -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 the implementation elided its use. */ 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 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; } - mark_used (fn); + if (!already_used) + mark_used (fn); if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0) { diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 0c7a76c697a..0649eec2486 100644 --- a/gcc/cp/class.c +++ b/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 different name from the class iff the class has a - user-defined constructor. */ + 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); @@ -3767,8 +3767,8 @@ check_methods (tree t) 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)) + /* All user-provided destructors are non-trivial. */ + if (DECL_DESTRUCTOR_P (x) && !DECL_DEFAULTED_FN (x)) TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1; } } @@ -4067,6 +4067,86 @@ type_has_user_nondefault_constructor (tree t) 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 @@ -4158,6 +4238,8 @@ check_bases_and_members (tree t) 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. */ @@ -4171,6 +4253,12 @@ check_bases_and_members (tree t) /* 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 @@ -4186,30 +4274,27 @@ check_bases_and_members (tree t) /* 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)); + 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-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; 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)); + |= (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-declared + 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_CONSTRUCTOR (t) || TYPE_POLYMORPHIC_P (t)); + |= (type_has_user_provided_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); + || 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)); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6bc5d2d2782..1488d4ce6f9 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1609,7 +1609,7 @@ struct lang_decl_flags GTY(()) unsigned repo_available_p : 1; unsigned hidden_friend_p : 1; unsigned threadprivate_p : 1; - /* One unused bit. */ + unsigned defaulted_p : 1; union lang_decl_u { /* 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) \ (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) @@ -4171,6 +4179,9 @@ extern void check_for_override (tree, tree); 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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index cc9e8c8bbc0..d02cab2c867 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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, "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. */ @@ -3931,13 +3937,14 @@ groktypename (cp_decl_specifier_seq *type_specifiers, 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. */ + 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, @@ -3991,12 +3998,15 @@ start_decl (const cp_declarator *declarator, switch (TREE_CODE (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; case FUNCTION_DECL: - error ("function %q#D is initialized like a variable", decl); - return error_mark_node; + 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; @@ -5686,10 +5696,38 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, else abstract_virtuals_error (decl, type); - if (TREE_CODE (decl) == FUNCTION_DECL - || TREE_TYPE (decl) == error_mark_node) + 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))) @@ -7361,7 +7399,7 @@ check_var_type (tree identifier, tree type) 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. + 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 @@ -7459,6 +7497,9 @@ grokdeclarator (const cp_declarator *declarator, 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; @@ -9670,6 +9711,8 @@ grok_special_member_properties (tree decl) 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; } @@ -9691,6 +9734,8 @@ grok_special_member_properties (tree decl) 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; } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index f14f94d16b5..6e6151d23f7 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -821,7 +821,25 @@ grokfield (const cp_declarator *declarator, { /* 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) + 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; @@ -3739,7 +3757,7 @@ mark_used (tree decl) /* 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_DEFAULTED_FN (decl) && !DECL_THUNK_P (decl) && ! DECL_INITIAL (decl) /* 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 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) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index d3ec82aaaef..ef26ad9114a 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -2685,7 +2685,7 @@ maybe_warn_cpp0x (const char* str) /* 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); + pedwarn (0, "%s only available with -std=c++0x or -std=gnu++0x", str); } /* Warn about the use of variadic templates when appropriate. */ diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 7319568b4b4..3dd6c4e328b 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -346,7 +346,7 @@ build_value_init_1 (tree type, bool have_ctor) 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 (type, build_special_member_call (NULL_TREE, complete_ctor_identifier, @@ -516,8 +516,17 @@ perform_member_init (tree member, tree init) tf_warning_or_error)); } 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 % type %qT", + current_function_decl, member, type); + finish_expr_stmt (build_aggr_init (decl, init, 0, + tf_warning_or_error)); + } } else { @@ -1883,7 +1892,9 @@ build_new_1 (tree placement, tree type, tree nelts, tree init, return error_mark_node; 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) error ("uninitialized const in % of %q#T", elt_type); diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 1bc72b86a2d..0703d0a96f7 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1056,7 +1056,10 @@ write_unqualified_name (const tree decl) 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)); + { + 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. diff --git a/gcc/cp/method.c b/gcc/cp/method.c index bd63d0cba52..f3d23eba23d 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -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); 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; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 420b92cea10..15b66b03b95 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -12378,7 +12378,7 @@ cp_parser_init_declarator (cp_parser* parser, tree initializer; tree decl = NULL_TREE; tree scope; - bool is_initialized; + int is_initialized; /* Only valid if IS_INITIALIZED is true. In that case, CPP_EQ if 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_BRACE) { - is_initialized = true; + 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 { @@ -12527,7 +12537,7 @@ cp_parser_init_declarator (cp_parser* parser, cp_parser_error (parser, "expected initializer"); return error_mark_node; } - is_initialized = false; + is_initialized = 0; initialization_kind = CPP_EOF; } @@ -15681,6 +15691,15 @@ cp_parser_pure_specifier (cp_parser* parser) 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)) { diff --git a/gcc/cp/search.c b/gcc/cp/search.c index cee29240e9e..7fc040bc8c4 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1912,6 +1912,20 @@ check_final_overrider (tree overrider, tree basefn) 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; } diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted1.C b/gcc/testsuite/g++.dg/cpp0x/defaulted1.C new file mode 100644 index 00000000000..e8fe37eb39a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/defaulted1.C @@ -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; +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted2.C b/gcc/testsuite/g++.dg/cpp0x/defaulted2.C new file mode 100644 index 00000000000..ea06d92530f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/defaulted2.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" } +} + diff --git a/gcc/testsuite/g++.dg/parse/crash27.C b/gcc/testsuite/g++.dg/parse/crash27.C index 069436666d3..217928781d3 100644 --- a/gcc/testsuite/g++.dg/parse/crash27.C +++ b/gcc/testsuite/g++.dg/parse/crash27.C @@ -1,5 +1,4 @@ // Bug: 23225 void Dispatcher() - (__builtin_offsetof (ArgsType, largeMsgLen)) - /* { dg-error "function " "function" { target *-*-* } 4 } */ + (__builtin_offsetof (ArgsType, largeMsgLen)) // { dg-error "initialize|end of input" } diff --git a/gcc/testsuite/g++.dg/parse/error15.C b/gcc/testsuite/g++.dg/parse/error15.C index 5903a585e97..5d30b554369 100644 --- a/gcc/testsuite/g++.dg/parse/error15.C +++ b/gcc/testsuite/g++.dg/parse/error15.C @@ -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" } }; -// { 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 } diff --git a/gcc/testsuite/g++.dg/template/crash60.C b/gcc/testsuite/g++.dg/template/crash60.C index 9e1d88b2432..c579775917e 100644 --- a/gcc/testsuite/g++.dg/template/crash60.C +++ b/gcc/testsuite/g++.dg/template/crash60.C @@ -5,5 +5,5 @@ struct A template void foo(X); // { dg-error "declared" } }; -template void f()(0); // { dg-error "initialized" } +template void f()(0); // { dg-error "initialize" } diff --git a/gcc/testsuite/g++.dg/template/crash7.C b/gcc/testsuite/g++.dg/template/crash7.C index 5b17928f5bb..ae07d91e739 100644 --- a/gcc/testsuite/g++.dg/template/crash7.C +++ b/gcc/testsuite/g++.dg/template/crash7.C @@ -6,8 +6,10 @@ // nested type. template struct A -{ // { dg-error "candidates" } +{ // { not-dg-error "candidates" } template A(typename A::X) {} // { dg-error "no type" } }; -A a; // { dg-error "instantiated|no match" } +A 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. diff --git a/gcc/testsuite/g++.old-deja/g++.pt/error2.C b/gcc/testsuite/g++.old-deja/g++.pt/error2.C index 2f777afdc70..40f7a7cb67f 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/error2.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/error2.C @@ -2,7 +2,7 @@ // Origin: Carl Nygard template -class Test { // { dg-error "" } in instantiation +class Test { public: Test(const RT& c = RT()) {} // { dg-error "" } reference to void };