diff options
Diffstat (limited to 'gcc/cp/sig.c')
-rwxr-xr-x | gcc/cp/sig.c | 1071 |
1 files changed, 0 insertions, 1071 deletions
diff --git a/gcc/cp/sig.c b/gcc/cp/sig.c deleted file mode 100755 index f264d31..0000000 --- a/gcc/cp/sig.c +++ /dev/null @@ -1,1071 +0,0 @@ -/* Functions dealing with signatures and signature pointers/references. - Copyright (C) 1992, 93-97, 1998 Free Software Foundation, Inc. - Contributed by Gerald Baumgartner (gb@cs.purdue.edu) - -This file is part of GNU CC. - -GNU CC 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) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - - -#include "config.h" -#include "system.h" -#include "obstack.h" -#include "tree.h" -#include "cp-tree.h" -#include "flags.h" -#include "assert.h" -#include "toplev.h" - -extern struct obstack *current_obstack; -extern struct obstack permanent_obstack; -extern struct obstack *saveable_obstack; - -extern void compiler_error (); - -static tree save_this PROTO((tree)); -static tree build_sptr_ref PROTO((tree)); -static tree build_member_function_pointer PROTO((tree)); -static void undo_casts PROTO((tree)); -static tree build_signature_pointer_or_reference_name - PROTO((tree, int, int)); -static void build_signature_pointer_or_reference_decl - PROTO((tree, tree)); -static tree build_signature_pointer_or_reference_type - PROTO((tree, int, int)); -static tree get_sigtable_name PROTO((tree, tree)); -static tree build_signature_table_constructor PROTO((tree, tree)); -static int match_method_types PROTO((tree, tree)); -static tree build_sigtable PROTO((tree, tree, tree)); - -/* Used to help generate globally unique names for signature tables. */ - -static int global_sigtable_name_counter; - -/* Build an identifier for a signature pointer or reference, so we - can use it's name in function name mangling. */ - -static tree -build_signature_pointer_or_reference_name (to_type, type_quals, refp) - tree to_type; - int type_quals; - int refp; -{ - char * sig_name = TYPE_NAME_STRING (to_type); - int name_len = TYPE_NAME_LENGTH (to_type) + 3 /* Enough room for - C,V,R. */; - char * name; - - char *const_rep = (type_quals & TYPE_QUAL_CONST) ? "C" : ""; - char *restrict_rep = (type_quals & TYPE_QUAL_RESTRICT) ? "R" : ""; - char *volatile_rep = (type_quals & TYPE_QUAL_VOLATILE) ? "C" : ""; - - if (refp) - { - name = (char *) alloca (name_len + sizeof (SIGNATURE_REFERENCE_NAME) +2); - sprintf (name, SIGNATURE_REFERENCE_NAME_FORMAT, - const_rep, volatile_rep, restrict_rep, sig_name); - } - else - { - name = (char *) alloca (name_len + sizeof (SIGNATURE_POINTER_NAME) + 2); - sprintf (name, SIGNATURE_POINTER_NAME_FORMAT, - const_rep, volatile_rep, restrict_rep, sig_name); - } - return get_identifier (name); -} - -/* Build a DECL node for a signature pointer or reference, so we can - tell the debugger the structure of signature pointers/references. - This function is called at most eight times for a given signature, - once for each [const] [volatile] signature pointer/reference. */ - -static void -build_signature_pointer_or_reference_decl (type, name) - tree type, name; -{ - tree decl; - - /* We don't enter this declaration in any sort of symbol table. */ - decl = build_decl (TYPE_DECL, name, type); - TYPE_NAME (type) = decl; - TREE_CHAIN (type) = decl; -} - -/* Construct, lay out and return the type of pointers or references to - signature TO_TYPE. If such a type has already been constructed, - reuse it. If TYPE_QUALS are specified, qualify the `optr'. If we - are constructing a const/volatile type variant and the main type - variant doesn't exist yet, it is built as well. If REFP is 1, we - construct a signature reference, otherwise a signature pointer is - constructed. - - This function is a subroutine of `build_signature_pointer_type' and - `build_signature_reference_type'. */ - -static tree -build_signature_pointer_or_reference_type (to_type, type_quals, refp) - tree to_type; - int type_quals; - int refp; -{ - register tree t, m; - register struct obstack *ambient_obstack = current_obstack; - register struct obstack *ambient_saveable_obstack = saveable_obstack; - - m = refp ? SIGNATURE_REFERENCE_TO (to_type) : SIGNATURE_POINTER_TO (to_type); - - /* If we don't have the main variant yet, construct it. */ - if (m == NULL_TREE && type_quals != TYPE_UNQUALIFIED) - m = build_signature_pointer_or_reference_type (to_type, - TYPE_UNQUALIFIED, refp); - - /* Treat any nonzero argument as 1. */ - refp = !!refp; - - /* If not generating auxiliary info, search the chain of variants to see - if there is already one there just like the one we need to have. If so, - use that existing one. - - We don't do this in the case where we are generating aux info because - in that case we want each typedef names to get it's own distinct type - node, even if the type of this new typedef is the same as some other - (existing) type. */ - - if (m && !flag_gen_aux_info) - for (t = m; t; t = TYPE_NEXT_VARIANT (t)) - if (type_quals == CP_TYPE_QUALS (TREE_TYPE (TREE_TYPE - (TYPE_FIELDS (t))))) - return t; - - /* We need a new one. If TO_TYPE is permanent, make this permanent too. */ - if (TREE_PERMANENT (to_type)) - { - current_obstack = &permanent_obstack; - saveable_obstack = &permanent_obstack; - } - - /* A signature pointer or reference to a signature `s' looks like this: - - struct { - void * optr; - const s * sptr; - }; - - A `const' signature pointer/reference is a - - struct { - const void * optr; - const s * sptr; - }; - - Similarly, for `volatile' and `const volatile'. */ - - t = make_lang_type (RECORD_TYPE); - { - tree obj_type = build_qualified_type (void_type_node, type_quals); - tree optr_type = build_pointer_type (obj_type); - tree optr, sptr; - - optr = build_lang_field_decl (FIELD_DECL, - get_identifier (SIGNATURE_OPTR_NAME), - optr_type); - DECL_FIELD_CONTEXT (optr) = t; - DECL_CLASS_CONTEXT (optr) = t; - - if (m) - /* We can share the `sptr' field among type variants. */ - sptr = TREE_CHAIN (TYPE_FIELDS (m)); - else - { - tree sig_tbl_type = - cp_build_qualified_type (to_type, TYPE_QUAL_CONST); - - sptr = build_lang_field_decl (FIELD_DECL, - get_identifier (SIGNATURE_SPTR_NAME), - build_pointer_type (sig_tbl_type)); - DECL_FIELD_CONTEXT (sptr) = t; - DECL_CLASS_CONTEXT (sptr) = t; - TREE_CHAIN (sptr) = NULL_TREE; - } - - TREE_CHAIN (optr) = sptr; - TYPE_FIELDS (t) = optr; - /* Allow signature pointers/references to be grabbed 2 words at a time. - For this to work on a Sparc, we need 8-byte alignment. */ - TYPE_ALIGN (t) = MAX (TYPE_ALIGN (double_type_node), - TYPE_ALIGN (optr_type)); - - /* A signature pointer/reference type isn't a `real' class type. */ - SET_IS_AGGR_TYPE (t, 0); - } - - { - tree name = build_signature_pointer_or_reference_name (to_type, - type_quals, - refp); - - /* Build a DECL node for this type, so the debugger has access to it. */ - build_signature_pointer_or_reference_decl (t, name); - } - - CLASSTYPE_GOT_SEMICOLON (t) = 1; - IS_SIGNATURE_POINTER (t) = ! refp; - IS_SIGNATURE_REFERENCE (t) = refp; - SIGNATURE_TYPE (t) = to_type; - - if (m) - { - /* Add this type to the chain of variants of TYPE. - Every type has to be its own TYPE_MAIN_VARIANT. */ - TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m); - TYPE_NEXT_VARIANT (m) = t; - } - else if (refp) - /* Record this type as the reference to TO_TYPE. */ - SIGNATURE_REFERENCE_TO (to_type) = t; - else - /* Record this type as the pointer to TO_TYPE. */ - SIGNATURE_POINTER_TO (to_type) = t; - - /* Lay out the type. This function has many callers that are concerned - with expression-construction, and this simplifies them all. - Also, it guarantees the TYPE_SIZE is permanent if the type is. */ - layout_type (t); - - current_obstack = ambient_obstack; - saveable_obstack = ambient_saveable_obstack; - - /* Output debug information for this type. */ - rest_of_type_compilation (t, 1); - - return t; -} - -/* Construct, lay out and return the type of pointers to signature TO_TYPE. */ - -tree -build_signature_pointer_type (to_type) - tree to_type; -{ - return - build_signature_pointer_or_reference_type (TYPE_MAIN_VARIANT (to_type), - CP_TYPE_QUALS (to_type), 0); -} - -/* Construct, lay out and return the type of pointers to signature TO_TYPE. */ - -tree -build_signature_reference_type (to_type) - tree to_type; -{ - return - build_signature_pointer_or_reference_type (TYPE_MAIN_VARIANT (to_type), - CP_TYPE_QUALS (to_type), 1); -} - -/* Return the name of the signature table (as an IDENTIFIER_NODE) - for the given signature type SIG_TYPE and rhs type RHS_TYPE. */ - -static tree -get_sigtable_name (sig_type, rhs_type) - tree sig_type, rhs_type; -{ - tree sig_type_id = build_typename_overload (sig_type); - tree rhs_type_id = build_typename_overload (rhs_type); - char *buf = (char *) alloca (sizeof (SIGTABLE_NAME_FORMAT_LONG) - + IDENTIFIER_LENGTH (sig_type_id) - + IDENTIFIER_LENGTH (rhs_type_id) + 20); - char *sig_ptr = IDENTIFIER_POINTER (sig_type_id); - char *rhs_ptr = IDENTIFIER_POINTER (rhs_type_id); - int i, j; - - for (i = 0; sig_ptr[i] == OPERATOR_TYPENAME_FORMAT[i]; i++) - /* do nothing */; - while (sig_ptr[i] >= '0' && sig_ptr[i] <= '9') - i += 1; - - for (j = 0; rhs_ptr[j] == OPERATOR_TYPENAME_FORMAT[j]; j++) - /* do nothing */; - while (rhs_ptr[j] >= '0' && rhs_ptr[j] <= '9') - j += 1; - - if (IS_SIGNATURE (rhs_type)) - sprintf (buf, SIGTABLE_NAME_FORMAT_LONG, sig_ptr+i, rhs_ptr+j, - global_sigtable_name_counter++); - else - sprintf (buf, SIGTABLE_NAME_FORMAT, sig_ptr+i, rhs_ptr+j); - return get_identifier (buf); -} - -/* Build a field decl that points to a signature member function. */ - -static tree -build_member_function_pointer (member) - tree member; -{ - char *namstr = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (member)); - int namlen = IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (member)); - char *name; - tree entry; - - name = (char *) alloca (namlen + sizeof (SIGNATURE_FIELD_NAME) + 2); - sprintf (name, SIGNATURE_FIELD_NAME_FORMAT, namstr); - - /* @@ Do we really want to xref signature table fields? */ - GNU_xref_ref (current_function_decl, name); - - entry = build_lang_field_decl (FIELD_DECL, get_identifier (name), - sigtable_entry_type); - TREE_CONSTANT (entry) = 1; - TREE_READONLY (entry) = 1; - - /* @@ Do we really want to xref signature table fields? */ - GNU_xref_decl (current_function_decl, entry); - - return entry; -} - -/* For each FUNCTION_DECL in a signature we construct a member function - pointer of the appropriate type. We also need two flags to test - whether the member function pointer points to a virtual function or - to a default implementation. Those flags will be the two lower order - bits of the member function pointer (or the two higher order bits, - based on the configuration). - - The new FIELD_DECLs are appended at the end of the last (and only) - sublist of `list_of_fieldlists.' - - T is the signature type. - - As a side effect, each member function in the signature gets the - `decl.ignored' bit turned on, so we don't output debug info for it. */ - -void -append_signature_fields (t) - tree t; -{ - tree x; - tree mfptr; - tree last_mfptr = NULL_TREE; - tree mfptr_list = NULL_TREE; - - for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x)) - { - if (TREE_CODE (x) == FUNCTION_DECL) - { - mfptr = build_member_function_pointer (x); - DECL_MEMFUNC_POINTER_TO (x) = mfptr; - DECL_MEMFUNC_POINTING_TO (mfptr) = x; - DECL_IGNORED_P (x) = 1; - DECL_IN_AGGR_P (mfptr) = 1; - if (! mfptr_list) - mfptr_list = last_mfptr = mfptr; - else - { - TREE_CHAIN (last_mfptr) = mfptr; - last_mfptr = mfptr; - } - } - } - - /* The member function pointers must come after the TYPE_DECLs, in - this case, because build_signature_table_constructor depends on - finding opaque TYPE_DECLS before the functions that make use of - them. */ - if (last_mfptr) - TYPE_FIELDS (t) = chainon (TYPE_FIELDS (t), mfptr_list); -} - -/* Compare the types of a signature member function and a class member - function. Returns 1 if the types are in the C++ `<=' relationship. - - If we have a signature pointer/reference as argument or return type - we don't want to do a recursive conformance check. The conformance - check only succeeds if both LHS and RHS refer to the same signature - pointer. Otherwise we need to keep information about parameter types - around at run time to initialize the signature table correctly. */ - -static int -match_method_types (sig_mtype, class_mtype) - tree sig_mtype, class_mtype; -{ - tree sig_return_type = TREE_TYPE (sig_mtype); - tree sig_arg_types = TYPE_ARG_TYPES (sig_mtype); - tree class_return_type = TREE_TYPE (class_mtype); - tree class_arg_types = TYPE_ARG_TYPES (class_mtype); - - /* The return types have to be the same. */ - if (!same_type_p (sig_return_type, class_return_type)) - return 0; - - /* Compare the first argument `this.' */ - { - /* Get the type of what the `optr' is pointing to. */ - tree sig_this - = TREE_TYPE (TREE_TYPE (TYPE_FIELDS (TREE_VALUE (sig_arg_types)))); - tree class_this = TREE_VALUE (class_arg_types); - - if (TREE_CODE (class_this) == RECORD_TYPE) /* Is `this' a sig ptr? */ - class_this = TREE_TYPE (TREE_TYPE (TYPE_FIELDS (class_this))); - else - class_this = TREE_TYPE (class_this); - - /* If a signature method's `this' is const or volatile, so has to be - the corresponding class method's `this.' */ - if (!at_least_as_qualified_p (class_this, sig_this)) - return 0; - } - - sig_arg_types = TREE_CHAIN (sig_arg_types); - class_arg_types = TREE_CHAIN (class_arg_types); - - /* The number of arguments and the argument types have to be the same. */ - return compparms (sig_arg_types, class_arg_types); -} - -/* Undo casts of opaque type variables to the RHS types. */ - -static void -undo_casts (sig_ty) - tree sig_ty; -{ - tree field = TYPE_FIELDS (sig_ty); - - /* Since all the FIELD_DECLs for the signature table entries are at the end - of the chain (see `append_signature_fields'), we can do it this way. */ - for (; field && TREE_CODE (field) != FIELD_DECL; field = TREE_CHAIN (field)) - if (TYPE_MAIN_VARIANT (TREE_TYPE (field)) == opaque_type_node) - TREE_TYPE (TREE_TYPE (field)) = TREE_TYPE (ptr_type_node); -} - -/* Do the type checking necessary to see whether the `rhs' conforms to - the lhs's `sig_ty'. Depending on the type of `rhs' return a NULL_TREE, - an integer_zero_node, a constructor, or an expression offsetting the - `rhs' signature table. */ - -static tree -build_signature_table_constructor (sig_ty, rhs) - tree sig_ty, rhs; -{ - tree rhstype = TREE_TYPE (rhs); - tree sig_field = TYPE_FIELDS (sig_ty); - tree result = NULL_TREE; - tree first_rhs_field = NULL_TREE; - tree last_rhs_field = NULL_TREE; - int sig_ptr_p = IS_SIGNATURE (rhstype); - int offset_p = sig_ptr_p; - - rhstype = sig_ptr_p ? rhstype : TREE_TYPE (rhstype); - - if (CLASSTYPE_TAGS (sig_ty)) - { - sorry ("conformance check with signature containing class declarations"); - return error_mark_node; - } - - for (; sig_field; sig_field = TREE_CHAIN (sig_field)) - { - tree basetype_path, baselink, basetypes; - tree sig_method, sig_mname, sig_mtype; - tree rhs_method, tbl_entry; - - if (TREE_CODE (sig_field) == TYPE_DECL) - { - tree sig_field_type = TREE_TYPE (sig_field); - - if (TYPE_MAIN_VARIANT (sig_field_type) == opaque_type_node) - { - /* We've got an opaque type here. */ - tree oty_name = DECL_NAME (sig_field); - tree oty_type = lookup_field (rhstype, oty_name, 1, 1); - - if (oty_type == NULL_TREE || oty_type == error_mark_node) - { - cp_error ("class `%T' does not contain type `%T'", - rhstype, oty_type); - undo_casts (sig_ty); - return error_mark_node; - } - oty_type = TREE_TYPE (oty_type); - - /* Cast `sig_field' to be of type `oty_type'. This will be - undone in `undo_casts' by walking over all the TYPE_DECLs. */ - TREE_TYPE (sig_field_type) = TREE_TYPE (oty_type); - } - /* If we don't have an opaque type, we can ignore the `typedef'. */ - continue; - } - - /* Find the signature method corresponding to `sig_field'. */ - sig_method = DECL_MEMFUNC_POINTING_TO (sig_field); - sig_mname = DECL_NAME (sig_method); - sig_mtype = TREE_TYPE (sig_method); - - basetype_path = TYPE_BINFO (rhstype); - baselink = lookup_fnfields (basetype_path, sig_mname, 0); - if (baselink == NULL_TREE || baselink == error_mark_node) - { - if (! IS_DEFAULT_IMPLEMENTATION (sig_method)) - { - cp_error ("class `%T' does not contain method `%D'", - rhstype, sig_mname); - undo_casts (sig_ty); - return error_mark_node; - } - else - { - /* We use the signature's default implementation. */ - rhs_method = sig_method; - } - } - else - { - /* Find the class method of the correct type. */ - tree rhs_methods; - basetypes = TREE_PURPOSE (baselink); - if (TREE_CODE (basetypes) == TREE_LIST) - basetypes = TREE_VALUE (basetypes); - - rhs_methods = TREE_VALUE (baselink); - for (; rhs_methods; rhs_methods = OVL_NEXT (rhs_methods)) - if ((rhs_method = OVL_CURRENT (rhs_methods)) - && sig_mname == DECL_NAME (rhs_method) - && ! DECL_STATIC_FUNCTION_P (rhs_method) - && match_method_types (sig_mtype, TREE_TYPE (rhs_method))) - break; - - if (rhs_methods == NULL_TREE - || (compute_access (basetypes, rhs_method) - != access_public_node)) - { - error ("class `%s' does not contain a method conforming to `%s'", - TYPE_NAME_STRING (rhstype), - fndecl_as_string (sig_method, 1)); - undo_casts (sig_ty); - return error_mark_node; - } - } - - if (sig_ptr_p && rhs_method != sig_method) - { - tree rhs_field = DECL_MEMFUNC_POINTER_TO (rhs_method); - - if (first_rhs_field == NULL_TREE) - { - first_rhs_field = rhs_field; - last_rhs_field = rhs_field; - } - else if (TREE_CHAIN (last_rhs_field) == rhs_field) - last_rhs_field = rhs_field; - else - offset_p = 0; - - tbl_entry = build_component_ref (rhs, DECL_NAME (rhs_field), - NULL_TREE, 1); - } - else - { - tree tag, vb_off, delta, idx, pfn = NULL_TREE, vt_off = NULL_TREE; - tree tag_decl, vb_off_decl, delta_decl, index_decl; - tree pfn_decl, vt_off_decl; - - if (rhs_method == sig_method) - { - /* default implementation */ - tag = build_unary_op (NEGATE_EXPR, integer_one_node, 0); - vb_off = build_unary_op (NEGATE_EXPR, integer_one_node, 0); - delta = integer_zero_node; - idx = integer_zero_node; - pfn = build_addr_func (rhs_method); - TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (rhs_method)) = 1; - TREE_TYPE (pfn) = ptr_type_node; - TREE_ADDRESSABLE (rhs_method) = 1; - offset_p = 0; /* we can't offset the rhs sig table */ - } - else if (DECL_VINDEX (rhs_method)) - { - /* virtual member function */ - tag = integer_one_node; - vb_off = build_unary_op (NEGATE_EXPR, integer_one_node, 0); - if (flag_vtable_thunks) - delta = BINFO_OFFSET - (get_binfo (DECL_CONTEXT (rhs_method), rhstype, 1)); - else - delta = BINFO_OFFSET - (get_binfo (DECL_CLASS_CONTEXT (rhs_method), rhstype, 1)); - idx = DECL_VINDEX (rhs_method); - vt_off = get_vfield_offset (get_binfo (DECL_CONTEXT (rhs_method), - rhstype, 0)); - } - else - { - /* non-virtual member function */ - tag = integer_zero_node; - vb_off = build_unary_op (NEGATE_EXPR, integer_one_node, 0); - delta = BINFO_OFFSET (get_binfo (DECL_CLASS_CONTEXT (rhs_method), - rhstype, 1)); - idx = integer_zero_node; - pfn = build_addr_func (rhs_method); - TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (rhs_method)) = 1; - TREE_TYPE (pfn) = ptr_type_node; - TREE_ADDRESSABLE (rhs_method) = 1; - } - - /* Since digest_init doesn't handle initializing selected fields - of a struct (i.e., anonymous union), we build the constructor - by hand, without calling digest_init. */ - tag_decl = TYPE_FIELDS (sigtable_entry_type); - vb_off_decl = TREE_CHAIN (tag_decl); - delta_decl = TREE_CHAIN (vb_off_decl); - index_decl = TREE_CHAIN (delta_decl); - pfn_decl = TREE_CHAIN (index_decl); - vt_off_decl = TREE_CHAIN (pfn_decl); - - tag = cp_convert (TREE_TYPE (tag_decl), tag); - vb_off = cp_convert (TREE_TYPE (vb_off_decl), vb_off); - delta = cp_convert (TREE_TYPE (delta_decl), delta); - idx = cp_convert (TREE_TYPE (index_decl), idx); - - if (DECL_VINDEX (rhs_method)) - { - vt_off = cp_convert (TREE_TYPE (vt_off_decl), vt_off); - - tbl_entry = build_tree_list (vt_off_decl, vt_off); - } - else - { - pfn = cp_convert (TREE_TYPE (pfn_decl), pfn); - - tbl_entry = build_tree_list (pfn_decl, pfn); - } - tbl_entry = tree_cons (delta_decl, delta, - tree_cons (index_decl, idx, tbl_entry)); - tbl_entry = tree_cons (tag_decl, tag, - tree_cons (vb_off_decl, vb_off, tbl_entry)); - tbl_entry = build (CONSTRUCTOR, sigtable_entry_type, - NULL_TREE, tbl_entry); - - TREE_CONSTANT (tbl_entry) = 1; - } - - /* Chain those function address expressions together. */ - if (result) - result = tree_cons (NULL_TREE, tbl_entry, result); - else - result = build_tree_list (NULL_TREE, tbl_entry); - } - - if (result == NULL_TREE) - { - /* The signature was empty, we don't need a signature table. */ - undo_casts (sig_ty); - return NULL_TREE; - } - - if (offset_p) - { - if (first_rhs_field == TYPE_FIELDS (rhstype)) - { - /* The sptr field on the lhs can be copied from the rhs. */ - undo_casts (sig_ty); - return integer_zero_node; - } - else - { - /* The sptr field on the lhs will point into the rhs sigtable. */ - undo_casts (sig_ty); - return build_component_ref (rhs, DECL_NAME (first_rhs_field), - NULL_TREE, 0); - } - } - - /* We need to construct a new signature table. */ - result = build_nt (CONSTRUCTOR, NULL_TREE, nreverse (result)); - TREE_HAS_CONSTRUCTOR (result) = 1; - TREE_CONSTANT (result) = !sig_ptr_p; - - undo_casts (sig_ty); - return result; -} - -/* Build a signature table declaration and initialize it or return an - existing one if we built one already. If we don't get a constructor - as initialization expression, we don't need a new signature table - variable and just hand back the init expression. - - The declaration processing is done by hand instead of using `cp_finish_decl' - so that we can make signature pointers global variables instead of - static ones. */ - -static tree -build_sigtable (sig_type, rhs_type, init_from) - tree sig_type, rhs_type, init_from; -{ - tree name = NULL_TREE; - tree decl = NULL_TREE; - tree init_expr; - - push_obstacks_nochange (); - end_temporary_allocation (); - - if (! IS_SIGNATURE (rhs_type)) - { - name = get_sigtable_name (sig_type, rhs_type); - decl = IDENTIFIER_GLOBAL_VALUE (name); - } - if (decl == NULL_TREE) - { - tree init = NULL_TREE; - - /* We allow only one signature table to be generated for signatures - with opaque types. Otherwise we create a loophole in the type - system since we could cast data from one classes implementation - of the opaque type to that of another class. */ - if (SIGNATURE_HAS_OPAQUE_TYPEDECLS (sig_type) - && SIGTABLE_HAS_BEEN_GENERATED (sig_type)) - { - error ("signature with opaque type implemented by multiple classes"); - return error_mark_node; - } - SIGTABLE_HAS_BEEN_GENERATED (sig_type) = 1; - - init_expr = build_signature_table_constructor (sig_type, init_from); - if (init_expr == NULL_TREE || TREE_CODE (init_expr) != CONSTRUCTOR) - return init_expr; - - if (name == NULL_TREE) - name = get_sigtable_name (sig_type, rhs_type); - { - tree context = current_function_decl; - - /* Make the signature table global, not just static in whichever - function a signature pointer/ref is used for the first time. */ - current_function_decl = NULL_TREE; - decl = pushdecl_top_level (build_decl (VAR_DECL, name, sig_type)); - current_function_decl = context; - } - SET_IDENTIFIER_GLOBAL_VALUE (name, decl); - store_init_value (decl, init_expr); - if (IS_SIGNATURE (rhs_type)) - { - init = DECL_INITIAL (decl); - DECL_INITIAL (decl) = error_mark_node; - } - - DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node), - DECL_ALIGN (decl)); -#if 0 - /* GDB-4.7 doesn't find the initialization value of a signature table - when it is constant. */ - TREE_READONLY (decl) = 1; -#endif - TREE_STATIC (decl) = 1; - TREE_USED (decl) = 1; - - make_decl_rtl (decl, NULL, 1); - if (IS_SIGNATURE (rhs_type)) - expand_static_init (decl, init); - } - - pop_obstacks (); - - return decl; -} - -/* Create a constructor or modify expression if the LHS of an assignment - is a signature pointer or a signature reference. If LHS is a record - type node, we build a constructor, otherwise a compound expression. */ - -tree -build_signature_pointer_constructor (lhs, rhs) - tree lhs, rhs; -{ - register struct obstack *ambient_obstack = current_obstack; - register struct obstack *ambient_saveable_obstack = saveable_obstack; - int initp = (TREE_CODE (lhs) == RECORD_TYPE); - tree lhstype = initp ? lhs : TREE_TYPE (lhs); - tree rhstype = TREE_TYPE (rhs); - tree sig_ty = SIGNATURE_TYPE (lhstype); - tree sig_tbl, sptr_expr, optr_expr; - tree result; - - if (! ((TREE_CODE (rhstype) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (rhstype)) == RECORD_TYPE) - || (TYPE_LANG_SPECIFIC (rhstype) - && (IS_SIGNATURE_POINTER (rhstype) - || IS_SIGNATURE_REFERENCE (rhstype))))) - { - error ("invalid assignment to signature pointer or reference"); - return error_mark_node; - } - - if (TYPE_SIZE (sig_ty) == NULL_TREE) - { - cp_error ("undefined signature `%T' used in signature %s declaration", - sig_ty, - IS_SIGNATURE_POINTER (lhstype) ? "pointer" : "reference"); - return error_mark_node; - } - - /* If SIG_TY is permanent, make the signature table constructor and - the signature pointer/reference constructor permanent too. */ - if (TREE_PERMANENT (sig_ty)) - { - current_obstack = &permanent_obstack; - saveable_obstack = &permanent_obstack; - } - - if (TYPE_LANG_SPECIFIC (rhstype) - && (IS_SIGNATURE_POINTER (rhstype) || IS_SIGNATURE_REFERENCE (rhstype))) - { - if (SIGNATURE_TYPE (rhstype) == sig_ty) - { - /* LHS and RHS are signature pointers/refs of the same signature. */ - optr_expr = build_optr_ref (rhs); - sptr_expr = build_sptr_ref (rhs); - } - else - { - /* We need to create a new signature table and copy - elements from the rhs signature table. */ - tree rhs_sptr_ref = build_sptr_ref (rhs); - tree rhs_tbl = build1 (INDIRECT_REF, SIGNATURE_TYPE (rhstype), - rhs_sptr_ref); - - sig_tbl = build_sigtable (sig_ty, SIGNATURE_TYPE (rhstype), rhs_tbl); - if (sig_tbl == error_mark_node) - return error_mark_node; - - optr_expr = build_optr_ref (rhs); - if (sig_tbl == NULL_TREE) - /* The signature was empty. The signature pointer is - pretty useless, but the user has been warned. */ - sptr_expr = copy_node (null_pointer_node); - else if (sig_tbl == integer_zero_node) - sptr_expr = rhs_sptr_ref; - else - sptr_expr = build_unary_op (ADDR_EXPR, sig_tbl, 0); - TREE_TYPE (sptr_expr) = build_pointer_type (sig_ty); - } - } - else - { - sig_tbl = build_sigtable (sig_ty, TREE_TYPE (rhstype), rhs); - if (sig_tbl == error_mark_node) - return error_mark_node; - - optr_expr = rhs; - if (sig_tbl == NULL_TREE) - /* The signature was empty. The signature pointer is - pretty useless, but the user has been warned. */ - { - sptr_expr = copy_node (null_pointer_node); - TREE_TYPE (sptr_expr) = build_pointer_type (sig_ty); - } - else - sptr_expr = build_unary_op (ADDR_EXPR, sig_tbl, 0); - } - - if (initp) - { - result = tree_cons (NULL_TREE, optr_expr, - build_tree_list (NULL_TREE, sptr_expr)); - result = build_nt (CONSTRUCTOR, NULL_TREE, result); - result = digest_init (lhstype, result, 0); - } - else - { - if (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype)) - readonly_error (lhs, "assignment", 0); - - optr_expr = build_modify_expr (build_optr_ref (lhs), NOP_EXPR, - optr_expr); - sptr_expr = build_modify_expr (build_sptr_ref (lhs), NOP_EXPR, - sptr_expr); - - result = tree_cons (NULL_TREE, optr_expr, - tree_cons (NULL_TREE, sptr_expr, - build_tree_list (NULL_TREE, lhs))); - result = build_compound_expr (result); - } - - current_obstack = ambient_obstack; - saveable_obstack = ambient_saveable_obstack; - return result; -} - -/* Build a temporary variable declaration for the instance of a signature - member function call if it isn't a declaration node already. Simply - using a SAVE_EXPR doesn't work since we need `this' in both branches - of a conditional expression. */ - -static tree -save_this (instance) - tree instance; -{ - tree decl; - - if (TREE_CODE_CLASS (TREE_CODE (instance)) == 'd') - decl = instance; - else - { - decl = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (instance)); - DECL_REGISTER (decl) = 1; - layout_decl (decl, 0); - expand_decl (decl); - } - - return decl; -} - -/* Build a signature member function call. Looks up the signature table - entry corresponding to FUNCTION. Depending on the value of the CODE - field, either call the function in PFN directly, or use OFFSET to - index the object's virtual function table. */ - -tree -build_signature_method_call (function, parms) - tree function, parms; -{ - tree instance = TREE_VALUE (parms); - tree saved_instance = save_this (instance); /* Create temp for `this'. */ - tree object_ptr = build_optr_ref (saved_instance); - tree new_object_ptr, new_parms; - tree signature_tbl_ptr = build_sptr_ref (saved_instance); - tree sig_field_name = DECL_NAME (DECL_MEMFUNC_POINTER_TO (function)); - tree basetype = DECL_CONTEXT (function); - tree basetype_path = TYPE_BINFO (basetype); - tree tbl_entry = build_component_ref (build1 (INDIRECT_REF, basetype, - signature_tbl_ptr), - sig_field_name, basetype_path, 1); - tree tag, delta, pfn, vt_off, idx, vfn; - tree deflt_call = NULL_TREE, direct_call, virtual_call, result; - - tbl_entry = save_expr (tbl_entry); - tag = build_component_ref (tbl_entry, tag_identifier, NULL_TREE, 1); - delta = build_component_ref (tbl_entry, delta_identifier, NULL_TREE, 1); - pfn = build_component_ref (tbl_entry, pfn_identifier, NULL_TREE, 1); - vt_off = build_component_ref (tbl_entry, vt_off_identifier, NULL_TREE, 1); - idx = build_component_ref (tbl_entry, index_identifier, NULL_TREE, 1); - TREE_TYPE (pfn) = build_pointer_type (TREE_TYPE (function)); - - if (IS_DEFAULT_IMPLEMENTATION (function)) - { - pfn = save_expr (pfn); - deflt_call = build_function_call (pfn, parms); - } - - new_object_ptr = build (PLUS_EXPR, build_pointer_type (basetype), - cp_convert (ptrdiff_type_node, object_ptr), - cp_convert (ptrdiff_type_node, delta)); - - parms = tree_cons (NULL_TREE, - cp_convert (build_pointer_type (basetype), object_ptr), - TREE_CHAIN (parms)); - new_parms = tree_cons (NULL_TREE, new_object_ptr, TREE_CHAIN (parms)); - - { - /* Cast the signature method to have `this' of a normal pointer type. */ - tree old_this = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn)))); - - TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn)))) - = build_qualified_type (build_pointer_type (basetype), - TYPE_QUALS (old_this)); - - direct_call = build_function_call (pfn, new_parms); - - { - tree vfld, vtbl, aref; - - vfld = build (PLUS_EXPR, - build_pointer_type (build_pointer_type (vtbl_type_node)), - cp_convert (ptrdiff_type_node, object_ptr), - cp_convert (ptrdiff_type_node, vt_off)); - vtbl = build_indirect_ref (build_indirect_ref (vfld, NULL_PTR), - NULL_PTR); - aref = build_array_ref (vtbl, idx); - - if (flag_vtable_thunks) - vfn = aref; - else - vfn = build_component_ref (aref, pfn_identifier, NULL_TREE, 0); - - TREE_TYPE (vfn) = build_pointer_type (TREE_TYPE (function)); - - virtual_call = build_function_call (vfn, new_parms); - } - - /* Undo the cast, make `this' a signature pointer again. */ - TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn)))) = old_this; - } - - /* Once the function was found, there should be no reason why we - couldn't build the member function pointer call. */ - if (!direct_call || direct_call == error_mark_node - || !virtual_call || virtual_call == error_mark_node - || (IS_DEFAULT_IMPLEMENTATION (function) - && (!deflt_call || deflt_call == error_mark_node))) - { - compiler_error ("cannot build call of signature member function `%s'", - fndecl_as_string (function, 1)); - return error_mark_node; - } - - if (IS_DEFAULT_IMPLEMENTATION (function)) - { - tree test = build_binary_op_nodefault (LT_EXPR, tag, integer_zero_node, - LT_EXPR); - result = build_conditional_expr (tag, - build_conditional_expr (test, - deflt_call, - virtual_call), - direct_call); - } - else - result = build_conditional_expr (tag, virtual_call, direct_call); - - /* If we created a temporary variable for `this', initialize it first. */ - if (instance != saved_instance) - result = build (COMPOUND_EXPR, TREE_TYPE (result), - build_modify_expr (saved_instance, NOP_EXPR, instance), - result); - - return result; -} - -/* Create a COMPONENT_REF expression for referencing the OPTR field - of a signature pointer or reference. */ - -tree -build_optr_ref (instance) - tree instance; -{ - tree field = get_identifier (SIGNATURE_OPTR_NAME); - - return build_component_ref (instance, field, NULL_TREE, 1); -} - -/* Create a COMPONENT_REF expression for referencing the SPTR field - of a signature pointer or reference. */ - -static tree -build_sptr_ref (instance) - tree instance; -{ - tree field = get_identifier (SIGNATURE_SPTR_NAME); - - return build_component_ref (instance, field, NULL_TREE, 1); -} |