| /* Language-dependent node constructors for parse phase of GNU compiler. |
| Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, |
| 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. |
| Hacked 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) |
| any later version. |
| |
| GCC 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 GCC; 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 "coretypes.h" |
| #include "tm.h" |
| #include "tree.h" |
| #include "cp-tree.h" |
| #include "flags.h" |
| #include "real.h" |
| #include "rtl.h" |
| #include "toplev.h" |
| #include "insn-config.h" |
| #include "integrate.h" |
| #include "tree-inline.h" |
| /* APPLE LOCAL mainline */ |
| #include "debug.h" |
| #include "target.h" |
| |
| static tree bot_manip (tree *, int *, void *); |
| static tree bot_replace (tree *, int *, void *); |
| static tree build_cplus_array_type_1 (tree, tree); |
| static int list_hash_eq (const void *, const void *); |
| static hashval_t list_hash_pieces (tree, tree, tree); |
| static hashval_t list_hash (const void *); |
| static cp_lvalue_kind lvalue_p_1 (tree, int); |
| static tree build_target_expr (tree, tree); |
| static tree count_trees_r (tree *, int *, void *); |
| static tree verify_stmt_tree_r (tree *, int *, void *); |
| static tree find_tree_r (tree *, int *, void *); |
| static tree build_local_temp (tree); |
| |
| static tree handle_java_interface_attribute (tree *, tree, tree, int, bool *); |
| static tree handle_com_interface_attribute (tree *, tree, tree, int, bool *); |
| static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *); |
| |
| /* If REF is an lvalue, returns the kind of lvalue that REF is. |
| Otherwise, returns clk_none. If TREAT_CLASS_RVALUES_AS_LVALUES is |
| nonzero, rvalues of class type are considered lvalues. */ |
| |
| static cp_lvalue_kind |
| lvalue_p_1 (tree ref, |
| int treat_class_rvalues_as_lvalues) |
| { |
| cp_lvalue_kind op1_lvalue_kind = clk_none; |
| cp_lvalue_kind op2_lvalue_kind = clk_none; |
| |
| if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE) |
| return clk_ordinary; |
| |
| if (ref == current_class_ptr) |
| return clk_none; |
| |
| switch (TREE_CODE (ref)) |
| { |
| /* preincrements and predecrements are valid lvals, provided |
| what they refer to are valid lvals. */ |
| case PREINCREMENT_EXPR: |
| case PREDECREMENT_EXPR: |
| case SAVE_EXPR: |
| case TRY_CATCH_EXPR: |
| case WITH_CLEANUP_EXPR: |
| case REALPART_EXPR: |
| case IMAGPART_EXPR: |
| return lvalue_p_1 (TREE_OPERAND (ref, 0), |
| treat_class_rvalues_as_lvalues); |
| |
| case COMPONENT_REF: |
| op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0), |
| treat_class_rvalues_as_lvalues); |
| /* In an expression of the form "X.Y", the packed-ness of the |
| expression does not depend on "X". */ |
| op1_lvalue_kind &= ~clk_packed; |
| /* Look at the member designator. */ |
| if (!op1_lvalue_kind |
| /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some |
| situations. */ |
| || TREE_CODE (TREE_OPERAND (ref, 1)) != FIELD_DECL) |
| ; |
| else if (DECL_C_BIT_FIELD (TREE_OPERAND (ref, 1))) |
| { |
| /* Clear the ordinary bit. If this object was a class |
| rvalue we want to preserve that information. */ |
| op1_lvalue_kind &= ~clk_ordinary; |
| /* The lvalue is for a bitfield. */ |
| op1_lvalue_kind |= clk_bitfield; |
| } |
| else if (DECL_PACKED (TREE_OPERAND (ref, 1))) |
| op1_lvalue_kind |= clk_packed; |
| |
| return op1_lvalue_kind; |
| |
| case STRING_CST: |
| return clk_ordinary; |
| |
| /* APPLE LOCAL mainline */ |
| case CONST_DECL: |
| case VAR_DECL: |
| if (TREE_READONLY (ref) && ! TREE_STATIC (ref) |
| && DECL_LANG_SPECIFIC (ref) |
| && DECL_IN_AGGR_P (ref)) |
| return clk_none; |
| case INDIRECT_REF: |
| case ARRAY_REF: |
| case PARM_DECL: |
| case RESULT_DECL: |
| if (TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE) |
| return clk_ordinary; |
| break; |
| |
| /* A currently unresolved scope ref. */ |
| case SCOPE_REF: |
| gcc_unreachable (); |
| case MAX_EXPR: |
| case MIN_EXPR: |
| /* Disallow <? and >? as lvalues if either argument side-effects. */ |
| if (TREE_SIDE_EFFECTS (TREE_OPERAND (ref, 0)) |
| || TREE_SIDE_EFFECTS (TREE_OPERAND (ref, 1))) |
| return clk_none; |
| op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0), |
| treat_class_rvalues_as_lvalues); |
| op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1), |
| treat_class_rvalues_as_lvalues); |
| break; |
| |
| case COND_EXPR: |
| op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1), |
| treat_class_rvalues_as_lvalues); |
| op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 2), |
| treat_class_rvalues_as_lvalues); |
| break; |
| |
| case MODIFY_EXPR: |
| return clk_ordinary; |
| |
| case COMPOUND_EXPR: |
| return lvalue_p_1 (TREE_OPERAND (ref, 1), |
| treat_class_rvalues_as_lvalues); |
| |
| case TARGET_EXPR: |
| return treat_class_rvalues_as_lvalues ? clk_class : clk_none; |
| |
| case CALL_EXPR: |
| case VA_ARG_EXPR: |
| /* Any class-valued call would be wrapped in a TARGET_EXPR. */ |
| return clk_none; |
| |
| case FUNCTION_DECL: |
| /* All functions (except non-static-member functions) are |
| lvalues. */ |
| return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref) |
| ? clk_none : clk_ordinary); |
| |
| case NON_DEPENDENT_EXPR: |
| /* We must consider NON_DEPENDENT_EXPRs to be lvalues so that |
| things like "&E" where "E" is an expression with a |
| non-dependent type work. It is safe to be lenient because an |
| error will be issued when the template is instantiated if "E" |
| is not an lvalue. */ |
| return clk_ordinary; |
| |
| default: |
| break; |
| } |
| |
| /* If one operand is not an lvalue at all, then this expression is |
| not an lvalue. */ |
| if (!op1_lvalue_kind || !op2_lvalue_kind) |
| return clk_none; |
| |
| /* Otherwise, it's an lvalue, and it has all the odd properties |
| contributed by either operand. */ |
| op1_lvalue_kind = op1_lvalue_kind | op2_lvalue_kind; |
| /* It's not an ordinary lvalue if it involves either a bit-field or |
| a class rvalue. */ |
| if ((op1_lvalue_kind & ~clk_ordinary) != clk_none) |
| op1_lvalue_kind &= ~clk_ordinary; |
| return op1_lvalue_kind; |
| } |
| |
| /* Returns the kind of lvalue that REF is, in the sense of |
| [basic.lval]. This function should really be named lvalue_p; it |
| computes the C++ definition of lvalue. */ |
| |
| cp_lvalue_kind |
| real_lvalue_p (tree ref) |
| { |
| return lvalue_p_1 (ref, |
| /*treat_class_rvalues_as_lvalues=*/0); |
| } |
| |
| /* This differs from real_lvalue_p in that class rvalues are |
| considered lvalues. */ |
| |
| int |
| lvalue_p (tree ref) |
| { |
| return |
| (lvalue_p_1 (ref, /*class rvalue ok*/ 1) != clk_none); |
| } |
| |
| /* Test whether DECL is a builtin that may appear in a |
| constant-expression. */ |
| |
| bool |
| builtin_valid_in_constant_expr_p (tree decl) |
| { |
| /* At present BUILT_IN_CONSTANT_P is the only builtin we're allowing |
| in constant-expressions. We may want to add other builtins later. */ |
| return DECL_IS_BUILTIN_CONSTANT_P (decl); |
| } |
| |
| /* Build a TARGET_EXPR, initializing the DECL with the VALUE. */ |
| |
| static tree |
| build_target_expr (tree decl, tree value) |
| { |
| tree t; |
| |
| t = build4 (TARGET_EXPR, TREE_TYPE (decl), decl, value, |
| cxx_maybe_build_cleanup (decl), NULL_TREE); |
| /* We always set TREE_SIDE_EFFECTS so that expand_expr does not |
| ignore the TARGET_EXPR. If there really turn out to be no |
| side-effects, then the optimizer should be able to get rid of |
| whatever code is generated anyhow. */ |
| TREE_SIDE_EFFECTS (t) = 1; |
| |
| return t; |
| } |
| |
| /* Return an undeclared local temporary of type TYPE for use in building a |
| TARGET_EXPR. */ |
| |
| static tree |
| build_local_temp (tree type) |
| { |
| tree slot = build_decl (VAR_DECL, NULL_TREE, type); |
| DECL_ARTIFICIAL (slot) = 1; |
| DECL_IGNORED_P (slot) = 1; |
| DECL_CONTEXT (slot) = current_function_decl; |
| layout_decl (slot, 0); |
| return slot; |
| } |
| |
| /* INIT is a CALL_EXPR which needs info about its target. |
| TYPE is the type that this initialization should appear to have. |
| |
| Build an encapsulation of the initialization to perform |
| and return it so that it can be processed by language-independent |
| and language-specific expression expanders. */ |
| |
| tree |
| build_cplus_new (tree type, tree init) |
| { |
| tree fn; |
| tree slot; |
| tree rval; |
| int is_ctor; |
| |
| /* Make sure that we're not trying to create an instance of an |
| abstract class. */ |
| abstract_virtuals_error (NULL_TREE, type); |
| |
| if (TREE_CODE (init) != CALL_EXPR && TREE_CODE (init) != AGGR_INIT_EXPR) |
| return convert (type, init); |
| |
| fn = TREE_OPERAND (init, 0); |
| is_ctor = (TREE_CODE (fn) == ADDR_EXPR |
| && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL |
| && DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0))); |
| |
| slot = build_local_temp (type); |
| |
| /* We split the CALL_EXPR into its function and its arguments here. |
| Then, in expand_expr, we put them back together. The reason for |
| this is that this expression might be a default argument |
| expression. In that case, we need a new temporary every time the |
| expression is used. That's what break_out_target_exprs does; it |
| replaces every AGGR_INIT_EXPR with a copy that uses a fresh |
| temporary slot. Then, expand_expr builds up a call-expression |
| using the new slot. */ |
| |
| /* If we don't need to use a constructor to create an object of this |
| type, don't mess with AGGR_INIT_EXPR. */ |
| if (is_ctor || TREE_ADDRESSABLE (type)) |
| { |
| rval = build3 (AGGR_INIT_EXPR, void_type_node, fn, |
| TREE_OPERAND (init, 1), slot); |
| TREE_SIDE_EFFECTS (rval) = 1; |
| AGGR_INIT_VIA_CTOR_P (rval) = is_ctor; |
| } |
| else |
| rval = init; |
| |
| rval = build_target_expr (slot, rval); |
| /* APPLE LOCAL mainline 2006-09-08 4658012 */ |
| TARGET_EXPR_IMPLICIT_P (rval) = 1; |
| |
| return rval; |
| } |
| |
| /* Build a TARGET_EXPR using INIT to initialize a new temporary of the |
| indicated TYPE. */ |
| |
| tree |
| build_target_expr_with_type (tree init, tree type) |
| { |
| tree slot; |
| |
| gcc_assert (!VOID_TYPE_P (type)); |
| |
| if (TREE_CODE (init) == TARGET_EXPR) |
| return init; |
| else if (CLASS_TYPE_P (type) && !TYPE_HAS_TRIVIAL_INIT_REF (type) |
| && TREE_CODE (init) != COND_EXPR |
| && TREE_CODE (init) != CONSTRUCTOR |
| && TREE_CODE (init) != VA_ARG_EXPR) |
| /* We need to build up a copy constructor call. COND_EXPR is a special |
| case because we already have copies on the arms and we don't want |
| another one here. A CONSTRUCTOR is aggregate initialization, which |
| is handled separately. A VA_ARG_EXPR is magic creation of an |
| aggregate; there's no additional work to be done. */ |
| return force_rvalue (init); |
| |
| slot = build_local_temp (type); |
| return build_target_expr (slot, init); |
| } |
| |
| /* Like the above function, but without the checking. This function should |
| only be used by code which is deliberately trying to subvert the type |
| system, such as call_builtin_trap. */ |
| |
| tree |
| force_target_expr (tree type, tree init) |
| { |
| tree slot; |
| |
| gcc_assert (!VOID_TYPE_P (type)); |
| |
| slot = build_local_temp (type); |
| return build_target_expr (slot, init); |
| } |
| |
| /* Like build_target_expr_with_type, but use the type of INIT. */ |
| |
| tree |
| get_target_expr (tree init) |
| { |
| return build_target_expr_with_type (init, TREE_TYPE (init)); |
| } |
| |
| |
| static tree |
| build_cplus_array_type_1 (tree elt_type, tree index_type) |
| { |
| tree t; |
| |
| if (elt_type == error_mark_node || index_type == error_mark_node) |
| return error_mark_node; |
| |
| if (dependent_type_p (elt_type) |
| || (index_type |
| && value_dependent_expression_p (TYPE_MAX_VALUE (index_type)))) |
| { |
| t = make_node (ARRAY_TYPE); |
| TREE_TYPE (t) = elt_type; |
| TYPE_DOMAIN (t) = index_type; |
| } |
| else |
| t = build_array_type (elt_type, index_type); |
| |
| /* Push these needs up so that initialization takes place |
| more easily. */ |
| TYPE_NEEDS_CONSTRUCTING (t) |
| = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type)); |
| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) |
| = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type)); |
| return t; |
| } |
| |
| tree |
| build_cplus_array_type (tree elt_type, tree index_type) |
| { |
| tree t; |
| int type_quals = cp_type_quals (elt_type); |
| |
| if (type_quals != TYPE_UNQUALIFIED) |
| elt_type = cp_build_qualified_type (elt_type, TYPE_UNQUALIFIED); |
| |
| t = build_cplus_array_type_1 (elt_type, index_type); |
| |
| if (type_quals != TYPE_UNQUALIFIED) |
| t = cp_build_qualified_type (t, type_quals); |
| |
| return t; |
| } |
| |
| /* Make a variant of TYPE, qualified with the TYPE_QUALS. Handles |
| arrays correctly. In particular, if TYPE is an array of T's, and |
| TYPE_QUALS is non-empty, returns an array of qualified T's. |
| |
| FLAGS determines how to deal with illformed qualifications. If |
| tf_ignore_bad_quals is set, then bad qualifications are dropped |
| (this is permitted if TYPE was introduced via a typedef or template |
| type parameter). If bad qualifications are dropped and tf_warning |
| is set, then a warning is issued for non-const qualifications. If |
| tf_ignore_bad_quals is not set and tf_error is not set, we |
| return error_mark_node. Otherwise, we issue an error, and ignore |
| the qualifications. |
| |
| Qualification of a reference type is valid when the reference came |
| via a typedef or template type argument. [dcl.ref] No such |
| dispensation is provided for qualifying a function type. [dcl.fct] |
| DR 295 queries this and the proposed resolution brings it into line |
| with qualifying a reference. We implement the DR. We also behave |
| in a similar manner for restricting non-pointer types. */ |
| |
| tree |
| cp_build_qualified_type_real (tree type, |
| int type_quals, |
| tsubst_flags_t complain) |
| { |
| tree result; |
| int bad_quals = TYPE_UNQUALIFIED; |
| |
| if (type == error_mark_node) |
| return type; |
| |
| if (type_quals == cp_type_quals (type)) |
| return type; |
| |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| /* In C++, the qualification really applies to the array element |
| type. Obtain the appropriately qualified element type. */ |
| tree t; |
| tree element_type |
| = cp_build_qualified_type_real (TREE_TYPE (type), |
| type_quals, |
| complain); |
| |
| if (element_type == error_mark_node) |
| return error_mark_node; |
| |
| /* See if we already have an identically qualified type. */ |
| for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) |
| if (cp_type_quals (t) == type_quals |
| && TYPE_NAME (t) == TYPE_NAME (type) |
| && TYPE_CONTEXT (t) == TYPE_CONTEXT (type)) |
| break; |
| |
| if (!t) |
| { |
| /* Make a new array type, just like the old one, but with the |
| appropriately qualified element type. */ |
| t = build_variant_type_copy (type); |
| TREE_TYPE (t) = element_type; |
| } |
| |
| /* Even if we already had this variant, we update |
| TYPE_NEEDS_CONSTRUCTING and TYPE_HAS_NONTRIVIAL_DESTRUCTOR in case |
| they changed since the variant was originally created. |
| |
| This seems hokey; if there is some way to use a previous |
| variant *without* coming through here, |
| TYPE_NEEDS_CONSTRUCTING will never be updated. */ |
| TYPE_NEEDS_CONSTRUCTING (t) |
| = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (element_type)); |
| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) |
| = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type)); |
| return t; |
| } |
| else if (TYPE_PTRMEMFUNC_P (type)) |
| { |
| /* For a pointer-to-member type, we can't just return a |
| cv-qualified version of the RECORD_TYPE. If we do, we |
| haven't changed the field that contains the actual pointer to |
| a method, and so TYPE_PTRMEMFUNC_FN_TYPE will be wrong. */ |
| tree t; |
| |
| t = TYPE_PTRMEMFUNC_FN_TYPE (type); |
| t = cp_build_qualified_type_real (t, type_quals, complain); |
| return build_ptrmemfunc_type (t); |
| } |
| |
| /* A reference or method type shall not be cv qualified. |
| [dcl.ref], [dct.fct] */ |
| if (type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE) |
| && (TREE_CODE (type) == REFERENCE_TYPE |
| || TREE_CODE (type) == METHOD_TYPE)) |
| { |
| bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); |
| type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); |
| } |
| |
| /* A restrict-qualified type must be a pointer (or reference) |
| to object or incomplete type, or a function type. */ |
| if ((type_quals & TYPE_QUAL_RESTRICT) |
| && TREE_CODE (type) != TEMPLATE_TYPE_PARM |
| && TREE_CODE (type) != TYPENAME_TYPE |
| && TREE_CODE (type) != FUNCTION_TYPE |
| && !POINTER_TYPE_P (type)) |
| { |
| bad_quals |= TYPE_QUAL_RESTRICT; |
| type_quals &= ~TYPE_QUAL_RESTRICT; |
| } |
| |
| if (bad_quals == TYPE_UNQUALIFIED) |
| /*OK*/; |
| else if (!(complain & (tf_error | tf_ignore_bad_quals))) |
| return error_mark_node; |
| else |
| { |
| if (complain & tf_ignore_bad_quals) |
| /* We're not going to warn about constifying things that can't |
| be constified. */ |
| bad_quals &= ~TYPE_QUAL_CONST; |
| if (bad_quals) |
| { |
| tree bad_type = build_qualified_type (ptr_type_node, bad_quals); |
| |
| if (!(complain & tf_ignore_bad_quals)) |
| error ("%qV qualifiers cannot be applied to %qT", |
| bad_type, type); |
| } |
| } |
| |
| /* Retrieve (or create) the appropriately qualified variant. */ |
| result = build_qualified_type (type, type_quals); |
| |
| /* If this was a pointer-to-method type, and we just made a copy, |
| then we need to unshare the record that holds the cached |
| pointer-to-member-function type, because these will be distinct |
| between the unqualified and qualified types. */ |
| if (result != type |
| && TREE_CODE (type) == POINTER_TYPE |
| && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE) |
| TYPE_LANG_SPECIFIC (result) = NULL; |
| |
| return result; |
| } |
| |
| /* Returns the canonical version of TYPE. In other words, if TYPE is |
| a typedef, returns the underlying type. The cv-qualification of |
| the type returned matches the type input; they will always be |
| compatible types. */ |
| |
| tree |
| canonical_type_variant (tree t) |
| { |
| return cp_build_qualified_type (TYPE_MAIN_VARIANT (t), cp_type_quals (t)); |
| } |
| |
| /* Makes a copy of BINFO and TYPE, which is to be inherited into a |
| graph dominated by T. If BINFO is NULL, TYPE is a dependent base, |
| and we do a shallow copy. If BINFO is non-NULL, we do a deep copy. |
| VIRT indicates whether TYPE is inherited virtually or not. |
| IGO_PREV points at the previous binfo of the inheritance graph |
| order chain. The newly copied binfo's TREE_CHAIN forms this |
| ordering. |
| |
| The CLASSTYPE_VBASECLASSES vector of T is constructed in the |
| correct order. That is in the order the bases themselves should be |
| constructed in. |
| |
| The BINFO_INHERITANCE of a virtual base class points to the binfo |
| of the most derived type. ??? We could probably change this so that |
| BINFO_INHERITANCE becomes synonymous with BINFO_PRIMARY, and hence |
| remove a field. They currently can only differ for primary virtual |
| virtual bases. */ |
| |
| tree |
| copy_binfo (tree binfo, tree type, tree t, tree *igo_prev, int virt) |
| { |
| tree new_binfo; |
| |
| if (virt) |
| { |
| /* See if we've already made this virtual base. */ |
| new_binfo = binfo_for_vbase (type, t); |
| if (new_binfo) |
| return new_binfo; |
| } |
| |
| new_binfo = make_tree_binfo (binfo ? BINFO_N_BASE_BINFOS (binfo) : 0); |
| BINFO_TYPE (new_binfo) = type; |
| |
| /* Chain it into the inheritance graph. */ |
| TREE_CHAIN (*igo_prev) = new_binfo; |
| *igo_prev = new_binfo; |
| |
| if (binfo) |
| { |
| int ix; |
| tree base_binfo; |
| |
| gcc_assert (!BINFO_DEPENDENT_BASE_P (binfo)); |
| gcc_assert (SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), type)); |
| |
| BINFO_OFFSET (new_binfo) = BINFO_OFFSET (binfo); |
| BINFO_VIRTUALS (new_binfo) = BINFO_VIRTUALS (binfo); |
| |
| /* We do not need to copy the accesses, as they are read only. */ |
| BINFO_BASE_ACCESSES (new_binfo) = BINFO_BASE_ACCESSES (binfo); |
| |
| /* Recursively copy base binfos of BINFO. */ |
| for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++) |
| { |
| tree new_base_binfo; |
| |
| gcc_assert (!BINFO_DEPENDENT_BASE_P (base_binfo)); |
| new_base_binfo = copy_binfo (base_binfo, BINFO_TYPE (base_binfo), |
| t, igo_prev, |
| BINFO_VIRTUAL_P (base_binfo)); |
| |
| if (!BINFO_INHERITANCE_CHAIN (new_base_binfo)) |
| BINFO_INHERITANCE_CHAIN (new_base_binfo) = new_binfo; |
| BINFO_BASE_APPEND (new_binfo, new_base_binfo); |
| } |
| } |
| else |
| BINFO_DEPENDENT_BASE_P (new_binfo) = 1; |
| |
| if (virt) |
| { |
| /* Push it onto the list after any virtual bases it contains |
| will have been pushed. */ |
| VEC_quick_push (tree, CLASSTYPE_VBASECLASSES (t), new_binfo); |
| BINFO_VIRTUAL_P (new_binfo) = 1; |
| BINFO_INHERITANCE_CHAIN (new_binfo) = TYPE_BINFO (t); |
| } |
| |
| return new_binfo; |
| } |
| |
| /* Hashing of lists so that we don't make duplicates. |
| The entry point is `list_hash_canon'. */ |
| |
| /* Now here is the hash table. When recording a list, it is added |
| to the slot whose index is the hash code mod the table size. |
| Note that the hash table is used for several kinds of lists. |
| While all these live in the same table, they are completely independent, |
| and the hash code is computed differently for each of these. */ |
| |
| static GTY ((param_is (union tree_node))) htab_t list_hash_table; |
| |
| struct list_proxy |
| { |
| tree purpose; |
| tree value; |
| tree chain; |
| }; |
| |
| /* Compare ENTRY (an entry in the hash table) with DATA (a list_proxy |
| for a node we are thinking about adding). */ |
| |
| static int |
| list_hash_eq (const void* entry, const void* data) |
| { |
| tree t = (tree) entry; |
| struct list_proxy *proxy = (struct list_proxy *) data; |
| |
| return (TREE_VALUE (t) == proxy->value |
| && TREE_PURPOSE (t) == proxy->purpose |
| && TREE_CHAIN (t) == proxy->chain); |
| } |
| |
| /* Compute a hash code for a list (chain of TREE_LIST nodes |
| with goodies in the TREE_PURPOSE, TREE_VALUE, and bits of the |
| TREE_COMMON slots), by adding the hash codes of the individual entries. */ |
| |
| static hashval_t |
| list_hash_pieces (tree purpose, tree value, tree chain) |
| { |
| hashval_t hashcode = 0; |
| |
| if (chain) |
| hashcode += TREE_HASH (chain); |
| |
| if (value) |
| hashcode += TREE_HASH (value); |
| else |
| hashcode += 1007; |
| if (purpose) |
| hashcode += TREE_HASH (purpose); |
| else |
| hashcode += 1009; |
| return hashcode; |
| } |
| |
| /* Hash an already existing TREE_LIST. */ |
| |
| static hashval_t |
| list_hash (const void* p) |
| { |
| tree t = (tree) p; |
| return list_hash_pieces (TREE_PURPOSE (t), |
| TREE_VALUE (t), |
| TREE_CHAIN (t)); |
| } |
| |
| /* Given list components PURPOSE, VALUE, AND CHAIN, return the canonical |
| object for an identical list if one already exists. Otherwise, build a |
| new one, and record it as the canonical object. */ |
| |
| tree |
| hash_tree_cons (tree purpose, tree value, tree chain) |
| { |
| int hashcode = 0; |
| void **slot; |
| struct list_proxy proxy; |
| |
| /* Hash the list node. */ |
| hashcode = list_hash_pieces (purpose, value, chain); |
| /* Create a proxy for the TREE_LIST we would like to create. We |
| don't actually create it so as to avoid creating garbage. */ |
| proxy.purpose = purpose; |
| proxy.value = value; |
| proxy.chain = chain; |
| /* See if it is already in the table. */ |
| slot = htab_find_slot_with_hash (list_hash_table, &proxy, hashcode, |
| INSERT); |
| /* If not, create a new node. */ |
| if (!*slot) |
| *slot = tree_cons (purpose, value, chain); |
| return *slot; |
| } |
| |
| /* Constructor for hashed lists. */ |
| |
| tree |
| hash_tree_chain (tree value, tree chain) |
| { |
| return hash_tree_cons (NULL_TREE, value, chain); |
| } |
| |
| void |
| debug_binfo (tree elem) |
| { |
| HOST_WIDE_INT n; |
| tree virtuals; |
| |
| fprintf (stderr, "type \"%s\", offset = " HOST_WIDE_INT_PRINT_DEC |
| "\nvtable type:\n", |
| TYPE_NAME_STRING (BINFO_TYPE (elem)), |
| TREE_INT_CST_LOW (BINFO_OFFSET (elem))); |
| debug_tree (BINFO_TYPE (elem)); |
| if (BINFO_VTABLE (elem)) |
| fprintf (stderr, "vtable decl \"%s\"\n", |
| IDENTIFIER_POINTER (DECL_NAME (get_vtbl_decl_for_binfo (elem)))); |
| else |
| fprintf (stderr, "no vtable decl yet\n"); |
| fprintf (stderr, "virtuals:\n"); |
| virtuals = BINFO_VIRTUALS (elem); |
| n = 0; |
| |
| while (virtuals) |
| { |
| tree fndecl = TREE_VALUE (virtuals); |
| fprintf (stderr, "%s [%ld =? %ld]\n", |
| IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)), |
| (long) n, (long) TREE_INT_CST_LOW (DECL_VINDEX (fndecl))); |
| ++n; |
| virtuals = TREE_CHAIN (virtuals); |
| } |
| } |
| |
| int |
| is_overloaded_fn (tree x) |
| { |
| /* A baselink is also considered an overloaded function. */ |
| if (TREE_CODE (x) == OFFSET_REF) |
| x = TREE_OPERAND (x, 1); |
| if (BASELINK_P (x)) |
| x = BASELINK_FUNCTIONS (x); |
| return (TREE_CODE (x) == FUNCTION_DECL |
| || TREE_CODE (x) == TEMPLATE_ID_EXPR |
| || DECL_FUNCTION_TEMPLATE_P (x) |
| || TREE_CODE (x) == OVERLOAD); |
| } |
| |
| int |
| really_overloaded_fn (tree x) |
| { |
| /* A baselink is also considered an overloaded function. */ |
| if (TREE_CODE (x) == OFFSET_REF) |
| x = TREE_OPERAND (x, 1); |
| if (BASELINK_P (x)) |
| x = BASELINK_FUNCTIONS (x); |
| |
| return ((TREE_CODE (x) == OVERLOAD && OVL_CHAIN (x)) |
| || DECL_FUNCTION_TEMPLATE_P (OVL_CURRENT (x)) |
| || TREE_CODE (x) == TEMPLATE_ID_EXPR); |
| } |
| |
| tree |
| get_first_fn (tree from) |
| { |
| gcc_assert (is_overloaded_fn (from)); |
| /* A baselink is also considered an overloaded function. */ |
| if (BASELINK_P (from)) |
| from = BASELINK_FUNCTIONS (from); |
| return OVL_CURRENT (from); |
| } |
| |
| /* Return a new OVL node, concatenating it with the old one. */ |
| |
| tree |
| ovl_cons (tree decl, tree chain) |
| { |
| tree result = make_node (OVERLOAD); |
| TREE_TYPE (result) = unknown_type_node; |
| OVL_FUNCTION (result) = decl; |
| TREE_CHAIN (result) = chain; |
| |
| return result; |
| } |
| |
| /* Build a new overloaded function. If this is the first one, |
| just return it; otherwise, ovl_cons the _DECLs */ |
| |
| tree |
| build_overload (tree decl, tree chain) |
| { |
| if (! chain && TREE_CODE (decl) != TEMPLATE_DECL) |
| return decl; |
| if (chain && TREE_CODE (chain) != OVERLOAD) |
| chain = ovl_cons (chain, NULL_TREE); |
| return ovl_cons (decl, chain); |
| } |
| |
| |
| #define PRINT_RING_SIZE 4 |
| |
| const char * |
| cxx_printable_name (tree decl, int v) |
| { |
| static tree decl_ring[PRINT_RING_SIZE]; |
| static char *print_ring[PRINT_RING_SIZE]; |
| static int ring_counter; |
| int i; |
| |
| /* Only cache functions. */ |
| if (v < 2 |
| || TREE_CODE (decl) != FUNCTION_DECL |
| || DECL_LANG_SPECIFIC (decl) == 0) |
| return lang_decl_name (decl, v); |
| |
| /* See if this print name is lying around. */ |
| for (i = 0; i < PRINT_RING_SIZE; i++) |
| if (decl_ring[i] == decl) |
| /* yes, so return it. */ |
| return print_ring[i]; |
| |
| if (++ring_counter == PRINT_RING_SIZE) |
| ring_counter = 0; |
| |
| if (current_function_decl != NULL_TREE) |
| { |
| if (decl_ring[ring_counter] == current_function_decl) |
| ring_counter += 1; |
| if (ring_counter == PRINT_RING_SIZE) |
| ring_counter = 0; |
| gcc_assert (decl_ring[ring_counter] != current_function_decl); |
| } |
| |
| if (print_ring[ring_counter]) |
| free (print_ring[ring_counter]); |
| |
| print_ring[ring_counter] = xstrdup (lang_decl_name (decl, v)); |
| decl_ring[ring_counter] = decl; |
| return print_ring[ring_counter]; |
| } |
| |
| /* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions |
| listed in RAISES. */ |
| |
| tree |
| build_exception_variant (tree type, tree raises) |
| { |
| tree v = TYPE_MAIN_VARIANT (type); |
| int type_quals = TYPE_QUALS (type); |
| |
| for (; v; v = TYPE_NEXT_VARIANT (v)) |
| if (check_qualified_type (v, type, type_quals) |
| && comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (v), 1)) |
| return v; |
| |
| /* Need to build a new variant. */ |
| v = build_variant_type_copy (type); |
| TYPE_RAISES_EXCEPTIONS (v) = raises; |
| return v; |
| } |
| |
| /* Given a TEMPLATE_TEMPLATE_PARM node T, create a new |
| BOUND_TEMPLATE_TEMPLATE_PARM bound with NEWARGS as its template |
| arguments. */ |
| |
| tree |
| bind_template_template_parm (tree t, tree newargs) |
| { |
| tree decl = TYPE_NAME (t); |
| tree t2; |
| |
| t2 = make_aggr_type (BOUND_TEMPLATE_TEMPLATE_PARM); |
| decl = build_decl (TYPE_DECL, DECL_NAME (decl), NULL_TREE); |
| |
| /* These nodes have to be created to reflect new TYPE_DECL and template |
| arguments. */ |
| TEMPLATE_TYPE_PARM_INDEX (t2) = copy_node (TEMPLATE_TYPE_PARM_INDEX (t)); |
| TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (t2)) = decl; |
| TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2) |
| = tree_cons (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t), |
| newargs, NULL_TREE); |
| |
| TREE_TYPE (decl) = t2; |
| TYPE_NAME (t2) = decl; |
| TYPE_STUB_DECL (t2) = decl; |
| TYPE_SIZE (t2) = 0; |
| |
| return t2; |
| } |
| |
| /* Called from count_trees via walk_tree. */ |
| |
| static tree |
| count_trees_r (tree *tp, int *walk_subtrees, void *data) |
| { |
| ++*((int *) data); |
| |
| if (TYPE_P (*tp)) |
| *walk_subtrees = 0; |
| |
| return NULL_TREE; |
| } |
| |
| /* Debugging function for measuring the rough complexity of a tree |
| representation. */ |
| |
| int |
| count_trees (tree t) |
| { |
| int n_trees = 0; |
| walk_tree_without_duplicates (&t, count_trees_r, &n_trees); |
| return n_trees; |
| } |
| |
| /* Called from verify_stmt_tree via walk_tree. */ |
| |
| static tree |
| verify_stmt_tree_r (tree* tp, |
| int* walk_subtrees ATTRIBUTE_UNUSED , |
| void* data) |
| { |
| tree t = *tp; |
| htab_t *statements = (htab_t *) data; |
| void **slot; |
| |
| if (!STATEMENT_CODE_P (TREE_CODE (t))) |
| return NULL_TREE; |
| |
| /* If this statement is already present in the hash table, then |
| there is a circularity in the statement tree. */ |
| gcc_assert (!htab_find (*statements, t)); |
| |
| slot = htab_find_slot (*statements, t, INSERT); |
| *slot = t; |
| |
| return NULL_TREE; |
| } |
| |
| /* Debugging function to check that the statement T has not been |
| corrupted. For now, this function simply checks that T contains no |
| circularities. */ |
| |
| void |
| verify_stmt_tree (tree t) |
| { |
| htab_t statements; |
| statements = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL); |
| walk_tree (&t, verify_stmt_tree_r, &statements, NULL); |
| htab_delete (statements); |
| } |
| |
| /* Called from find_tree via walk_tree. */ |
| |
| static tree |
| find_tree_r (tree* tp, |
| int* walk_subtrees ATTRIBUTE_UNUSED , |
| void* data) |
| { |
| if (*tp == (tree) data) |
| return (tree) data; |
| |
| return NULL_TREE; |
| } |
| |
| /* Returns X if X appears in the tree structure rooted at T. */ |
| |
| tree |
| find_tree (tree t, tree x) |
| { |
| return walk_tree_without_duplicates (&t, find_tree_r, x); |
| } |
| |
| /* Check if the type T depends on a type with no linkage and if so, return |
| it. If RELAXED_P then do not consider a class type declared within |
| a TREE_PUBLIC function to have no linkage. */ |
| |
| tree |
| no_linkage_check (tree t, bool relaxed_p) |
| { |
| tree r; |
| |
| /* There's no point in checking linkage on template functions; we |
| can't know their complete types. */ |
| if (processing_template_decl) |
| return NULL_TREE; |
| |
| switch (TREE_CODE (t)) |
| { |
| tree fn; |
| |
| case RECORD_TYPE: |
| if (TYPE_PTRMEMFUNC_P (t)) |
| goto ptrmem; |
| /* Fall through. */ |
| case UNION_TYPE: |
| if (!CLASS_TYPE_P (t)) |
| return NULL_TREE; |
| /* Fall through. */ |
| case ENUMERAL_TYPE: |
| if (TYPE_ANONYMOUS_P (t)) |
| return t; |
| fn = decl_function_context (TYPE_MAIN_DECL (t)); |
| if (fn && (!relaxed_p || !TREE_PUBLIC (fn))) |
| return t; |
| return NULL_TREE; |
| |
| case ARRAY_TYPE: |
| case POINTER_TYPE: |
| case REFERENCE_TYPE: |
| return no_linkage_check (TREE_TYPE (t), relaxed_p); |
| |
| case OFFSET_TYPE: |
| ptrmem: |
| r = no_linkage_check (TYPE_PTRMEM_POINTED_TO_TYPE (t), |
| relaxed_p); |
| if (r) |
| return r; |
| return no_linkage_check (TYPE_PTRMEM_CLASS_TYPE (t), relaxed_p); |
| |
| case METHOD_TYPE: |
| r = no_linkage_check (TYPE_METHOD_BASETYPE (t), relaxed_p); |
| if (r) |
| return r; |
| /* Fall through. */ |
| case FUNCTION_TYPE: |
| { |
| tree parm; |
| for (parm = TYPE_ARG_TYPES (t); |
| parm && parm != void_list_node; |
| parm = TREE_CHAIN (parm)) |
| { |
| r = no_linkage_check (TREE_VALUE (parm), relaxed_p); |
| if (r) |
| return r; |
| } |
| return no_linkage_check (TREE_TYPE (t), relaxed_p); |
| } |
| |
| default: |
| return NULL_TREE; |
| } |
| } |
| |
| #ifdef GATHER_STATISTICS |
| extern int depth_reached; |
| #endif |
| |
| void |
| cxx_print_statistics (void) |
| { |
| print_search_statistics (); |
| print_class_statistics (); |
| #ifdef GATHER_STATISTICS |
| fprintf (stderr, "maximum template instantiation depth reached: %d\n", |
| depth_reached); |
| #endif |
| } |
| |
| /* Return, as an INTEGER_CST node, the number of elements for TYPE |
| (which is an ARRAY_TYPE). This counts only elements of the top |
| array. */ |
| |
| tree |
| array_type_nelts_top (tree type) |
| { |
| return fold (build2 (PLUS_EXPR, sizetype, |
| array_type_nelts (type), |
| integer_one_node)); |
| } |
| |
| /* Return, as an INTEGER_CST node, the number of elements for TYPE |
| (which is an ARRAY_TYPE). This one is a recursive count of all |
| ARRAY_TYPEs that are clumped together. */ |
| |
| tree |
| array_type_nelts_total (tree type) |
| { |
| tree sz = array_type_nelts_top (type); |
| type = TREE_TYPE (type); |
| while (TREE_CODE (type) == ARRAY_TYPE) |
| { |
| tree n = array_type_nelts_top (type); |
| sz = fold (build2 (MULT_EXPR, sizetype, sz, n)); |
| type = TREE_TYPE (type); |
| } |
| return sz; |
| } |
| |
| /* Called from break_out_target_exprs via mapcar. */ |
| |
| static tree |
| bot_manip (tree* tp, int* walk_subtrees, void* data) |
| { |
| splay_tree target_remap = ((splay_tree) data); |
| tree t = *tp; |
| |
| if (!TYPE_P (t) && TREE_CONSTANT (t)) |
| { |
| /* There can't be any TARGET_EXPRs or their slot variables below |
| this point. We used to check !TREE_SIDE_EFFECTS, but then we |
| failed to copy an ADDR_EXPR of the slot VAR_DECL. */ |
| *walk_subtrees = 0; |
| return NULL_TREE; |
| } |
| if (TREE_CODE (t) == TARGET_EXPR) |
| { |
| tree u; |
| |
| if (TREE_CODE (TREE_OPERAND (t, 1)) == AGGR_INIT_EXPR) |
| { |
| mark_used (TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 1), 0), 0)); |
| u = build_cplus_new |
| (TREE_TYPE (t), break_out_target_exprs (TREE_OPERAND (t, 1))); |
| } |
| else |
| { |
| u = build_target_expr_with_type |
| (break_out_target_exprs (TREE_OPERAND (t, 1)), TREE_TYPE (t)); |
| } |
| |
| /* Map the old variable to the new one. */ |
| splay_tree_insert (target_remap, |
| (splay_tree_key) TREE_OPERAND (t, 0), |
| (splay_tree_value) TREE_OPERAND (u, 0)); |
| |
| /* Replace the old expression with the new version. */ |
| *tp = u; |
| /* We don't have to go below this point; the recursive call to |
| break_out_target_exprs will have handled anything below this |
| point. */ |
| *walk_subtrees = 0; |
| return NULL_TREE; |
| } |
| else if (TREE_CODE (t) == CALL_EXPR) |
| mark_used (TREE_OPERAND (TREE_OPERAND (t, 0), 0)); |
| |
| /* Make a copy of this node. */ |
| return copy_tree_r (tp, walk_subtrees, NULL); |
| } |
| |
| /* Replace all remapped VAR_DECLs in T with their new equivalents. |
| DATA is really a splay-tree mapping old variables to new |
| variables. */ |
| |
| static tree |
| bot_replace (tree* t, |
| int* walk_subtrees ATTRIBUTE_UNUSED , |
| void* data) |
| { |
| splay_tree target_remap = ((splay_tree) data); |
| |
| if (TREE_CODE (*t) == VAR_DECL) |
| { |
| splay_tree_node n = splay_tree_lookup (target_remap, |
| (splay_tree_key) *t); |
| if (n) |
| *t = (tree) n->value; |
| } |
| |
| return NULL_TREE; |
| } |
| |
| /* When we parse a default argument expression, we may create |
| temporary variables via TARGET_EXPRs. When we actually use the |
| default-argument expression, we make a copy of the expression, but |
| we must replace the temporaries with appropriate local versions. */ |
| |
| tree |
| break_out_target_exprs (tree t) |
| { |
| static int target_remap_count; |
| static splay_tree target_remap; |
| |
| if (!target_remap_count++) |
| target_remap = splay_tree_new (splay_tree_compare_pointers, |
| /*splay_tree_delete_key_fn=*/NULL, |
| /*splay_tree_delete_value_fn=*/NULL); |
| walk_tree (&t, bot_manip, target_remap, NULL); |
| walk_tree (&t, bot_replace, target_remap, NULL); |
| |
| if (!--target_remap_count) |
| { |
| splay_tree_delete (target_remap); |
| target_remap = NULL; |
| } |
| |
| return t; |
| } |
| |
| /* Similar to `build_nt', but for template definitions of dependent |
| expressions */ |
| |
| tree |
| build_min_nt (enum tree_code code, ...) |
| { |
| tree t; |
| int length; |
| int i; |
| va_list p; |
| |
| va_start (p, code); |
| |
| t = make_node (code); |
| length = TREE_CODE_LENGTH (code); |
| |
| for (i = 0; i < length; i++) |
| { |
| tree x = va_arg (p, tree); |
| TREE_OPERAND (t, i) = x; |
| } |
| |
| va_end (p); |
| return t; |
| } |
| |
| /* Similar to `build', but for template definitions. */ |
| |
| tree |
| build_min (enum tree_code code, tree tt, ...) |
| { |
| tree t; |
| int length; |
| int i; |
| va_list p; |
| |
| va_start (p, tt); |
| |
| t = make_node (code); |
| length = TREE_CODE_LENGTH (code); |
| TREE_TYPE (t) = tt; |
| |
| for (i = 0; i < length; i++) |
| { |
| tree x = va_arg (p, tree); |
| TREE_OPERAND (t, i) = x; |
| if (x && !TYPE_P (x) && TREE_SIDE_EFFECTS (x)) |
| TREE_SIDE_EFFECTS (t) = 1; |
| } |
| |
| va_end (p); |
| return t; |
| } |
| |
| /* Similar to `build', but for template definitions of non-dependent |
| expressions. NON_DEP is the non-dependent expression that has been |
| built. */ |
| |
| tree |
| build_min_non_dep (enum tree_code code, tree non_dep, ...) |
| { |
| tree t; |
| int length; |
| int i; |
| va_list p; |
| |
| va_start (p, non_dep); |
| |
| t = make_node (code); |
| length = TREE_CODE_LENGTH (code); |
| TREE_TYPE (t) = TREE_TYPE (non_dep); |
| TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (non_dep); |
| |
| for (i = 0; i < length; i++) |
| { |
| tree x = va_arg (p, tree); |
| TREE_OPERAND (t, i) = x; |
| } |
| |
| if (code == COMPOUND_EXPR && TREE_CODE (non_dep) != COMPOUND_EXPR) |
| /* This should not be considered a COMPOUND_EXPR, because it |
| resolves to an overload. */ |
| COMPOUND_EXPR_OVERLOADED (t) = 1; |
| |
| va_end (p); |
| return t; |
| } |
| |
| tree |
| get_type_decl (tree t) |
| { |
| if (TREE_CODE (t) == TYPE_DECL) |
| return t; |
| if (TYPE_P (t)) |
| return TYPE_STUB_DECL (t); |
| gcc_assert (t == error_mark_node); |
| return t; |
| } |
| |
| /* Returns the namespace that contains DECL, whether directly or |
| indirectly. */ |
| |
| tree |
| decl_namespace_context (tree decl) |
| { |
| while (1) |
| { |
| if (TREE_CODE (decl) == NAMESPACE_DECL) |
| return decl; |
| else if (TYPE_P (decl)) |
| decl = CP_DECL_CONTEXT (TYPE_MAIN_DECL (decl)); |
| else |
| decl = CP_DECL_CONTEXT (decl); |
| } |
| } |
| |
| /* Return truthvalue of whether T1 is the same tree structure as T2. |
| Return 1 if they are the same. Return 0 if they are different. */ |
| |
| bool |
| cp_tree_equal (tree t1, tree t2) |
| { |
| enum tree_code code1, code2; |
| |
| if (t1 == t2) |
| return true; |
| if (!t1 || !t2) |
| return false; |
| |
| for (code1 = TREE_CODE (t1); |
| code1 == NOP_EXPR || code1 == CONVERT_EXPR |
| || code1 == NON_LVALUE_EXPR; |
| code1 = TREE_CODE (t1)) |
| t1 = TREE_OPERAND (t1, 0); |
| for (code2 = TREE_CODE (t2); |
| code2 == NOP_EXPR || code2 == CONVERT_EXPR |
| || code1 == NON_LVALUE_EXPR; |
| code2 = TREE_CODE (t2)) |
| t2 = TREE_OPERAND (t2, 0); |
| |
| /* They might have become equal now. */ |
| if (t1 == t2) |
| return true; |
| |
| if (code1 != code2) |
| return false; |
| |
| switch (code1) |
| { |
| case INTEGER_CST: |
| return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2) |
| && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2); |
| |
| case REAL_CST: |
| return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2)); |
| |
| case STRING_CST: |
| return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2) |
| && !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2), |
| TREE_STRING_LENGTH (t1)); |
| |
| case CONSTRUCTOR: |
| /* We need to do this when determining whether or not two |
| non-type pointer to member function template arguments |
| are the same. */ |
| if (!(same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)) |
| /* The first operand is RTL. */ |
| && TREE_OPERAND (t1, 0) == TREE_OPERAND (t2, 0))) |
| return false; |
| return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)); |
| |
| case TREE_LIST: |
| if (!cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))) |
| return false; |
| if (!cp_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2))) |
| return false; |
| return cp_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2)); |
| |
| case SAVE_EXPR: |
| return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); |
| |
| case CALL_EXPR: |
| if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))) |
| return false; |
| return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)); |
| |
| case TARGET_EXPR: |
| { |
| tree o1 = TREE_OPERAND (t1, 0); |
| tree o2 = TREE_OPERAND (t2, 0); |
| |
| /* Special case: if either target is an unallocated VAR_DECL, |
| it means that it's going to be unified with whatever the |
| TARGET_EXPR is really supposed to initialize, so treat it |
| as being equivalent to anything. */ |
| if (TREE_CODE (o1) == VAR_DECL && DECL_NAME (o1) == NULL_TREE |
| && !DECL_RTL_SET_P (o1)) |
| /*Nop*/; |
| else if (TREE_CODE (o2) == VAR_DECL && DECL_NAME (o2) == NULL_TREE |
| && !DECL_RTL_SET_P (o2)) |
| /*Nop*/; |
| else if (!cp_tree_equal (o1, o2)) |
| return false; |
| |
| return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)); |
| } |
| |
| case WITH_CLEANUP_EXPR: |
| if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))) |
| return false; |
| return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1)); |
| |
| case COMPONENT_REF: |
| if (TREE_OPERAND (t1, 1) != TREE_OPERAND (t2, 1)) |
| return false; |
| return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); |
| |
| case VAR_DECL: |
| case PARM_DECL: |
| case CONST_DECL: |
| case FUNCTION_DECL: |
| case TEMPLATE_DECL: |
| case IDENTIFIER_NODE: |
| case SSA_NAME: |
| return false; |
| |
| case BASELINK: |
| return (BASELINK_BINFO (t1) == BASELINK_BINFO (t2) |
| && BASELINK_ACCESS_BINFO (t1) == BASELINK_ACCESS_BINFO (t2) |
| && cp_tree_equal (BASELINK_FUNCTIONS (t1), |
| BASELINK_FUNCTIONS (t2))); |
| |
| case TEMPLATE_PARM_INDEX: |
| return (TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2) |
| && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2) |
| && same_type_p (TREE_TYPE (TEMPLATE_PARM_DECL (t1)), |
| TREE_TYPE (TEMPLATE_PARM_DECL (t2)))); |
| |
| case TEMPLATE_ID_EXPR: |
| { |
| unsigned ix; |
| tree vec1, vec2; |
| |
| if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))) |
| return false; |
| vec1 = TREE_OPERAND (t1, 1); |
| vec2 = TREE_OPERAND (t2, 1); |
| |
| if (!vec1 || !vec2) |
| return !vec1 && !vec2; |
| |
| if (TREE_VEC_LENGTH (vec1) != TREE_VEC_LENGTH (vec2)) |
| return false; |
| |
| for (ix = TREE_VEC_LENGTH (vec1); ix--;) |
| if (!cp_tree_equal (TREE_VEC_ELT (vec1, ix), |
| TREE_VEC_ELT (vec2, ix))) |
| return false; |
| |
| return true; |
| } |
| |
| case SIZEOF_EXPR: |
| case ALIGNOF_EXPR: |
| { |
| tree o1 = TREE_OPERAND (t1, 0); |
| tree o2 = TREE_OPERAND (t2, 0); |
| |
| if (TREE_CODE (o1) != TREE_CODE (o2)) |
| return false; |
| if (TYPE_P (o1)) |
| return same_type_p (o1, o2); |
| else |
| return cp_tree_equal (o1, o2); |
| } |
| |
| case PTRMEM_CST: |
| /* Two pointer-to-members are the same if they point to the same |
| field or function in the same class. */ |
| if (PTRMEM_CST_MEMBER (t1) != PTRMEM_CST_MEMBER (t2)) |
| return false; |
| |
| return same_type_p (PTRMEM_CST_CLASS (t1), PTRMEM_CST_CLASS (t2)); |
| |
| case OVERLOAD: |
| if (OVL_FUNCTION (t1) != OVL_FUNCTION (t2)) |
| return false; |
| return cp_tree_equal (OVL_CHAIN (t1), OVL_CHAIN (t2)); |
| |
| default: |
| break; |
| } |
| |
| switch (TREE_CODE_CLASS (code1)) |
| { |
| case tcc_unary: |
| case tcc_binary: |
| case tcc_comparison: |
| case tcc_expression: |
| case tcc_reference: |
| case tcc_statement: |
| { |
| int i; |
| |
| for (i = 0; i < TREE_CODE_LENGTH (code1); ++i) |
| if (!cp_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i))) |
| return false; |
| |
| return true; |
| } |
| |
| case tcc_type: |
| return same_type_p (t1, t2); |
| default: |
| gcc_unreachable (); |
| } |
| /* We can get here with --disable-checking. */ |
| return false; |
| } |
| |
| /* The type of ARG when used as an lvalue. */ |
| |
| tree |
| lvalue_type (tree arg) |
| { |
| tree type = TREE_TYPE (arg); |
| return type; |
| } |
| |
| /* The type of ARG for printing error messages; denote lvalues with |
| reference types. */ |
| |
| tree |
| error_type (tree arg) |
| { |
| tree type = TREE_TYPE (arg); |
| |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| ; |
| else if (TREE_CODE (type) == ERROR_MARK) |
| ; |
| else if (real_lvalue_p (arg)) |
| type = build_reference_type (lvalue_type (arg)); |
| else if (IS_AGGR_TYPE (type)) |
| type = lvalue_type (arg); |
| |
| return type; |
| } |
| |
| /* Does FUNCTION use a variable-length argument list? */ |
| |
| int |
| varargs_function_p (tree function) |
| { |
| tree parm = TYPE_ARG_TYPES (TREE_TYPE (function)); |
| for (; parm; parm = TREE_CHAIN (parm)) |
| if (TREE_VALUE (parm) == void_type_node) |
| return 0; |
| return 1; |
| } |
| |
| /* Returns 1 if decl is a member of a class. */ |
| |
| int |
| member_p (tree decl) |
| { |
| const tree ctx = DECL_CONTEXT (decl); |
| return (ctx && TYPE_P (ctx)); |
| } |
| |
| /* Create a placeholder for member access where we don't actually have an |
| object that the access is against. */ |
| |
| tree |
| build_dummy_object (tree type) |
| { |
| tree decl = build1 (NOP_EXPR, build_pointer_type (type), void_zero_node); |
| return build_indirect_ref (decl, NULL); |
| } |
| |
| /* We've gotten a reference to a member of TYPE. Return *this if appropriate, |
| or a dummy object otherwise. If BINFOP is non-0, it is filled with the |
| binfo path from current_class_type to TYPE, or 0. */ |
| |
| tree |
| maybe_dummy_object (tree type, tree* binfop) |
| { |
| tree decl, context; |
| tree binfo; |
| |
| if (current_class_type |
| && (binfo = lookup_base (current_class_type, type, |
| ba_unique | ba_quiet, NULL))) |
| context = current_class_type; |
| else |
| { |
| /* Reference from a nested class member function. */ |
| context = type; |
| binfo = TYPE_BINFO (type); |
| } |
| |
| if (binfop) |
| *binfop = binfo; |
| |
| if (current_class_ref && context == current_class_type |
| /* Kludge: Make sure that current_class_type is actually |
| correct. It might not be if we're in the middle of |
| tsubst_default_argument. */ |
| && same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)), |
| current_class_type)) |
| decl = current_class_ref; |
| else |
| decl = build_dummy_object (context); |
| |
| return decl; |
| } |
| |
| /* Returns 1 if OB is a placeholder object, or a pointer to one. */ |
| |
| int |
| is_dummy_object (tree ob) |
| { |
| if (TREE_CODE (ob) == INDIRECT_REF) |
| ob = TREE_OPERAND (ob, 0); |
| return (TREE_CODE (ob) == NOP_EXPR |
| && TREE_OPERAND (ob, 0) == void_zero_node); |
| } |
| |
| /* Returns 1 iff type T is a POD type, as defined in [basic.types]. */ |
| |
| int |
| pod_type_p (tree t) |
| { |
| t = strip_array_types (t); |
| |
| if (t == error_mark_node) |
| return 1; |
| if (INTEGRAL_TYPE_P (t)) |
| return 1; /* integral, character or enumeral type */ |
| if (FLOAT_TYPE_P (t)) |
| return 1; |
| if (TYPE_PTR_P (t)) |
| return 1; /* pointer to non-member */ |
| if (TYPE_PTR_TO_MEMBER_P (t)) |
| return 1; /* pointer to member */ |
| |
| if (TREE_CODE (t) == VECTOR_TYPE) |
| return 1; /* vectors are (small) arrays of scalars */ |
| |
| if (! CLASS_TYPE_P (t)) |
| return 0; /* other non-class type (reference or function) */ |
| if (CLASSTYPE_NON_POD_P (t)) |
| return 0; |
| return 1; |
| } |
| |
| /* Returns 1 iff zero initialization of type T means actually storing |
| zeros in it. */ |
| |
| int |
| zero_init_p (tree t) |
| { |
| t = strip_array_types (t); |
| |
| if (t == error_mark_node) |
| return 1; |
| |
| /* NULL pointers to data members are initialized with -1. */ |
| if (TYPE_PTRMEM_P (t)) |
| return 0; |
| |
| /* Classes that contain types that can't be zero-initialized, cannot |
| be zero-initialized themselves. */ |
| if (CLASS_TYPE_P (t) && CLASSTYPE_NON_ZERO_INIT_P (t)) |
| return 0; |
| |
| return 1; |
| } |
| |
| /* Table of valid C++ attributes. */ |
| const struct attribute_spec cxx_attribute_table[] = |
| { |
| /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ |
| { "java_interface", 0, 0, false, false, false, handle_java_interface_attribute }, |
| { "com_interface", 0, 0, false, false, false, handle_com_interface_attribute }, |
| { "init_priority", 1, 1, true, false, false, handle_init_priority_attribute }, |
| { NULL, 0, 0, false, false, false, NULL } |
| }; |
| |
| /* Handle a "java_interface" attribute; arguments as in |
| struct attribute_spec.handler. */ |
| static tree |
| handle_java_interface_attribute (tree* node, |
| tree name, |
| tree args ATTRIBUTE_UNUSED , |
| int flags, |
| bool* no_add_attrs) |
| { |
| if (DECL_P (*node) |
| || !CLASS_TYPE_P (*node) |
| || !TYPE_FOR_JAVA (*node)) |
| { |
| error ("%qE attribute can only be applied to Java class definitions", |
| name); |
| *no_add_attrs = true; |
| return NULL_TREE; |
| } |
| if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) |
| *node = build_variant_type_copy (*node); |
| TYPE_JAVA_INTERFACE (*node) = 1; |
| |
| return NULL_TREE; |
| } |
| |
| /* Handle a "com_interface" attribute; arguments as in |
| struct attribute_spec.handler. */ |
| static tree |
| handle_com_interface_attribute (tree* node, |
| tree name, |
| tree args ATTRIBUTE_UNUSED , |
| int flags ATTRIBUTE_UNUSED , |
| bool* no_add_attrs) |
| { |
| static int warned; |
| |
| *no_add_attrs = true; |
| |
| if (DECL_P (*node) |
| || !CLASS_TYPE_P (*node) |
| || *node != TYPE_MAIN_VARIANT (*node)) |
| { |
| warning ("%qE attribute can only be applied to class definitions", name); |
| return NULL_TREE; |
| } |
| |
| if (!warned++) |
| warning ("%qE is obsolete; g++ vtables are now COM-compatible by default", |
| name); |
| |
| return NULL_TREE; |
| } |
| |
| /* Handle an "init_priority" attribute; arguments as in |
| struct attribute_spec.handler. */ |
| static tree |
| handle_init_priority_attribute (tree* node, |
| tree name, |
| tree args, |
| int flags ATTRIBUTE_UNUSED , |
| bool* no_add_attrs) |
| { |
| tree initp_expr = TREE_VALUE (args); |
| tree decl = *node; |
| tree type = TREE_TYPE (decl); |
| int pri; |
| |
| STRIP_NOPS (initp_expr); |
| |
| if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST) |
| { |
| error ("requested init_priority is not an integer constant"); |
| *no_add_attrs = true; |
| return NULL_TREE; |
| } |
| |
| pri = TREE_INT_CST_LOW (initp_expr); |
| |
| type = strip_array_types (type); |
| |
| if (decl == NULL_TREE |
| || TREE_CODE (decl) != VAR_DECL |
| || !TREE_STATIC (decl) |
| || DECL_EXTERNAL (decl) |
| || (TREE_CODE (type) != RECORD_TYPE |
| && TREE_CODE (type) != UNION_TYPE) |
| /* Static objects in functions are initialized the |
| first time control passes through that |
| function. This is not precise enough to pin down an |
| init_priority value, so don't allow it. */ |
| || current_function_decl) |
| { |
| error ("can only use %qE attribute on file-scope definitions " |
| "of objects of class type", name); |
| *no_add_attrs = true; |
| return NULL_TREE; |
| } |
| |
| if (pri > MAX_INIT_PRIORITY || pri <= 0) |
| { |
| error ("requested init_priority is out of range"); |
| *no_add_attrs = true; |
| return NULL_TREE; |
| } |
| |
| /* Check for init_priorities that are reserved for |
| language and runtime support implementations.*/ |
| if (pri <= MAX_RESERVED_INIT_PRIORITY) |
| { |
| warning |
| ("requested init_priority is reserved for internal use"); |
| } |
| |
| if (SUPPORTS_INIT_PRIORITY) |
| { |
| DECL_INIT_PRIORITY (decl) = pri; |
| return NULL_TREE; |
| } |
| else |
| { |
| error ("%qE attribute is not supported on this platform", name); |
| *no_add_attrs = true; |
| return NULL_TREE; |
| } |
| } |
| |
| /* Return a new PTRMEM_CST of the indicated TYPE. The MEMBER is the |
| thing pointed to by the constant. */ |
| |
| tree |
| make_ptrmem_cst (tree type, tree member) |
| { |
| tree ptrmem_cst = make_node (PTRMEM_CST); |
| TREE_TYPE (ptrmem_cst) = type; |
| PTRMEM_CST_MEMBER (ptrmem_cst) = member; |
| return ptrmem_cst; |
| } |
| |
| /* Build a variant of TYPE that has the indicated ATTRIBUTES. May |
| return an existing type of an appropriate type already exists. */ |
| |
| tree |
| cp_build_type_attribute_variant (tree type, tree attributes) |
| { |
| tree new_type; |
| |
| new_type = build_type_attribute_variant (type, attributes); |
| if (TREE_CODE (new_type) == FUNCTION_TYPE |
| && (TYPE_RAISES_EXCEPTIONS (new_type) |
| != TYPE_RAISES_EXCEPTIONS (type))) |
| new_type = build_exception_variant (new_type, |
| TYPE_RAISES_EXCEPTIONS (type)); |
| return new_type; |
| } |
| |
| /* Apply FUNC to all language-specific sub-trees of TP in a pre-order |
| traversal. Called from walk_tree. */ |
| |
| tree |
| cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, |
| void *data, struct pointer_set_t *pset) |
| { |
| enum tree_code code = TREE_CODE (*tp); |
| location_t save_locus; |
| tree result; |
| |
| #define WALK_SUBTREE(NODE) \ |
| do \ |
| { \ |
| result = walk_tree (&(NODE), func, data, pset); \ |
| if (result) goto out; \ |
| } \ |
| while (0) |
| |
| /* Set input_location here so we get the right instantiation context |
| if we call instantiate_decl from inlinable_function_p. */ |
| save_locus = input_location; |
| if (EXPR_HAS_LOCATION (*tp)) |
| input_location = EXPR_LOCATION (*tp); |
| |
| /* Not one of the easy cases. We must explicitly go through the |
| children. */ |
| result = NULL_TREE; |
| switch (code) |
| { |
| case DEFAULT_ARG: |
| case TEMPLATE_TEMPLATE_PARM: |
| case BOUND_TEMPLATE_TEMPLATE_PARM: |
| case UNBOUND_CLASS_TEMPLATE: |
| case TEMPLATE_PARM_INDEX: |
| case TEMPLATE_TYPE_PARM: |
| case TYPENAME_TYPE: |
| case TYPEOF_TYPE: |
| case BASELINK: |
| /* None of these have subtrees other than those already walked |
| above. */ |
| *walk_subtrees_p = 0; |
| break; |
| |
| case TINST_LEVEL: |
| WALK_SUBTREE (TINST_DECL (*tp)); |
| *walk_subtrees_p = 0; |
| break; |
| |
| case PTRMEM_CST: |
| WALK_SUBTREE (TREE_TYPE (*tp)); |
| *walk_subtrees_p = 0; |
| break; |
| |
| case TREE_LIST: |
| WALK_SUBTREE (TREE_PURPOSE (*tp)); |
| break; |
| |
| case OVERLOAD: |
| WALK_SUBTREE (OVL_FUNCTION (*tp)); |
| WALK_SUBTREE (OVL_CHAIN (*tp)); |
| *walk_subtrees_p = 0; |
| break; |
| |
| case RECORD_TYPE: |
| if (TYPE_PTRMEMFUNC_P (*tp)) |
| WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp)); |
| break; |
| |
| default: |
| input_location = save_locus; |
| return NULL_TREE; |
| } |
| |
| /* We didn't find what we were looking for. */ |
| out: |
| input_location = save_locus; |
| return result; |
| |
| #undef WALK_SUBTREE |
| } |
| |
| /* Decide whether there are language-specific reasons to not inline a |
| function as a tree. */ |
| |
| int |
| cp_cannot_inline_tree_fn (tree* fnp) |
| { |
| tree fn = *fnp; |
| |
| /* We can inline a template instantiation only if it's fully |
| instantiated. */ |
| if (DECL_TEMPLATE_INFO (fn) |
| && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn))) |
| { |
| /* Don't instantiate functions that are not going to be |
| inlined. */ |
| if (!DECL_INLINE (DECL_TEMPLATE_RESULT |
| (template_for_substitution (fn)))) |
| return 1; |
| |
| fn = *fnp = instantiate_decl (fn, /*defer_ok=*/0, /*undefined_ok=*/0); |
| |
| if (TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn))) |
| return 1; |
| } |
| |
| if (flag_really_no_inline |
| && lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) == NULL) |
| return 1; |
| |
| /* Don't auto-inline anything that might not be bound within |
| this unit of translation. |
| Exclude comdat functions from this rule. While they can be bound |
| to the other unit, they all must be the same. This is especially |
| important so templates can inline. */ |
| if (!DECL_DECLARED_INLINE_P (fn) && !(*targetm.binds_local_p) (fn) |
| && !DECL_COMDAT (fn)) |
| { |
| DECL_UNINLINABLE (fn) = 1; |
| return 1; |
| } |
| |
| if (varargs_function_p (fn)) |
| { |
| DECL_UNINLINABLE (fn) = 1; |
| return 1; |
| } |
| |
| if (! function_attribute_inlinable_p (fn)) |
| { |
| DECL_UNINLINABLE (fn) = 1; |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| /* Add any pending functions other than the current function (already |
| handled by the caller), that thus cannot be inlined, to FNS_P, then |
| return the latest function added to the array, PREV_FN. */ |
| |
| tree |
| cp_add_pending_fn_decls (void* fns_p, tree prev_fn) |
| { |
| varray_type *fnsp = (varray_type *)fns_p; |
| struct saved_scope *s; |
| |
| for (s = scope_chain; s; s = s->prev) |
| if (s->function_decl && s->function_decl != prev_fn) |
| { |
| VARRAY_PUSH_TREE (*fnsp, s->function_decl); |
| prev_fn = s->function_decl; |
| } |
| |
| return prev_fn; |
| } |
| |
| /* Determine whether VAR is a declaration of an automatic variable in |
| function FN. */ |
| |
| int |
| cp_auto_var_in_fn_p (tree var, tree fn) |
| { |
| return (DECL_P (var) && DECL_CONTEXT (var) == fn |
| && nonstatic_local_decl_p (var)); |
| } |
| |
| /* Initialize tree.c. */ |
| |
| void |
| init_tree (void) |
| { |
| list_hash_table = htab_create_ggc (31, list_hash, list_hash_eq, NULL); |
| } |
| |
| /* Returns the kind of special function that DECL (a FUNCTION_DECL) |
| is. Note that sfk_none is zero, so this function can be used as a |
| predicate to test whether or not DECL is a special function. */ |
| |
| special_function_kind |
| special_function_p (tree decl) |
| { |
| /* Rather than doing all this stuff with magic names, we should |
| probably have a field of type `special_function_kind' in |
| DECL_LANG_SPECIFIC. */ |
| if (DECL_COPY_CONSTRUCTOR_P (decl)) |
| return sfk_copy_constructor; |
| if (DECL_CONSTRUCTOR_P (decl)) |
| return sfk_constructor; |
| if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR) |
| return sfk_assignment_operator; |
| if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)) |
| return sfk_destructor; |
| if (DECL_COMPLETE_DESTRUCTOR_P (decl)) |
| return sfk_complete_destructor; |
| if (DECL_BASE_DESTRUCTOR_P (decl)) |
| return sfk_base_destructor; |
| if (DECL_DELETING_DESTRUCTOR_P (decl)) |
| return sfk_deleting_destructor; |
| if (DECL_CONV_FN_P (decl)) |
| return sfk_conversion; |
| |
| return sfk_none; |
| } |
| |
| /* Returns nonzero if TYPE is a character type, including wchar_t. */ |
| |
| int |
| char_type_p (tree type) |
| { |
| return (same_type_p (type, char_type_node) |
| || same_type_p (type, unsigned_char_type_node) |
| || same_type_p (type, signed_char_type_node) |
| || same_type_p (type, wchar_type_node)); |
| } |
| |
| /* Returns the kind of linkage associated with the indicated DECL. Th |
| value returned is as specified by the language standard; it is |
| independent of implementation details regarding template |
| instantiation, etc. For example, it is possible that a declaration |
| to which this function assigns external linkage would not show up |
| as a global symbol when you run `nm' on the resulting object file. */ |
| |
| linkage_kind |
| decl_linkage (tree decl) |
| { |
| /* This function doesn't attempt to calculate the linkage from first |
| principles as given in [basic.link]. Instead, it makes use of |
| the fact that we have already set TREE_PUBLIC appropriately, and |
| then handles a few special cases. Ideally, we would calculate |
| linkage first, and then transform that into a concrete |
| implementation. */ |
| |
| /* Things that don't have names have no linkage. */ |
| if (!DECL_NAME (decl)) |
| return lk_none; |
| |
| /* Things that are TREE_PUBLIC have external linkage. */ |
| if (TREE_PUBLIC (decl)) |
| return lk_external; |
| |
| /* Some things that are not TREE_PUBLIC have external linkage, too. |
| For example, on targets that don't have weak symbols, we make all |
| template instantiations have internal linkage (in the object |
| file), but the symbols should still be treated as having external |
| linkage from the point of view of the language. */ |
| if (DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl)) |
| return lk_external; |
| |
| /* Things in local scope do not have linkage, if they don't have |
| TREE_PUBLIC set. */ |
| if (decl_function_context (decl)) |
| return lk_none; |
| |
| /* Everything else has internal linkage. */ |
| return lk_internal; |
| } |
| |
| /* EXP is an expression that we want to pre-evaluate. Returns via INITP an |
| expression to perform the pre-evaluation, and returns directly an |
| expression to use the precalculated result. */ |
| |
| tree |
| stabilize_expr (tree exp, tree* initp) |
| { |
| tree init_expr; |
| |
| if (!TREE_SIDE_EFFECTS (exp)) |
| { |
| init_expr = NULL_TREE; |
| } |
| else if (!real_lvalue_p (exp) |
| || !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (exp))) |
| { |
| init_expr = get_target_expr (exp); |
| exp = TARGET_EXPR_SLOT (init_expr); |
| } |
| else |
| { |
| exp = build_unary_op (ADDR_EXPR, exp, 1); |
| init_expr = get_target_expr (exp); |
| exp = TARGET_EXPR_SLOT (init_expr); |
| exp = build_indirect_ref (exp, 0); |
| } |
| |
| *initp = init_expr; |
| return exp; |
| } |
| |
| /* Add NEW, an expression whose value we don't care about, after the |
| similar expression ORIG. */ |
| |
| tree |
| add_stmt_to_compound (tree orig, tree new) |
| { |
| if (!new || !TREE_SIDE_EFFECTS (new)) |
| return orig; |
| if (!orig || !TREE_SIDE_EFFECTS (orig)) |
| return new; |
| return build2 (COMPOUND_EXPR, void_type_node, orig, new); |
| } |
| |
| /* Like stabilize_expr, but for a call whose args we want to |
| pre-evaluate. */ |
| |
| void |
| stabilize_call (tree call, tree *initp) |
| { |
| tree inits = NULL_TREE; |
| tree t; |
| |
| if (call == error_mark_node) |
| return; |
| |
| gcc_assert (TREE_CODE (call) == CALL_EXPR |
| || TREE_CODE (call) == AGGR_INIT_EXPR); |
| |
| for (t = TREE_OPERAND (call, 1); t; t = TREE_CHAIN (t)) |
| if (TREE_SIDE_EFFECTS (TREE_VALUE (t))) |
| { |
| tree init; |
| TREE_VALUE (t) = stabilize_expr (TREE_VALUE (t), &init); |
| inits = add_stmt_to_compound (inits, init); |
| } |
| |
| *initp = inits; |
| } |
| |
| /* Like stabilize_expr, but for an initialization. If we are initializing |
| an object of class type, we don't want to introduce an extra temporary, |
| so we look past the TARGET_EXPR and stabilize the arguments of the call |
| instead. */ |
| |
| bool |
| stabilize_init (tree init, tree *initp) |
| { |
| tree t = init; |
| |
| if (t == error_mark_node) |
| return true; |
| |
| if (TREE_CODE (t) == INIT_EXPR |
| && TREE_CODE (TREE_OPERAND (t, 1)) != TARGET_EXPR) |
| TREE_OPERAND (t, 1) = stabilize_expr (TREE_OPERAND (t, 1), initp); |
| else |
| { |
| if (TREE_CODE (t) == INIT_EXPR) |
| t = TREE_OPERAND (t, 1); |
| if (TREE_CODE (t) == TARGET_EXPR) |
| t = TARGET_EXPR_INITIAL (t); |
| if (TREE_CODE (t) == COMPOUND_EXPR) |
| t = expr_last (t); |
| if (TREE_CODE (t) == CONSTRUCTOR |
| && CONSTRUCTOR_ELTS (t) == NULL_TREE) |
| { |
| /* Default-initialization. */ |
| *initp = NULL_TREE; |
| return true; |
| } |
| |
| /* If the initializer is a COND_EXPR, we can't preevaluate |
| anything. */ |
| if (TREE_CODE (t) == COND_EXPR) |
| return false; |
| |
| /* The TARGET_EXPR might be initializing via bitwise copy from |
| another variable; leave that alone. */ |
| if (TREE_SIDE_EFFECTS (t)) |
| stabilize_call (t, initp); |
| } |
| |
| return true; |
| } |
| |
| /* Like "fold", but should be used whenever we might be processing the |
| body of a template. */ |
| |
| tree |
| fold_if_not_in_template (tree expr) |
| { |
| /* In the body of a template, there is never any need to call |
| "fold". We will call fold later when actually instantiating the |
| template. Integral constant expressions in templates will be |
| evaluated via fold_non_dependent_expr, as necessary. */ |
| return (processing_template_decl ? expr : fold (expr)); |
| } |
| |
| |
| #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007) |
| /* Complain that some language-specific thing hanging off a tree |
| node has been accessed improperly. */ |
| |
| void |
| lang_check_failed (const char* file, int line, const char* function) |
| { |
| internal_error ("lang_* check: failed in %s, at %s:%d", |
| function, trim_filename (file), line); |
| } |
| #endif /* ENABLE_TREE_CHECKING */ |
| |
| #include "gt-cp-tree.h" |