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
This commit is contained in:
Jason Merrill 2009-10-26 15:07:14 -04:00 committed by Jason Merrill
parent f96d6fd02e
commit 20f2653ef0
21 changed files with 239 additions and 66 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,12 @@
2009-10-26 Jason Merrill <jason@redhat.com>
Core issue 906
* 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.
009-10-20 Paolo Carlini <paolo.carlini@oracle.com>
PR libstdc++/41773

View File

@ -130,9 +130,11 @@ namespace std
};
protected:
~_Future_result_base() = default;
~_Future_result_base();
};
inline _Future_result_base::~_Future_result_base() = default;
// TODO: use template alias when available
/*
template<typename _Res>

View File

@ -64,7 +64,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
class error_category
{
protected:
error_category() = default;
error_category();
public:
virtual ~error_category() { }
@ -100,6 +100,8 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
{ return this != &__other; }
};
inline error_category::error_category() = default;
// DR 890.
_GLIBCXX_CONST const error_category& system_category() throw ();
_GLIBCXX_CONST const error_category& generic_category() throw ();

View File

@ -57,9 +57,9 @@ namespace std
public:
nested_exception() throw() : _M_ptr(current_exception()) { }
nested_exception(const nested_exception&) throw() = default;
nested_exception(const nested_exception&) = default;
nested_exception& operator=(const nested_exception&) throw() = default;
nested_exception& operator=(const nested_exception&) = default;
virtual ~nested_exception() = default;

View File

@ -33,4 +33,4 @@ void test01()
}
// { dg-error "used here" "" { target *-*-* } 32 }
// { dg-error "deleted function" "" { target *-*-* } 862 }
// { dg-error "deleted function" "" { target *-*-* } 864 }

View File

@ -32,4 +32,4 @@ void test01()
}
// { dg-error "used here" "" { target *-*-* } 31 }
// { dg-error "deleted function" "" { target *-*-* } 861 }
// { dg-error "deleted function" "" { target *-*-* } 863 }

View File

@ -33,4 +33,4 @@ void test01()
}
// { dg-error "used here" "" { target *-*-* } 32 }
// { dg-error "deleted function" "" { target *-*-* } 588 }
// { dg-error "deleted function" "" { target *-*-* } 590 }

View File

@ -32,4 +32,4 @@ void test01()
}
// { dg-error "used here" "" { target *-*-* } 31 }
// { dg-error "deleted function" "" { target *-*-* } 572 }
// { dg-error "deleted function" "" { target *-*-* } 574 }

View File

@ -35,4 +35,4 @@ void test01()
}
// { dg-error "used here" "" { target *-*-* } 34 }
// { dg-error "deleted function" "" { target *-*-* } 481 }
// { dg-error "deleted function" "" { target *-*-* } 483 }

View File

@ -35,4 +35,4 @@ void test01()
}
// { dg-error "used here" "" { target *-*-* } 34 }
// { dg-error "deleted function" "" { target *-*-* } 401 }
// { dg-error "deleted function" "" { target *-*-* } 403 }

View File

@ -34,4 +34,4 @@ void test01()
}
// { dg-error "used here" "" { target *-*-* } 33 }
// { dg-error "deleted function" "" { target *-*-* } 400 }
// { dg-error "deleted function" "" { target *-*-* } 402 }