/* 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
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
gcc_assert (TYPE_SIZE (DECL_CONTEXT (function))
&& TYPE_BEING_DEFINED (DECL_CONTEXT (function)));
- thunk = build_decl (FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));
+ thunk = build_decl (DECL_SOURCE_LOCATION (function),
+ FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));
DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
cxx_dup_lang_specific_decl (thunk);
DECL_THUNKS (thunk) = NULL_TREE;
DECL_CONSTRUCTOR_P (thunk) = 0;
DECL_EXTERNAL (thunk) = 1;
DECL_ARTIFICIAL (thunk) = 1;
- /* Even if this thunk is a member of a local class, we don't
- need a static chain. */
- DECL_NO_STATIC_CHAIN (thunk) = 1;
/* The THUNK is not a pending inline, even if the FUNCTION is. */
DECL_PENDING_INLINE_P (thunk) = 0;
- DECL_INLINE (thunk) = 0;
DECL_DECLARED_INLINE_P (thunk) = 0;
- /* Nor has it been deferred. */
- DECL_DEFERRED_FN (thunk) = 0;
/* Nor is it a template instantiation. */
DECL_USE_TEMPLATE (thunk) = 0;
DECL_TEMPLATE_INFO (thunk) = NULL;
{
if (this_adjusting)
/* Adjust the pointer by the constant. */
- ptr = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr,
+ ptr = fold_build2_loc (input_location,
+ POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr,
size_int (fixed_offset));
/* If there's a virtual offset, look up that value in the vtable and
/* Form the vtable address. */
vtable = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (vtable)), vtable);
/* Find the entry with the vcall offset. */
- vtable = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (vtable), vtable,
- fold_convert (sizetype, virtual_offset));
+ vtable = fold_build2_loc (input_location,
+ POINTER_PLUS_EXPR, TREE_TYPE (vtable), vtable,
+ fold_convert (sizetype, virtual_offset));
/* Get the offset itself. */
vtable = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (vtable)), vtable);
/* Adjust the `this' pointer. */
- ptr = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr,
+ ptr = fold_build2_loc (input_location,
+ POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr,
fold_convert (sizetype, vtable));
}
if (!this_adjusting)
/* Adjust the pointer by the constant. */
- ptr = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr,
+ ptr = fold_build2_loc (input_location,
+ POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr,
size_int (fixed_offset));
return ptr;
tree
make_alias_for (tree function, tree newid)
{
- tree alias = build_decl (FUNCTION_DECL, newid, TREE_TYPE (function));
+ tree alias = build_decl (DECL_SOURCE_LOCATION (function),
+ FUNCTION_DECL, newid, TREE_TYPE (function));
DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
cxx_dup_lang_specific_decl (alias);
DECL_CONTEXT (alias) = NULL;
DECL_SAVED_FUNCTION_DATA (alias) = NULL;
DECL_DESTRUCTOR_P (alias) = 0;
DECL_CONSTRUCTOR_P (alias) = 0;
- DECL_CLONED_FUNCTION (alias) = NULL_TREE;
DECL_EXTERNAL (alias) = 0;
DECL_ARTIFICIAL (alias) = 1;
- DECL_NO_STATIC_CHAIN (alias) = 1;
DECL_PENDING_INLINE_P (alias) = 0;
- DECL_INLINE (alias) = 0;
DECL_DECLARED_INLINE_P (alias) = 0;
- DECL_DEFERRED_FN (alias) = 0;
DECL_USE_TEMPLATE (alias) = 0;
DECL_TEMPLATE_INSTANTIATED (alias) = 0;
DECL_TEMPLATE_INFO (alias) = NULL;
DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
= DECL_VISIBILITY_SPECIFIED (function);
- if (DECL_ONE_ONLY (function))
- make_decl_one_only (thunk_fndecl);
+ if (DECL_ONE_ONLY (function) || DECL_WEAK (function))
+ make_decl_one_only (thunk_fndecl, cxx_comdat_group (thunk_fndecl));
if (flag_syntax_only)
{
current_function_decl = thunk_fndecl;
DECL_RESULT (thunk_fndecl)
- = build_decl (RESULT_DECL, 0, integer_type_node);
+ = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
+ RESULT_DECL, 0, integer_type_node);
fnname = IDENTIFIER_POINTER (DECL_NAME (thunk_fndecl));
/* The back end expects DECL_INITIAL to contain a BLOCK, so we
create one. */
BLOCK_VARS (fn_block) = a;
DECL_INITIAL (thunk_fndecl) = fn_block;
init_function_start (thunk_fndecl);
- crtl->is_thunk = 1;
+ cfun->is_thunk = 1;
assemble_start_function (thunk_fndecl, fnname);
targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
assemble_end_function (thunk_fndecl, fnname);
init_insn_lengths ();
+ free_after_compilation (cfun);
current_function_decl = 0;
set_cfun (NULL);
TREE_ASM_WRITTEN (thunk_fndecl) = 1;
\f
/* Code for synthesizing methods which have default semantics defined. */
-/* Generate code for default X(X&) constructor. */
+/* Generate code for default X(X&) or X(X&&) constructor. */
static void
do_build_copy_constructor (tree fndecl)
{
tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
+ bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl);
parm = convert_from_reference (parm);
int cvquals = cp_type_quals (TREE_TYPE (parm));
int i;
tree binfo, base_binfo;
+ tree init;
VEC(tree,gc) *vbases;
/* Initialize all the base-classes with the parameter converted
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);
+ if (move_p)
+ init = move (init);
member_init_list
= tree_cons (binfo,
- build_tree_list (NULL_TREE,
- build_base_path (PLUS_EXPR, parm,
- binfo, 1)),
+ build_tree_list (NULL_TREE, init),
member_init_list);
}
if (BINFO_VIRTUAL_P (base_binfo))
continue;
+ init = build_base_path (PLUS_EXPR, parm, base_binfo, 1);
+ if (move_p)
+ init = move (init);
member_init_list
= tree_cons (base_binfo,
- build_tree_list (NULL_TREE,
- build_base_path (PLUS_EXPR, parm,
- base_binfo, 1)),
+ build_tree_list (NULL_TREE, init),
member_init_list);
}
for (; fields; fields = TREE_CHAIN (fields))
{
- tree init = parm;
tree field = fields;
tree expr_type;
if (DECL_MUTABLE_P (field))
quals &= ~TYPE_QUAL_CONST;
+ quals |= TYPE_QUALS (expr_type);
expr_type = cp_build_qualified_type (expr_type, quals);
}
- init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE);
+ init = build3 (COMPONENT_REF, expr_type, parm, field, NULL_TREE);
+ if (move_p && TREE_CODE (expr_type) != REFERENCE_TYPE)
+ init = move (init);
init = build_tree_list (NULL_TREE, init);
member_init_list = tree_cons (field, init, member_init_list);
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
{
tree converted_parm;
+ VEC(tree,gc) *parmvec;
/* 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);
/* Call the base class assignment operator. */
+ parmvec = make_tree_vector_single (converted_parm);
finish_expr_stmt
(build_special_member_call (current_class_ref,
ansi_assopname (NOP_EXPR),
- build_tree_list (NULL_TREE,
- converted_parm),
+ &parmvec,
base_binfo,
LOOKUP_NORMAL | LOOKUP_NONVIRTUAL,
tf_warning_or_error));
+ release_tree_vector (parmvec);
}
/* Assign to each of the non-static data members. */
pop_deferring_access_checks ();
if (error_count != errorcount || warning_count != warningcount)
- inform ("%Hsynthesized method %qD first required here ",
- &input_location, fndecl);
+ inform (input_location, "synthesized method %qD first required here ",
+ fndecl);
}
/* Use EXTRACTOR to locate the relevant function called for each base &
it now. */
if (CLASSTYPE_LAZY_COPY_CTOR (type))
lazily_declare_fn (sfk_copy_constructor, type);
+ if (CLASSTYPE_LAZY_MOVE_CTOR (type))
+ lazily_declare_fn (sfk_move_constructor, type);
fns = CLASSTYPE_CONSTRUCTORS (type);
}
else
case sfk_copy_constructor:
case sfk_assignment_operator:
+ case sfk_move_constructor:
{
struct copy_data data;
}
else
rhs_parm_type = type;
- rhs_parm_type = build_reference_type (rhs_parm_type);
+ rhs_parm_type
+ = cp_build_reference_type (rhs_parm_type,
+ kind == sfk_move_constructor);
parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
raises = synthesize_exception_spec (type, &locate_copy, &data);
break;
fn_type = build_exception_variant (fn_type, raises);
fn = build_lang_decl (FUNCTION_DECL, name, fn_type);
DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (TYPE_NAME (type));
- if (kind == sfk_constructor || kind == sfk_copy_constructor)
+ if (kind == sfk_constructor || kind == sfk_copy_constructor
+ || kind == sfk_move_constructor)
DECL_CONSTRUCTOR_P (fn) = 1;
else if (kind == sfk_destructor)
DECL_DESTRUCTOR_P (fn) = 1;
DECL_DEFAULTED_FN (fn) = 1;
DECL_NOT_REALLY_EXTERN (fn) = 1;
DECL_DECLARED_INLINE_P (fn) = 1;
- DECL_INLINE (fn) = 1;
gcc_assert (!TREE_USED (fn));
/* Restore PROCESSING_TEMPLATE_DECL. */
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. */
/* G++ 3.2 put the implicit destructor at the *beginning* of the
TYPE_METHODS list, which cause the destructor to be emitted
in an incorrect location in the vtable. */
- if (warn_abi && DECL_VIRTUAL_P (fn))
+ if (warn_abi && sfk == sfk_destructor && DECL_VIRTUAL_P (fn))
warning (OPT_Wabi, "vtable layout for class %qT may not be ABI-compliant"
"and may change in a future version of GCC due to "
"implicit virtual destructor",
CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0;
else if (sfk == sfk_copy_constructor)
CLASSTYPE_LAZY_COPY_CTOR (type) = 0;
+ else if (sfk == sfk_move_constructor)
+ CLASSTYPE_LAZY_MOVE_CTOR (type) = 0;
else if (sfk == sfk_destructor)
CLASSTYPE_LAZY_DESTRUCTOR (type) = 0;
/* Create appropriate clones. */