aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/method.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/method.c')
-rw-r--r--gcc/cp/method.c230
1 files changed, 132 insertions, 98 deletions
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 9470cd5997d..2f5e1f67e81 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1,11 +1,11 @@
/* 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,
+ Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
-
+
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
@@ -37,6 +37,7 @@ Boston, MA 02111-1307, USA. */
#include "tm_p.h"
#include "target.h"
#include "tree-pass.h"
+#include "diagnostic.h"
/* Various flags to control the mangling process. */
@@ -88,22 +89,22 @@ make_thunk (tree function, bool this_adjusting,
{
HOST_WIDE_INT d;
tree thunk;
-
+
gcc_assert (TREE_CODE (function) == FUNCTION_DECL);
/* We can have this thunks to covariant thunks, but not vice versa. */
gcc_assert (!DECL_THIS_THUNK_P (function));
gcc_assert (!DECL_RESULT_THUNK_P (function) || this_adjusting);
-
+
/* Scale the VIRTUAL_OFFSET to be in terms of bytes. */
if (this_adjusting && virtual_offset)
- virtual_offset
+ virtual_offset
= size_binop (MULT_EXPR,
- virtual_offset,
- convert (ssizetype,
- TYPE_SIZE_UNIT (vtable_entry_type)));
-
+ virtual_offset,
+ convert (ssizetype,
+ TYPE_SIZE_UNIT (vtable_entry_type)));
+
d = tree_low_cst (fixed_offset, 0);
-
+
/* See if we already have the thunk in question. For this_adjusting
thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it
will be a BINFO. */
@@ -117,7 +118,7 @@ make_thunk (tree function, bool this_adjusting,
virtual_offset)
: THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)))
return thunk;
-
+
/* All thunks must be created before FUNCTION is actually emitted;
the ABI requires that all thunks be emitted together with the
function to which they transfer control. */
@@ -131,7 +132,7 @@ make_thunk (tree function, bool this_adjusting,
DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
cxx_dup_lang_specific_decl (thunk);
DECL_THUNKS (thunk) = NULL_TREE;
-
+
DECL_CONTEXT (thunk) = DECL_CONTEXT (function);
TREE_READONLY (thunk) = TREE_READONLY (function);
TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);
@@ -143,7 +144,7 @@ make_thunk (tree function, bool this_adjusting,
THUNK_FIXED_OFFSET (thunk) = d;
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;
@@ -162,7 +163,7 @@ make_thunk (tree function, bool this_adjusting,
DECL_DECLARED_INLINE_P (thunk) = 0;
/* Nor has it been deferred. */
DECL_DEFERRED_FN (thunk) = 0;
-
+
/* Add it to the list of thunks associated with FUNCTION. */
TREE_CHAIN (thunk) = DECL_THUNKS (function);
DECL_THUNKS (function) = thunk;
@@ -205,7 +206,7 @@ finish_thunk (tree thunk)
break;
}
}
-
+
DECL_NAME (thunk) = name;
SET_DECL_ASSEMBLER_NAME (thunk, name);
}
@@ -233,7 +234,7 @@ thunk_adjust (tree ptr, bool this_adjusting,
ptr = save_expr (ptr);
/* The vptr is always at offset zero in the object. */
vtable = build1 (NOP_EXPR,
- build_pointer_type (build_pointer_type
+ build_pointer_type (build_pointer_type
(vtable_entry_type)),
ptr);
/* Form the vtable address. */
@@ -245,7 +246,7 @@ thunk_adjust (tree ptr, bool this_adjusting,
/* Adjust the `this' pointer. */
ptr = fold_build2 (PLUS_EXPR, TREE_TYPE (ptr), ptr, vtable);
}
-
+
if (!this_adjusting)
/* Adjust the pointer by the constant. */
ptr = fold_build2 (PLUS_EXPR, TREE_TYPE (ptr), ptr,
@@ -258,16 +259,10 @@ static GTY (()) int thunk_labelno;
/* Create a static alias to function. */
-static tree
-make_alias_for_thunk (tree function)
+tree
+make_alias_for (tree function, tree newid)
{
- tree alias;
- char buf[256];
-
- ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno);
- thunk_labelno++;
- alias = build_decl (FUNCTION_DECL, get_identifier (buf),
- TREE_TYPE (function));
+ tree alias = build_decl (FUNCTION_DECL, newid, TREE_TYPE (function));
DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
cxx_dup_lang_specific_decl (alias);
DECL_CONTEXT (alias) = NULL;
@@ -296,8 +291,23 @@ make_alias_for_thunk (tree function)
TREE_USED (alias) = 1;
SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1;
+ return alias;
+}
+
+static tree
+make_alias_for_thunk (tree function)
+{
+ tree alias;
+ char buf[256];
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno);
+ thunk_labelno++;
+
+ alias = make_alias_for (function, get_identifier (buf));
+
if (!flag_syntax_only)
assemble_alias (alias, DECL_ASSEMBLER_NAME (function));
+
return alias;
}
@@ -322,7 +332,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
if (TREE_ASM_WRITTEN (thunk_fndecl))
return;
-
+
function = THUNK_TARGET (thunk_fndecl);
if (DECL_RESULT (thunk_fndecl))
/* We already turned this thunk into an ordinary function.
@@ -332,7 +342,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
if (DECL_THUNK_P (function))
/* The target is itself a thunk, process it now. */
use_thunk (function, emit_p);
-
+
/* Thunks are always addressable; they only appear in vtables. */
TREE_ADDRESSABLE (thunk_fndecl) = 1;
@@ -360,7 +370,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
}
else
virtual_value = 0;
-
+
/* And, if we need to emit the thunk, it's used. */
mark_used (thunk_fndecl);
/* This thunk is actually defined. */
@@ -369,7 +379,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
rewrite. */
TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
- DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
+ DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
= DECL_VISIBILITY_SPECIFIED (function);
if (flag_weak && TREE_PUBLIC (thunk_fndecl))
comdat_linkage (thunk_fndecl);
@@ -413,7 +423,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
a = nreverse (t);
DECL_ARGUMENTS (thunk_fndecl) = a;
BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = a;
-
+
if (this_adjusting
&& targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
virtual_value, alias))
@@ -458,7 +468,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
if (this_adjusting)
t = thunk_adjust (t, /*this_adjusting=*/1,
fixed_offset, virtual_offset);
-
+
/* Build up the call to the real function. */
t = tree_cons (NULL_TREE, t, NULL_TREE);
for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
@@ -466,7 +476,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
t = nreverse (t);
t = build_call (alias, t);
CALL_FROM_THUNK_P (t) = 1;
-
+
if (VOID_TYPE_P (TREE_TYPE (t)))
finish_expr_stmt (t);
else
@@ -484,7 +494,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
t = save_expr (t);
cond = cp_convert (boolean_type_node, t);
}
-
+
t = thunk_adjust (t, /*this_adjusting=*/0,
fixed_offset, virtual_offset);
if (cond)
@@ -550,7 +560,7 @@ do_build_copy_constructor (tree fndecl)
for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0;
VEC_iterate (tree, vbases, i, binfo); i++)
{
- member_init_list
+ member_init_list
= tree_cons (binfo,
build_tree_list (NULL_TREE,
build_base_path (PLUS_EXPR, parm,
@@ -562,9 +572,9 @@ do_build_copy_constructor (tree fndecl)
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
{
if (BINFO_VIRTUAL_P (base_binfo))
- continue;
+ continue;
- member_init_list
+ member_init_list
= tree_cons (base_binfo,
build_tree_list (NULL_TREE,
build_base_path (PLUS_EXPR, parm,
@@ -601,12 +611,12 @@ do_build_copy_constructor (tree fndecl)
if (TREE_CODE (expr_type) != REFERENCE_TYPE)
{
int quals = cvquals;
-
+
if (DECL_MUTABLE_P (field))
quals &= ~TYPE_QUAL_CONST;
expr_type = cp_build_qualified_type (expr_type, quals);
}
-
+
init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE);
init = build_tree_list (NULL_TREE, init);
@@ -651,18 +661,18 @@ do_build_assign_ref (tree fndecl)
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. */
- finish_expr_stmt
- (build_special_member_call (current_class_ref,
+ finish_expr_stmt
+ (build_special_member_call (current_class_ref,
ansi_assopname (NOP_EXPR),
- build_tree_list (NULL_TREE,
+ build_tree_list (NULL_TREE,
converted_parm),
base_binfo,
LOOKUP_NORMAL | LOOKUP_NONVIRTUAL));
}
/* Assign to each of the non-static data members. */
- for (fields = TYPE_FIELDS (current_class_type);
- fields;
+ for (fields = TYPE_FIELDS (current_class_type);
+ fields;
fields = TREE_CHAIN (fields))
{
tree comp = current_class_ref;
@@ -675,17 +685,17 @@ do_build_assign_ref (tree fndecl)
continue;
expr_type = TREE_TYPE (field);
-
+
if (CP_TYPE_CONST_P (expr_type))
{
- error ("non-static const member %q#D, can't use default "
- "assignment operator", field);
+ error ("non-static const member %q#D, can't use default "
+ "assignment operator", field);
continue;
}
else if (TREE_CODE (expr_type) == REFERENCE_TYPE)
{
error ("non-static reference member %q#D, can't use "
- "default assignment operator", field);
+ "default assignment operator", field);
continue;
}
@@ -702,13 +712,13 @@ do_build_assign_ref (tree fndecl)
continue;
comp = build3 (COMPONENT_REF, expr_type, comp, field, NULL_TREE);
-
+
/* Compute the type of init->field */
quals = cvquals;
if (DECL_MUTABLE_P (field))
quals &= ~TYPE_QUAL_CONST;
expr_type = cp_build_qualified_type (expr_type, quals);
-
+
init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE);
if (DECL_NAME (field))
@@ -722,6 +732,8 @@ do_build_assign_ref (tree fndecl)
finish_compound_stmt (compound_stmt);
}
+/* Synthesize FNDECL, a non-static member function. */
+
void
synthesize_method (tree fndecl)
{
@@ -730,17 +742,19 @@ synthesize_method (tree fndecl)
bool need_body = true;
tree stmt;
location_t save_input_location = input_location;
+ int error_count = errorcount;
+ int warning_count = warningcount;
+
+ /* Reset the source location, we might have been previously
+ deferred, and thus have saved where we were first needed. */
+ DECL_SOURCE_LOCATION (fndecl)
+ = DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (fndecl)));
/* If we've been asked to synthesize a clone, just synthesize the
cloned function instead. Doing so will automatically fill in the
body for the clone. */
if (DECL_CLONED_FUNCTION_P (fndecl))
- {
- DECL_SOURCE_LOCATION (DECL_CLONED_FUNCTION (fndecl)) =
- DECL_SOURCE_LOCATION (fndecl);
- synthesize_method (DECL_CLONED_FUNCTION (fndecl));
- return;
- }
+ fndecl = DECL_CLONED_FUNCTION (fndecl);
/* We may be in the middle of deferred access check. Disable
it now. */
@@ -790,6 +804,10 @@ synthesize_method (tree fndecl)
pop_function_context_from (context);
pop_deferring_access_checks ();
+
+ if (error_count != errorcount || warning_count != warningcount)
+ inform ("%Hsynthesized method %qD first required here ",
+ &input_location, fndecl);
}
/* Use EXTRACTOR to locate the relevant function called for each base &
@@ -800,7 +818,7 @@ synthesize_method (tree fndecl)
static tree
synthesize_exception_spec (tree type, tree (*extractor) (tree, void*),
- void *client)
+ void *client)
{
tree raises = empty_except_spec;
tree fields = TYPE_FIELDS (type);
@@ -812,31 +830,31 @@ synthesize_exception_spec (tree type, tree (*extractor) (tree, void*),
{
tree fn = (*extractor) (BINFO_TYPE (base_binfo), client);
if (fn)
- {
- tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
-
- raises = merge_exception_specifiers (raises, fn_raises);
- }
+ {
+ tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+
+ raises = merge_exception_specifiers (raises, fn_raises);
+ }
}
for (; fields; fields = TREE_CHAIN (fields))
{
tree type = TREE_TYPE (fields);
tree fn;
-
+
if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields))
- continue;
+ continue;
while (TREE_CODE (type) == ARRAY_TYPE)
- type = TREE_TYPE (type);
+ type = TREE_TYPE (type);
if (TREE_CODE (type) != RECORD_TYPE)
- continue;
-
+ continue;
+
fn = (*extractor) (type, client);
if (fn)
- {
- tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
-
- raises = merge_exception_specifiers (raises, fn_raises);
- }
+ {
+ tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+
+ raises = merge_exception_specifiers (raises, fn_raises);
+ }
}
return raises;
}
@@ -855,7 +873,7 @@ static tree
locate_ctor (tree type, void *client ATTRIBUTE_UNUSED)
{
tree fns;
-
+
if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
return NULL_TREE;
@@ -868,9 +886,9 @@ locate_ctor (tree type, void *client ATTRIBUTE_UNUSED)
{
tree fn = OVL_CURRENT (fns);
tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
-
+
if (sufficient_parms_p (TREE_CHAIN (parms)))
- return fn;
+ return fn;
}
return NULL_TREE;
}
@@ -892,7 +910,7 @@ locate_copy (tree type, void *client_)
tree fns;
tree best = NULL_TREE;
bool excess_p = false;
-
+
if (client->name)
{
int ix;
@@ -918,27 +936,27 @@ locate_copy (tree type, void *client_)
tree src_type;
int excess;
int quals;
-
+
parms = TREE_CHAIN (parms);
if (!parms)
- continue;
+ continue;
src_type = non_reference (TREE_VALUE (parms));
if (!same_type_ignoring_top_level_qualifiers_p (src_type, type))
- continue;
+ continue;
if (!sufficient_parms_p (TREE_CHAIN (parms)))
- continue;
+ continue;
quals = cp_type_quals (src_type);
if (client->quals & ~quals)
- continue;
+ continue;
excess = quals & ~client->quals;
if (!best || (excess_p && !excess))
- {
- best = fn;
- excess_p = excess;
- }
+ {
+ best = fn;
+ excess_p = excess;
+ }
else
- /* Ambiguous */
- return NULL_TREE;
+ /* Ambiguous */
+ return NULL_TREE;
}
return best;
}
@@ -959,6 +977,19 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
tree raises = empty_except_spec;
tree rhs_parm_type = NULL_TREE;
tree name;
+ HOST_WIDE_INT saved_processing_template_decl;
+
+ /* Because we create declarations for implictly declared functions
+ lazily, we may be creating the declaration for a member of TYPE
+ while in some completely different context. However, TYPE will
+ never be a dependent class (because we never want to do lookups
+ for implicitly defined functions in a dependent class).
+ Furthermore, we must set PROCESSING_TEMPLATE_DECL to zero here
+ because we only create clones for constructors and destructors
+ when not in a template. */
+ gcc_assert (!dependent_type_p (type));
+ saved_processing_template_decl = processing_template_decl;
+ processing_template_decl = 0;
type = TYPE_MAIN_VARIANT (type);
@@ -991,23 +1022,23 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
case sfk_assignment_operator:
{
struct copy_data data;
-
+
data.name = NULL;
data.quals = 0;
if (kind == sfk_assignment_operator)
- {
+ {
return_type = build_reference_type (type);
- name = ansi_assopname (NOP_EXPR);
- data.name = name;
- }
+ name = ansi_assopname (NOP_EXPR);
+ data.name = name;
+ }
else
name = constructor_name (type);
if (const_p)
- {
- data.quals = TYPE_QUAL_CONST;
+ {
+ data.quals = TYPE_QUAL_CONST;
rhs_parm_type = build_qualified_type (type, TYPE_QUAL_CONST);
- }
+ }
else
rhs_parm_type = type;
rhs_parm_type = build_reference_type (rhs_parm_type);
@@ -1057,6 +1088,9 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
DECL_INLINE (fn) = 1;
gcc_assert (!TREE_USED (fn));
+ /* Restore PROCESSING_TEMPLATE_DECL. */
+ processing_template_decl = saved_processing_template_decl;
+
return fn;
}
@@ -1085,9 +1119,9 @@ lazily_declare_fn (special_function_kind sfk, tree type)
if (sfk == sfk_destructor)
check_for_override (fn, type);
/* Add it to CLASSTYPE_METHOD_VEC. */
- add_method (type, fn);
+ add_method (type, fn, NULL_TREE);
/* Add it to TYPE_METHODS. */
- if (sfk == sfk_destructor
+ if (sfk == sfk_destructor
&& DECL_VIRTUAL_P (fn)
&& abi_version_at_least (2))
/* The ABI requires that a virtual destructor go at the end of the
@@ -1097,7 +1131,7 @@ lazily_declare_fn (special_function_kind sfk, tree type)
{
/* 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. */
+ in an incorrect location in the vtable. */
if (warn_abi && DECL_VIRTUAL_P (fn))
warning (0, "vtable layout for class %qT may not be ABI-compliant"
"and may change in a future version of GCC due to "