+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
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;
}
}
}
/* 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. */
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
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. */
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
#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)
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);
}
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;
}
}
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
/* 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)
{
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;
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))
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;
}
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;
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. */
= 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);
+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
--- /dev/null
+// 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" }
+};
--- /dev/null
+// 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;
+
+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
};
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>
class error_category
{
protected:
- error_category() = default;
+ error_category();
public:
virtual ~error_category() { }
{ 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 ();
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;
}
// { dg-error "used here" "" { target *-*-* } 32 }
-// { dg-error "deleted function" "" { target *-*-* } 862 }
+// { dg-error "deleted function" "" { target *-*-* } 864 }
}
// { dg-error "used here" "" { target *-*-* } 31 }
-// { dg-error "deleted function" "" { target *-*-* } 861 }
+// { dg-error "deleted function" "" { target *-*-* } 863 }
}
// { dg-error "used here" "" { target *-*-* } 32 }
-// { dg-error "deleted function" "" { target *-*-* } 588 }
+// { dg-error "deleted function" "" { target *-*-* } 590 }
}
// { dg-error "used here" "" { target *-*-* } 31 }
-// { dg-error "deleted function" "" { target *-*-* } 572 }
+// { dg-error "deleted function" "" { target *-*-* } 574 }
}
// { dg-error "used here" "" { target *-*-* } 34 }
-// { dg-error "deleted function" "" { target *-*-* } 481 }
+// { dg-error "deleted function" "" { target *-*-* } 483 }
}
// { dg-error "used here" "" { target *-*-* } 34 }
-// { dg-error "deleted function" "" { target *-*-* } 401 }
+// { dg-error "deleted function" "" { target *-*-* } 403 }
}
// { dg-error "used here" "" { target *-*-* } 33 }
-// { dg-error "deleted function" "" { target *-*-* } 400 }
+// { dg-error "deleted function" "" { target *-*-* } 402 }