diff options
author | Jason Merrill <jason@redhat.com> | 2009-10-26 15:07:14 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2009-10-26 15:07:14 -0400 |
commit | 20f2653ef0f7f2d33ec3e5ce389ab72d4216ec2a (patch) | |
tree | 3a188f1a76fba7e0480a3fadf8f3fd90b1751852 /gcc | |
parent | f96d6fd02e10a4f266c5c459461562887cbf0c6a (diff) | |
download | gcc-20f2653ef0f7f2d33ec3e5ce389ab72d4216ec2a.zip gcc-20f2653ef0f7f2d33ec3e5ce389ab72d4216ec2a.tar.gz gcc-20f2653ef0f7f2d33ec3e5ce389ab72d4216ec2a.tar.bz2 |
PR c++/38796, Core issue 906
PR c++/38796, Core issue 906
gcc/cp
* cp-tree.h (DECL_DEFAULTED_OUTSIDE_CLASS_P): New.
(DECL_DEFAULTED_IN_CLASS_P): New.
* class.c (user_provided_p): Non-static.
(check_methods): Use it.
(check_bases_and_members): Check defaulted fns.
(defaultable_fn_p): Move and rename to...
* method.c (defaultable_fn_check): ...this.
(defaulted_late_check): New.
* pt.c (tsubst_decl): Call it.
* decl2.c (grokfield): Adjust.
* decl.c (cp_finish_decl): Adjust.
(grok_special_member_properties): Use user_provided_p.
libstdc++-v3
* include/std/future (~Future_result_base): Default outside class
body.
* include/std/system_error (error_category()): Likewise.
* libsupc++/nested_exception.h (nested_exception): Remove
exception specifications from defaulted methods.
From-SVN: r153565
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/cp/class.c | 61 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 14 | ||||
-rw-r--r-- | gcc/cp/decl.c | 28 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 4 | ||||
-rw-r--r-- | gcc/cp/method.c | 82 | ||||
-rw-r--r-- | gcc/cp/pt.c | 3 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/defaulted15.C | 43 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/defaulted16.C | 13 |
10 files changed, 215 insertions, 55 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2f7ec52..50212a9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2009-10-26 Jason Merrill <jason@redhat.com> + + PR c++/38796, Core issue 906 + * cp-tree.h (DECL_DEFAULTED_OUTSIDE_CLASS_P): New. + (DECL_DEFAULTED_IN_CLASS_P): New. + * class.c (user_provided_p): Non-static. + (check_methods): Use it. + (check_bases_and_members): Check defaulted fns. + (defaultable_fn_p): Move and rename to... + * method.c (defaultable_fn_check): ...this. + (defaulted_late_check): New. + * pt.c (tsubst_decl): Call it. + * decl2.c (grokfield): Adjust. + * decl.c (cp_finish_decl): Adjust. + (grok_special_member_properties): Use user_provided_p. + 2009-10-26 Dodji Seketeli <dodji@redhat.com> PR c++/41785 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index d29d661..d737bdf 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3843,7 +3843,7 @@ check_methods (tree t) 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)) + if (DECL_DESTRUCTOR_P (x) && user_provided_p (x)) TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1; } } @@ -4174,17 +4174,17 @@ type_has_user_nondefault_constructor (tree t) } /* Returns true iff FN is a user-provided function, i.e. user-declared - and not defaulted at its first declaration. */ + and not defaulted at its first declaration; or explicit, private, + protected, or non-const. */ -static bool +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))); + && !DECL_DEFAULTED_IN_CLASS_P (fn)); } /* Returns true iff class T has a user-provided constructor. */ @@ -4238,31 +4238,6 @@ type_has_user_provided_default_constructor (tree t) return false; } -/* Returns true if FN can be explicitly defaulted. */ - -bool -defaultable_fn_p (tree fn) -{ - if (DECL_CONSTRUCTOR_P (fn)) - { - if (FUNCTION_FIRST_USER_PARMTYPE (fn) == void_list_node) - return true; - else if (copy_fn_p (fn) > 0 - && (TREE_CHAIN (FUNCTION_FIRST_USER_PARMTYPE (fn)) - == void_list_node)) - return true; - else - return false; - } - else if (DECL_DESTRUCTOR_P (fn)) - return true; - else if (DECL_ASSIGNMENT_OPERATOR_P (fn) - && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR) - return copy_fn_p (fn); - else - return false; -} - /* Remove all zero-width bit-fields from T. */ static void @@ -4356,6 +4331,7 @@ check_bases_and_members (tree t) tree access_decls; bool saved_complex_asn_ref; bool saved_nontrivial_dtor; + tree fn; /* By default, we use const reference arguments and generate default constructors. */ @@ -4453,6 +4429,31 @@ check_bases_and_members (tree t) cant_have_const_ctor, no_const_asn_ref); + /* Check defaulted declarations here so we have cant_have_const_ctor + and don't need to worry about clones. */ + for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn)) + if (DECL_DEFAULTED_IN_CLASS_P (fn)) + { + int copy = copy_fn_p (fn); + if (copy > 0) + { + bool imp_const_p + = (DECL_CONSTRUCTOR_P (fn) ? !cant_have_const_ctor + : !no_const_asn_ref); + bool fn_const_p = (copy == 2); + + if (fn_const_p && !imp_const_p) + /* If the function is defaulted outside the class, we just + give the synthesis error. */ + error ("%q+D declared to take const reference, but implicit " + "declaration would take non-const", fn); + else if (imp_const_p && !fn_const_p) + error ("%q+D declared to take non-const reference cannot be " + "defaulted in the class body", fn); + } + defaulted_late_check (fn); + } + if (LAMBDA_TYPE_P (t)) { /* "The closure type associated with a lambda-expression has a deleted diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3d826b9..ea28e9f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2815,10 +2815,18 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define DECL_DELETED_FN(DECL) \ (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->u.base.threadprivate_or_deleted_p) -/* Nonzero if DECL was declared with '= default'. */ +/* Nonzero if DECL was declared with '= default' (maybe implicitly). */ #define DECL_DEFAULTED_FN(DECL) \ (LANG_DECL_FN_CHECK (DECL)->defaulted_p) +/* Nonzero if DECL is explicitly defaulted in the class body. */ +#define DECL_DEFAULTED_IN_CLASS_P(DECL) \ + (DECL_DEFAULTED_FN (DECL) && DECL_INITIALIZED_IN_CLASS_P (DECL)) +/* Nonzero if DECL was defaulted outside the class body. */ +#define DECL_DEFAULTED_OUTSIDE_CLASS_P(DECL) \ + (DECL_DEFAULTED_FN (DECL) \ + && !(DECL_ARTIFICIAL (DECL) || DECL_INITIALIZED_IN_CLASS_P (DECL))) + /* Record whether a typedef for type `int' was actually `signed int'. */ #define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP) @@ -4483,9 +4491,11 @@ 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 user_provided_p (tree); extern bool type_has_user_provided_constructor (tree); extern bool type_has_user_provided_default_constructor (tree); -extern bool defaultable_fn_p (tree); +extern void defaulted_late_check (tree); +extern bool defaultable_fn_check (tree); extern void fixup_type_variants (tree); extern tree* decl_cloned_function_p (const_tree, bool); extern void clone_function_decl (tree, int); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c772ca5..ead3f33 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5603,17 +5603,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, } else if (init == ridpointers[(int)RID_DEFAULT]) { - if (!defaultable_fn_p (decl)) - { - error ("%qD cannot be defaulted", decl); - DECL_INITIAL (decl) = NULL_TREE; - } + if (defaultable_fn_check (decl)) + DECL_DEFAULTED_FN (decl) = 1; else - { - DECL_DEFAULTED_FN (decl) = 1; - FOR_EACH_CLONE (clone, decl) - DECL_DEFAULTED_FN (clone) = 1; - } + DECL_INITIAL (decl) = NULL_TREE; } } @@ -9866,9 +9859,9 @@ grokparms (tree parmlist, tree *parms) 0 if D is not a copy constructor or copy assignment operator. 1 if D is a copy constructor or copy assignment operator whose - first parameter is a reference to const qualified T. - 2 if D is a copy constructor or copy assignment operator whose first parameter is a reference to non-const qualified T. + 2 if D is a copy constructor or copy assignment operator whose + first parameter is a reference to const qualified T. This function can be used as a predicate. Positive values indicate a copy constructor and nonzero values indicate a copy assignment @@ -9977,10 +9970,6 @@ move_fn_p (const_tree d) /* Remember any special properties of member function DECL. */ -#define DECL_DEFAULTED_IN_CLASS_P(DECL) \ - (DECL_DEFAULTED_FN (DECL) \ - && (DECL_ARTIFICIAL (DECL) || DECL_INITIALIZED_IN_CLASS_P (DECL))) - void grok_special_member_properties (tree decl) { @@ -10007,7 +9996,7 @@ 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_IN_CLASS_P (decl)) + if (user_provided_p (decl)) TYPE_HAS_COMPLEX_INIT_REF (class_type) = 1; if (ctor > 1) TYPE_HAS_CONST_INIT_REF (class_type) = 1; @@ -10015,8 +10004,7 @@ grok_special_member_properties (tree decl) else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl))) { TYPE_HAS_DEFAULT_CONSTRUCTOR (class_type) = 1; - if (TREE_CODE (decl) == TEMPLATE_DECL - || !DECL_DEFAULTED_IN_CLASS_P (decl)) + if (user_provided_p (decl)) TYPE_HAS_COMPLEX_DFLT (class_type) = 1; } else if (is_list_ctor (decl)) @@ -10035,7 +10023,7 @@ grok_special_member_properties (tree decl) if (assop) { TYPE_HAS_ASSIGN_REF (class_type) = 1; - if (!DECL_DEFAULTED_IN_CLASS_P (decl)) + if (user_provided_p (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 3e8c0d7..592ee08 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -862,9 +862,7 @@ grokfield (const cp_declarator *declarator, } else if (init == ridpointers[(int)RID_DEFAULT]) { - if (!defaultable_fn_p (value)) - error ("%qD cannot be defaulted", value); - else + if (defaultable_fn_check (value)) { DECL_DEFAULTED_FN (value) = 1; DECL_INITIALIZED_IN_CLASS_P (value) = 1; diff --git a/gcc/cp/method.c b/gcc/cp/method.c index e8b28d8..266406c 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1130,6 +1130,88 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) return fn; } +/* Gives any errors about defaulted functions which need to be deferred + until the containing class is complete. */ + +void +defaulted_late_check (tree fn) +{ + /* Complain about invalid signature for defaulted fn. */ + tree ctx = DECL_CONTEXT (fn); + special_function_kind kind = special_function_p (fn); + bool fn_const_p = (copy_fn_p (fn) == 2); + tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p); + + if (!same_type_p (TREE_TYPE (TREE_TYPE (fn)), + TREE_TYPE (TREE_TYPE (implicit_fn))) + || !compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)), + TYPE_ARG_TYPES (TREE_TYPE (implicit_fn)))) + { + error ("defaulted declaration %q+D", fn); + error_at (DECL_SOURCE_LOCATION (fn), + "does not match expected signature %qD", implicit_fn); + } +} + +/* Returns true iff FN can be explicitly defaulted, and gives any + errors if defaulting FN is ill-formed. */ + +bool +defaultable_fn_check (tree fn) +{ + special_function_kind kind = sfk_none; + + if (DECL_CONSTRUCTOR_P (fn)) + { + if (FUNCTION_FIRST_USER_PARMTYPE (fn) == void_list_node) + kind = sfk_constructor; + else if (copy_fn_p (fn) > 0 + && (TREE_CHAIN (FUNCTION_FIRST_USER_PARMTYPE (fn)) + == void_list_node)) + kind = sfk_copy_constructor; + else if (move_fn_p (fn)) + kind = sfk_move_constructor; + } + else if (DECL_DESTRUCTOR_P (fn)) + kind = sfk_destructor; + else if (DECL_ASSIGNMENT_OPERATOR_P (fn) + && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR + && copy_fn_p (fn)) + kind = sfk_assignment_operator; + + if (kind == sfk_none) + { + error ("%qD cannot be defaulted", fn); + return false; + } + else + { + tree t = FUNCTION_FIRST_USER_PARMTYPE (fn); + for (; t && t != void_list_node; t = TREE_CHAIN (t)) + if (TREE_PURPOSE (t)) + { + error ("defaulted function %q+D with default argument", fn); + break; + } + if (TYPE_BEING_DEFINED (DECL_CONTEXT (fn))) + { + if (DECL_NONCONVERTING_P (fn)) + error ("%qD declared explicit cannot be defaulted in the class " + "body", fn); + if (current_access_specifier != access_public_node) + error ("%qD declared with non-public access cannot be defaulted " + "in the class body", fn); + if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))) + error ("function %q+D defaulted on its first declaration " + "must not have an exception-specification", fn); + } + else if (!processing_template_decl) + defaulted_late_check (fn); + + return true; + } +} + /* Add an implicit declaration to TYPE for the kind of function indicated by SFK. Return the FUNCTION_DECL for the new implicit declaration. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index e80bc30..f480682 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8848,6 +8848,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) = remove_attribute ("visibility", DECL_ATTRIBUTES (r)); } determine_visibility (r); + if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r) + && !processing_template_decl) + defaulted_late_check (r); apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0, args, complain, in_decl); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cc89a76..0556d76 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2009-10-26 Jason Merrill <jason@redhat.com> + + PR c++/38796 + * g++.dg/cpp0x/defaulted15.C: New. + * g++.dg/cpp0x/defaulted16.C: New. + 2009-10-26 Dodji Seketeli <dodji@redhat.com> PR c++/41785 diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted15.C b/gcc/testsuite/g++.dg/cpp0x/defaulted15.C new file mode 100644 index 0000000..092b560 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/defaulted15.C @@ -0,0 +1,43 @@ +// PR c++/38796 +// { dg-options -std=c++0x } + +struct A +{ + A (int); + A (const A& = 1) = default; // { dg-error "default argument" } + void operator= (const A&) = default; // { dg-error "defaulted|match" } +}; + +struct B +{ +private: + B() = default; // { dg-error "access" } +}; + +struct C +{ +protected: + ~C() = default; // { dg-error "access" } +}; + +struct D +{ +private: + D& operator= (const D&) = default; // { dg-error "access" } +}; + +struct E +{ + explicit E (const E&) = default; // { dg-error "explicit" } +}; + +struct F +{ + F(F&) = default; // { dg-error "non-const" } +}; + +struct G: public F +{ + // Can't be const because F copy ctor isn't. + G(const G&) = default; // { dg-error "const" } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted16.C b/gcc/testsuite/g++.dg/cpp0x/defaulted16.C new file mode 100644 index 0000000..741b43d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/defaulted16.C @@ -0,0 +1,13 @@ +// Test that non-inline default causes the function to be defined even if +// it isn't used. + +// { dg-options -std=c++0x } +// { dg-final { scan-assembler "_ZN1AC1Ev" } } + +struct A +{ + A(); +}; + +A::A() = default; + |