/* Handle the hair of processing (but not expanding) inline functions.
Also manage function and variable name overloading.
Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
#include "toplev.h"
#include "tm_p.h"
#include "target.h"
+#include "common/common-target.h"
#include "tree-pass.h"
#include "diagnostic.h"
#include "cgraph.h"
THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset;
THUNK_ALIAS (thunk) = NULL_TREE;
- /* The thunk itself is not a constructor or destructor, even if
- the thing it is thunking to is. */
DECL_INTERFACE_KNOWN (thunk) = 1;
DECL_NOT_REALLY_EXTERN (thunk) = 1;
+ DECL_COMDAT (thunk) = DECL_COMDAT (function);
DECL_SAVED_FUNCTION_DATA (thunk) = NULL;
+ /* The thunk itself is not a constructor or destructor, even if
+ the thing it is thunking to is. */
DECL_DESTRUCTOR_P (thunk) = 0;
DECL_CONSTRUCTOR_P (thunk) = 0;
DECL_EXTERNAL (thunk) = 1;
if (!flag_syntax_only)
{
- struct cgraph_node *aliasn = cgraph_same_body_alias (alias, function);
+ struct cgraph_node *funcn, *aliasn;
+ funcn = cgraph_get_node (function);
+ gcc_checking_assert (funcn);
+ aliasn = cgraph_same_body_alias (funcn, alias, function);
DECL_ASSEMBLER_NAME (function);
gcc_assert (aliasn != NULL);
}
tree virtual_offset;
HOST_WIDE_INT fixed_offset, virtual_value;
bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl);
+ struct cgraph_node *funcn, *thunk_node;
/* We should have called finish_thunk to give it a name. */
gcc_assert (DECL_NAME (thunk_fndecl));
DECL_EXTERNAL (thunk_fndecl) = 0;
/* The linkage of the function may have changed. FIXME in linkage
rewrite. */
+ gcc_assert (DECL_INTERFACE_KNOWN (function));
TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
= DECL_VISIBILITY_SPECIFIED (function);
- if (DECL_ONE_ONLY (function) || DECL_WEAK (function))
- make_decl_one_only (thunk_fndecl, cxx_comdat_group (thunk_fndecl));
+ DECL_COMDAT (thunk_fndecl) = DECL_COMDAT (function);
+ DECL_WEAK (thunk_fndecl) = DECL_WEAK (function);
if (flag_syntax_only)
{
push_to_top_level ();
if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)
- && targetm.have_named_sections)
+ && targetm_common.have_named_sections)
{
resolve_unique_section (function, 0, flag_function_sections);
DECL_CONTEXT (x) = thunk_fndecl;
SET_DECL_RTL (x, NULL);
DECL_HAS_VALUE_EXPR_P (x) = 0;
+ TREE_ADDRESSABLE (x) = 0;
t = x;
}
a = nreverse (t);
DECL_ARGUMENTS (thunk_fndecl) = a;
TREE_ASM_WRITTEN (thunk_fndecl) = 1;
- cgraph_add_thunk (thunk_fndecl, function,
- this_adjusting, fixed_offset, virtual_value,
- virtual_offset, alias);
+ funcn = cgraph_get_node (function);
+ gcc_checking_assert (funcn);
+ thunk_node = cgraph_add_thunk (funcn, thunk_fndecl, function,
+ this_adjusting, fixed_offset, virtual_value,
+ virtual_offset, alias);
+ if (DECL_ONE_ONLY (function))
+ cgraph_add_to_same_comdat_group (thunk_node, funcn);
if (!this_adjusting
|| !targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0;
VEC_iterate (tree, vbases, i, binfo); i++)
{
- init = build_base_path (PLUS_EXPR, parm, binfo, 1);
+ init = build_base_path (PLUS_EXPR, parm, binfo, 1,
+ tf_warning_or_error);
if (move_p)
init = move (init);
member_init_list
if (BINFO_VIRTUAL_P (base_binfo))
continue;
- init = build_base_path (PLUS_EXPR, parm, base_binfo, 1);
+ init = build_base_path (PLUS_EXPR, parm, base_binfo, 1,
+ tf_warning_or_error);
if (move_p)
init = move (init);
member_init_list
tree compound_stmt;
bool move_p = move_fn_p (fndecl);
bool trivial = trivial_fn_p (fndecl);
+ int flags = LOOKUP_NORMAL | LOOKUP_NONVIRTUAL | LOOKUP_DEFAULTED;
compound_stmt = begin_compound_stmt (0);
parm = convert_from_reference (parm);
/* We must convert PARM directly to the base class
explicitly since the base class may be ambiguous. */
- converted_parm = build_base_path (PLUS_EXPR, parm, base_binfo, 1);
+ converted_parm = build_base_path (PLUS_EXPR, parm, base_binfo, 1,
+ tf_warning_or_error);
if (move_p)
converted_parm = move (converted_parm);
/* Call the base class assignment operator. */
ansi_assopname (NOP_EXPR),
&parmvec,
base_binfo,
- LOOKUP_NORMAL | LOOKUP_NONVIRTUAL,
+ flags,
tf_warning_or_error));
release_tree_vector (parmvec);
}
/* Locate the dtor of TYPE. */
tree
-get_dtor (tree type)
+get_dtor (tree type, tsubst_flags_t complain)
{
tree fn = locate_fn_flags (type, complete_dtor_identifier, NULL_TREE,
- LOOKUP_NORMAL, tf_warning_or_error);
+ LOOKUP_NORMAL, complain);
if (fn == error_mark_node)
return NULL_TREE;
return fn;
/* Locate the copy ctor of TYPE. */
tree
-get_copy_ctor (tree type)
+get_copy_ctor (tree type, tsubst_flags_t complain)
{
int quals = (TYPE_HAS_CONST_COPY_CTOR (type)
? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
tree argtype = build_stub_type (type, quals, false);
tree fn = locate_fn_flags (type, complete_ctor_identifier, argtype,
- LOOKUP_NORMAL, tf_warning_or_error);
+ LOOKUP_NORMAL, complain);
if (fn == error_mark_node)
return NULL_TREE;
return fn;
static void
process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
- bool *deleted_p, bool *constexpr_p,
+ bool *deleted_p, bool *constexpr_p, bool *no_implicit_p,
const char *msg, tree arg)
{
if (!fn || fn == error_mark_node)
if (spec_p)
{
tree raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
- *spec_p = merge_exception_specifiers (*spec_p, raises);
+ *spec_p = merge_exception_specifiers (*spec_p, raises, fn);
}
if (!trivial_fn_p (fn))
}
}
- if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
+ /* Core 1402: A non-trivial copy op suppresses the implicit
+ declaration of the move ctor/op=. */
+ if (no_implicit_p && move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
+ *no_implicit_p = true;
+
+ if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn))
{
+ *constexpr_p = false;
if (msg)
- error (msg, arg);
- goto bad;
+ {
+ inform (0, "defaulted constructor calls non-constexpr "
+ "%q+D", fn);
+ explain_invalid_constexpr_fn (fn);
+ }
}
- if (constexpr_p && !DECL_DECLARED_CONSTEXPR_P (fn))
- *constexpr_p = false;
-
return;
bad:
walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
int quals, bool copy_arg_p, bool move_p,
bool assign_p, tree *spec_p, bool *trivial_p,
- bool *deleted_p, bool *constexpr_p, const char *msg,
- int flags, tsubst_flags_t complain)
+ bool *deleted_p, bool *constexpr_p, bool *no_implicit_p,
+ const char *msg, int flags, tsubst_flags_t complain)
{
tree field;
for (field = fields; field; field = DECL_CHAIN (field))
}
else if (sfk == sfk_constructor)
{
- bool bad = true;
+ bool bad;
+
+ if (DECL_INITIAL (field))
+ {
+ if (msg && DECL_INITIAL (field) == error_mark_node)
+ inform (0, "initializer for %q+#D is invalid", field);
+ if (trivial_p)
+ *trivial_p = false;
+#if 0
+ /* Core 1351: If the field has an NSDMI that could throw, the
+ default constructor is noexcept(false). FIXME this is
+ broken by deferred parsing and 1360 saying we can't lazily
+ declare a non-trivial default constructor. Also this
+ needs to do deferred instantiation. Disable until the
+ conflict between 1351 and 1360 is resolved. */
+ if (spec_p && !expr_noexcept_p (DECL_INITIAL (field), complain))
+ *spec_p = noexcept_false_spec;
+#endif
+
+ /* Don't do the normal processing. */
+ continue;
+ }
+
+ bad = false;
if (CP_TYPE_CONST_P (mem_type)
- && (!CLASS_TYPE_P (mem_type)
- || !type_has_user_provided_default_constructor (mem_type)))
+ && default_init_uninitialized_part (mem_type))
{
if (msg)
error ("uninitialized non-static const member %q#D",
field);
+ bad = true;
}
else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
{
if (msg)
error ("uninitialized non-static reference member %q#D",
field);
+ bad = true;
}
- else
- bad = false;
if (bad && deleted_p)
*deleted_p = true;
/* For an implicitly-defined default constructor to be constexpr,
- every member must have a user-provided default constructor. */
- /* FIXME will need adjustment for non-static data member
- initializers. */
- if (constexpr_p && !CLASS_TYPE_P (mem_type))
- *constexpr_p = false;
+ every member must have a user-provided default constructor or
+ an explicit initializer. */
+ if (constexpr_p && !CLASS_TYPE_P (mem_type)
+ && TREE_CODE (DECL_CONTEXT (field)) != UNION_TYPE)
+ {
+ *constexpr_p = false;
+ if (msg)
+ inform (0, "defaulted default constructor does not "
+ "initialize %q+#D", field);
+ }
}
if (!CLASS_TYPE_P (mem_type))
{
walk_field_subobs (TYPE_FIELDS (mem_type), fnname, sfk, quals,
copy_arg_p, move_p, assign_p, spec_p, trivial_p,
- deleted_p, constexpr_p, msg, flags, complain);
+ deleted_p, constexpr_p, no_implicit_p,
+ msg, flags, complain);
continue;
}
rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
- constexpr_p, msg, field);
+ constexpr_p, no_implicit_p, msg, field);
}
}
/* The caller wants to generate an implicit declaration of SFK for CTYPE
which is const if relevant and CONST_P is set. If spec_p, trivial_p and
deleted_p are non-null, set their referent appropriately. If diag is
- true, we're being called from maybe_explain_implicit_delete to give
- errors. */
+ true, we're either being called from maybe_explain_implicit_delete to
+ give errors, or if constexpr_p is non-null, from
+ explain_invalid_constexpr_fn. */
static void
synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
tree *spec_p, bool *trivial_p, bool *deleted_p,
- bool *constexpr_p, bool diag)
+ bool *constexpr_p, bool *no_implicit_p, bool diag)
{
tree binfo, base_binfo, scope, fnname, rval, argtype;
bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
tsubst_flags_t complain;
const char *msg;
bool ctor_p;
- tree cleanup_spec;
- bool cleanup_trivial = true;
- bool cleanup_deleted = false;
- cleanup_spec
- = (cxx_dialect >= cxx0x ? noexcept_true_spec : empty_except_spec);
if (spec_p)
- *spec_p = cleanup_spec;
+ *spec_p = (cxx_dialect >= cxx0x ? noexcept_true_spec : empty_except_spec);
+
+ if (no_implicit_p)
+ *no_implicit_p = false;
if (deleted_p)
{
if (trivial_p)
*trivial_p = expected_trivial;
-#ifndef ENABLE_CHECKING
/* The TYPE_HAS_COMPLEX_* flags tell us about constraints from base
class versions and other properties of the type. But a subobject
class can be trivially copyable and yet have overload resolution
choose a template constructor for initialization, depending on
rvalueness and cv-quals. So we can't exit early for copy/move
- methods in C++0x. */
+ methods in C++0x. The same considerations apply in C++98/03, but
+ there the definition of triviality does not consider overload
+ resolution, so a constructor can be trivial even if it would otherwise
+ call a non-trivial constructor. */
if (expected_trivial
&& (!copy_arg_p || cxx_dialect < cxx0x))
{
if (constexpr_p && sfk == sfk_constructor)
- *constexpr_p = synthesized_default_constructor_is_constexpr (ctype);
- return;
+ {
+ bool cx = trivial_default_constructor_is_constexpr (ctype);
+ *constexpr_p = cx;
+ if (diag && !cx && TREE_CODE (ctype) == UNION_TYPE)
+ /* A trivial constructor doesn't have any NSDMI. */
+ inform (input_location, "defaulted default constructor does "
+ "not initialize any non-static data member");
+ }
+ if (!diag)
+ return;
}
-#endif
++cp_unevaluated_operand;
++c_inhibit_evaluation_warnings;
if (diag)
{
- flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE;
+ flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
complain = tf_warning_or_error;
}
else
{
- flags = LOOKUP_PROTECT|LOOKUP_SPECULATIVE;
+ flags = LOOKUP_PROTECT|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
complain = tf_none;
}
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
- constexpr_p, msg, basetype);
+ constexpr_p, no_implicit_p, msg, basetype);
if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype))
{
/* In a constructor we also need to check the subobject
destructors for cleanup of partially constructed objects. */
rval = locate_fn_flags (base_binfo, complete_dtor_identifier,
NULL_TREE, flags, complain);
- process_subob_fn (rval, false, &cleanup_spec, &cleanup_trivial,
- &cleanup_deleted, NULL, NULL,
+ /* Note that we don't pass down trivial_p; the subobject
+ destructors don't affect triviality of the constructor. Nor
+ do they affect constexpr-ness (a constant expression doesn't
+ throw) or exception-specification (a throw from one of the
+ dtors would be a double-fault). */
+ process_subob_fn (rval, false, NULL, NULL,
+ deleted_p, NULL, NULL, NULL,
basetype);
}
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
- constexpr_p, msg, basetype);
+ constexpr_p, no_implicit_p, msg, basetype);
if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype))
{
rval = locate_fn_flags (base_binfo, complete_dtor_identifier,
NULL_TREE, flags, complain);
- process_subob_fn (rval, false, &cleanup_spec, &cleanup_trivial,
- &cleanup_deleted, NULL, NULL,
+ process_subob_fn (rval, false, NULL, NULL,
+ deleted_p, NULL, NULL, NULL,
basetype);
}
}
"constructor or trivial copy constructor");
walk_field_subobs (TYPE_FIELDS (ctype), fnname, sfk, quals,
copy_arg_p, move_p, assign_p, spec_p, trivial_p,
- deleted_p, constexpr_p, msg, flags, complain);
+ deleted_p, constexpr_p, no_implicit_p,
+ msg, flags, complain);
if (ctor_p)
walk_field_subobs (TYPE_FIELDS (ctype), complete_dtor_identifier,
sfk_destructor, TYPE_UNQUALIFIED, false,
- false, false, &cleanup_spec, &cleanup_trivial,
- &cleanup_deleted, NULL,
- NULL, flags, complain);
+ false, false, NULL, NULL,
+ deleted_p, NULL,
+ NULL, NULL, flags, complain);
pop_scope (scope);
--cp_unevaluated_operand;
--c_inhibit_evaluation_warnings;
-
- /* If the constructor isn't trivial, consider the subobject cleanups. */
- if (ctor_p && trivial_p && !*trivial_p)
- {
- if (deleted_p && cleanup_deleted)
- *deleted_p = true;
- if (spec_p)
- *spec_p = merge_exception_specifiers (*spec_p, cleanup_spec);
- }
-
-#ifdef ENABLE_CHECKING
- /* If we expected this to be trivial but it isn't, then either we're in
- C++0x mode and this is a copy/move ctor/op= or there's an error. */
- gcc_assert (!(trivial_p && expected_trivial && !*trivial_p)
- || (copy_arg_p && cxx_dialect >= cxx0x)
- || errorcount);
-#endif
}
/* DECL is a deleted function. If it's implicitly deleted, explain why and
/* If decl is a clone, get the primary variant. */
decl = DECL_ORIGIN (decl);
gcc_assert (DECL_DELETED_FN (decl));
- if (DECL_DEFAULTED_FN (decl)
- && DECL_INITIAL (decl) == NULL_TREE)
+ if (DECL_DEFAULTED_FN (decl))
{
/* Not marked GTY; it doesn't need to be GC'd or written to PCH. */
- static htab_t explained_htab;
- void **slot;
+ static struct pointer_set_t *explained;
special_function_kind sfk;
location_t loc;
bool informed;
tree ctype;
- if (!explained_htab)
- explained_htab = htab_create (37, htab_hash_pointer,
- htab_eq_pointer, NULL);
- slot = htab_find_slot (explained_htab, decl, INSERT);
- if (*slot)
+ if (!explained)
+ explained = pointer_set_create ();
+ if (pointer_set_insert (explained, decl))
return true;
- *slot = decl;
sfk = special_function_p (decl);
ctype = DECL_CONTEXT (decl);
{
informed = true;
if (sfk == sfk_constructor)
- error ("a lambda closure type has a deleted default constructor");
+ inform (DECL_SOURCE_LOCATION (decl),
+ "a lambda closure type has a deleted default constructor");
else if (sfk == sfk_copy_assignment)
- error ("a lambda closure type has a deleted copy assignment operator");
+ inform (DECL_SOURCE_LOCATION (decl),
+ "a lambda closure type has a deleted copy assignment operator");
else
informed = false;
}
+ else if (DECL_ARTIFICIAL (decl)
+ && (sfk == sfk_copy_assignment
+ || sfk == sfk_copy_constructor)
+ && (type_has_user_declared_move_constructor (ctype)
+ || type_has_user_declared_move_assign (ctype)))
+ {
+ inform (0, "%q+#D is implicitly declared as deleted because %qT "
+ "declares a move constructor or move assignment operator",
+ decl, ctype);
+ informed = true;
+ }
if (!informed)
{
tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl));
bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
tree scope = push_scope (ctype);
- error ("%qD is implicitly deleted because the default "
+ inform (0, "%q+#D is implicitly deleted because the default "
"definition would be ill-formed:", decl);
pop_scope (scope);
synthesized_method_walk (ctype, sfk, const_p,
- NULL, NULL, NULL, NULL, true);
+ NULL, NULL, NULL, NULL, NULL, true);
}
input_location = loc;
return false;
}
+/* DECL is a defaulted function which was declared constexpr. Explain why
+ it can't be constexpr. */
+
+void
+explain_implicit_non_constexpr (tree decl)
+{
+ tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl));
+ bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
+ bool dummy;
+ synthesized_method_walk (DECL_CLASS_CONTEXT (decl),
+ special_function_p (decl), const_p,
+ NULL, NULL, NULL, &dummy, NULL, true);
+}
+
/* Implicitly declare the special function indicated by KIND, as a
member of TYPE. For copy constructors and assignment operators,
CONST_P indicates whether these functions should take a const
bool deleted_p;
bool trivial_p;
bool constexpr_p;
+ bool no_implicit_p;
/* Because we create declarations for implicitly declared functions
lazily, we may be creating the declaration for a member of TYPE
}
synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
- &deleted_p, &constexpr_p, false);
+ &deleted_p, &constexpr_p, &no_implicit_p, false);
/* Don't bother marking a deleted constructor as constexpr. */
if (deleted_p)
constexpr_p = false;
/* Note that this parameter is *not* marked DECL_ARTIFICIAL; we
want its type to be included in the mangled function
name. */
- DECL_ARGUMENTS (fn) = cp_build_parm_decl (NULL_TREE, rhs_parm_type);
- TREE_READONLY (DECL_ARGUMENTS (fn)) = 1;
+ tree decl = cp_build_parm_decl (NULL_TREE, rhs_parm_type);
+ TREE_READONLY (decl) = 1;
+ retrofit_lang_decl (decl);
+ DECL_PARM_INDEX (decl) = DECL_PARM_LEVEL (decl) = 1;
+ DECL_ARGUMENTS (fn) = decl;
}
/* Add the "this" parameter. */
this_parm = build_this_parm (fn_type, TYPE_UNQUALIFIED);
DECL_DELETED_FN (fn) = deleted_p;
DECL_DECLARED_CONSTEXPR_P (fn) = constexpr_p;
}
+ FNDECL_SUPPRESS_IMPLICIT_DECL (fn) = no_implicit_p;
+ DECL_EXTERNAL (fn) = true;
DECL_NOT_REALLY_EXTERN (fn) = 1;
DECL_DECLARED_INLINE_P (fn) = 1;
gcc_assert (!TREE_USED (fn));
if (DECL_DEFAULTED_IN_CLASS_P (fn))
{
tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
+ if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
+ {
+ maybe_instantiate_noexcept (fn);
+ if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)),
+ eh_spec, ce_normal))
+ error ("function %q+D defaulted on its first declaration "
+ "with an exception-specification that differs from "
+ "the implicit declaration %q#D", fn, implicit_fn);
+ }
TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
if (DECL_DECLARED_CONSTEXPR_P (implicit_fn))
- /* Hmm...should we do this for out-of-class too? Should it be OK to
- add constexpr later like inline, rather than requiring
- declarations to match? */
- DECL_DECLARED_CONSTEXPR_P (fn) = true;
+ {
+ /* Hmm...should we do this for out-of-class too? Should it be OK to
+ add constexpr later like inline, rather than requiring
+ declarations to match? */
+ DECL_DECLARED_CONSTEXPR_P (fn) = true;
+ if (kind == sfk_constructor)
+ TYPE_HAS_CONSTEXPR_CTOR (ctx) = true;
+ }
}
if (!DECL_DECLARED_CONSTEXPR_P (implicit_fn)
&& DECL_DECLARED_CONSTEXPR_P (fn))
{
if (!CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
- error ("%qD cannot be declared as constexpr", fn);
+ {
+ error ("explicitly defaulted function %q+D cannot be declared "
+ "as constexpr because the implicit declaration is not "
+ "constexpr:", fn);
+ explain_implicit_non_constexpr (fn);
+ }
DECL_DECLARED_CONSTEXPR_P (fn) = false;
}
{
special_function_kind kind = sfk_none;
+ if (template_parm_scope_p ())
+ {
+ error ("a template cannot be defaulted");
+ return false;
+ }
+
if (DECL_CONSTRUCTOR_P (fn))
{
if (FUNCTION_FIRST_USER_PARMTYPE (fn) == void_list_node)
break;
}
if (TYPE_BEING_DEFINED (DECL_CONTEXT (fn)))
- {
- if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
- error ("function %q+D defaulted on its first declaration "
- "must not have an exception-specification", fn);
- if (DECL_VIRTUAL_P (fn))
- error ("%qD declared virtual cannot be defaulted in the class "
- "body", fn);
- }
+ /* Defer checking. */;
else if (!processing_template_decl)
defaulted_late_check (fn);
/* Declare the function. */
fn = implicitly_declare_fn (sfk, type, const_p);
+ /* [class.copy]/8 If the class definition declares a move constructor or
+ move assignment operator, the implicitly declared copy constructor is
+ defined as deleted.... */
+ if ((sfk == sfk_copy_assignment
+ || sfk == sfk_copy_constructor)
+ && (type_has_user_declared_move_constructor (type)
+ || type_has_user_declared_move_assign (type)))
+ DECL_DELETED_FN (fn) = true;
+
/* For move variants, rather than declare them as deleted we just
don't declare them at all. */
if (DECL_DELETED_FN (fn)
|| sfk == sfk_move_assignment))
return NULL_TREE;
+ /* We also suppress implicit move if it would call a non-trivial copy. */
+ if (FNDECL_SUPPRESS_IMPLICIT_DECL (fn))
+ return NULL_TREE;
+
/* A destructor may be virtual. */
if (sfk == sfk_destructor
|| sfk == sfk_move_assignment