📄 tree.c
字号:
/* Language-dependent node constructors for parse phase of GNU compiler. Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com)This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. */#include "config.h"#include <stdio.h>#include "obstack.h"#include "tree.h"#include "cp-tree.h"#include "flags.h"#include "rtl.h"#ifdef __STDC__#include <stdarg.h>#else#include <varargs.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef NEED_DECLARATION_FREEextern void free PROTO((void *));#endifextern void compiler_error ();static tree get_identifier_list PROTO((tree));static tree bot_manip PROTO((tree));static tree perm_manip PROTO((tree));static tree build_cplus_array_type_1 PROTO((tree, tree));static void list_hash_add PROTO((int, tree));static int list_hash PROTO((tree, tree, tree));static tree list_hash_lookup PROTO((int, int, int, int, tree, tree, tree));#define CEIL(x,y) (((x) + (y) - 1) / (y))/* Return nonzero if REF is an lvalue valid for this language. Lvalues can be assigned, unless they have TREE_READONLY. Lvalues can have their address taken, unless they have DECL_REGISTER. */intreal_lvalue_p (ref) tree ref;{ if (! language_lvalue_valid (ref)) return 0; if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE) return 1; if (ref == current_class_ptr && flag_this_is_variable <= 0) return 0; 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 COMPONENT_REF: case SAVE_EXPR: case UNSAVE_EXPR: case TRY_CATCH_EXPR: case WITH_CLEANUP_EXPR: return real_lvalue_p (TREE_OPERAND (ref, 0)); case STRING_CST: return 1; case VAR_DECL: if (TREE_READONLY (ref) && ! TREE_STATIC (ref) && DECL_LANG_SPECIFIC (ref) && DECL_IN_AGGR_P (ref)) return 0; case INDIRECT_REF: case ARRAY_REF: case PARM_DECL: case RESULT_DECL: case ERROR_MARK: if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE) return 1; break; /* A currently unresolved scope ref. */ case SCOPE_REF: my_friendly_abort (103); case OFFSET_REF: if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL) return 1; return real_lvalue_p (TREE_OPERAND (ref, 0)) && real_lvalue_p (TREE_OPERAND (ref, 1)); break; case COND_EXPR: return (real_lvalue_p (TREE_OPERAND (ref, 1)) && real_lvalue_p (TREE_OPERAND (ref, 2))); case MODIFY_EXPR: return 1; case COMPOUND_EXPR: return real_lvalue_p (TREE_OPERAND (ref, 1)); case MAX_EXPR: case MIN_EXPR: return (real_lvalue_p (TREE_OPERAND (ref, 0)) && real_lvalue_p (TREE_OPERAND (ref, 1))); } return 0;}/* This differs from real_lvalue_p in that class rvalues are considered lvalues. */intlvalue_p (ref) tree ref;{ if (! language_lvalue_valid (ref)) return 0; if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE) return 1; if (ref == current_class_ptr && flag_this_is_variable <= 0) return 0; 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 REALPART_EXPR: case IMAGPART_EXPR: case COMPONENT_REF: case SAVE_EXPR: case UNSAVE_EXPR: case TRY_CATCH_EXPR: case WITH_CLEANUP_EXPR: return lvalue_p (TREE_OPERAND (ref, 0)); case STRING_CST: return 1; case VAR_DECL: if (TREE_READONLY (ref) && ! TREE_STATIC (ref) && DECL_LANG_SPECIFIC (ref) && DECL_IN_AGGR_P (ref)) return 0; case INDIRECT_REF: case ARRAY_REF: case PARM_DECL: case RESULT_DECL: case ERROR_MARK: if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE) return 1; break; case TARGET_EXPR: return 1; case CALL_EXPR: if (IS_AGGR_TYPE (TREE_TYPE (ref))) return 1; break; /* A currently unresolved scope ref. */ case SCOPE_REF: my_friendly_abort (103); case OFFSET_REF: if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL) return 1; return lvalue_p (TREE_OPERAND (ref, 0)) && lvalue_p (TREE_OPERAND (ref, 1)); break; case COND_EXPR: return (lvalue_p (TREE_OPERAND (ref, 1)) && lvalue_p (TREE_OPERAND (ref, 2))); case MODIFY_EXPR: return 1; case COMPOUND_EXPR: return lvalue_p (TREE_OPERAND (ref, 1)); case MAX_EXPR: case MIN_EXPR: return (lvalue_p (TREE_OPERAND (ref, 0)) && lvalue_p (TREE_OPERAND (ref, 1))); } return 0;}/* Return nonzero if REF is an lvalue valid for this language; otherwise, print an error message and return zero. */intlvalue_or_else (ref, string) tree ref; char *string;{ int win = lvalue_p (ref); if (! win) error ("non-lvalue in %s", string); return win;}/* 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. */treebuild_cplus_new (type, init) tree type; tree init;{ tree slot; tree rval; if (TREE_CODE (init) != CALL_EXPR && TREE_CODE (init) != NEW_EXPR) return init; slot = build (VAR_DECL, type); layout_decl (slot, 0); rval = build (NEW_EXPR, type, TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), slot); TREE_SIDE_EFFECTS (rval) = 1; rval = build (TARGET_EXPR, type, slot, rval, NULL_TREE, NULL_TREE); TREE_SIDE_EFFECTS (rval) = 1; return rval;}/* Recursively search EXP for CALL_EXPRs that need cleanups and replace these CALL_EXPRs with tree nodes that will perform the cleanups. */treebreak_out_cleanups (exp) tree exp;{ tree tmp = exp; if (TREE_CODE (tmp) == CALL_EXPR && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (tmp))) return build_cplus_new (TREE_TYPE (tmp), tmp); while (TREE_CODE (tmp) == NOP_EXPR || TREE_CODE (tmp) == CONVERT_EXPR || TREE_CODE (tmp) == NON_LVALUE_EXPR) { if (TREE_CODE (TREE_OPERAND (tmp, 0)) == CALL_EXPR && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (TREE_OPERAND (tmp, 0)))) { TREE_OPERAND (tmp, 0) = build_cplus_new (TREE_TYPE (TREE_OPERAND (tmp, 0)), TREE_OPERAND (tmp, 0)); break; } else tmp = TREE_OPERAND (tmp, 0); } return exp;}/* Recursively perform a preorder search EXP for CALL_EXPRs, making copies where they are found. Returns a deep copy all nodes transitively containing CALL_EXPRs. */treebreak_out_calls (exp) tree exp;{ register tree t1, t2; register enum tree_code code; register int changed = 0; register int i; if (exp == NULL_TREE) return exp; code = TREE_CODE (exp); if (code == CALL_EXPR) return copy_node (exp); /* Don't try and defeat a save_expr, as it should only be done once. */ if (code == SAVE_EXPR) return exp; switch (TREE_CODE_CLASS (code)) { default: abort (); case 'c': /* a constant */ case 't': /* a type node */ case 'x': /* something random, like an identifier or an ERROR_MARK. */ return exp; case 'd': /* A decl node */#if 0 /* This is bogus. jason 9/21/94 */ t1 = break_out_calls (DECL_INITIAL (exp)); if (t1 != DECL_INITIAL (exp)) { exp = copy_node (exp); DECL_INITIAL (exp) = t1; }#endif return exp; case 'b': /* A block node */ { /* Don't know how to handle these correctly yet. Must do a break_out_calls on all DECL_INITIAL values for local variables, and also break_out_calls on all sub-blocks and sub-statements. */ abort (); } return exp; case 'e': /* an expression */ case 'r': /* a reference */ case 's': /* an expression with side effects */ for (i = tree_code_length[(int) code] - 1; i >= 0; i--) { t1 = break_out_calls (TREE_OPERAND (exp, i)); if (t1 != TREE_OPERAND (exp, i)) { exp = copy_node (exp); TREE_OPERAND (exp, i) = t1; } } return exp; case '<': /* a comparison expression */ case '2': /* a binary arithmetic expression */ t2 = break_out_calls (TREE_OPERAND (exp, 1)); if (t2 != TREE_OPERAND (exp, 1)) changed = 1; case '1': /* a unary arithmetic expression */ t1 = break_out_calls (TREE_OPERAND (exp, 0)); if (t1 != TREE_OPERAND (exp, 0)) changed = 1; if (changed) { if (tree_code_length[(int) code] == 1) return build1 (code, TREE_TYPE (exp), t1); else return build (code, TREE_TYPE (exp), t1, t2); } return exp; }}extern struct obstack *current_obstack;extern struct obstack permanent_obstack, class_obstack;extern struct obstack *saveable_obstack;extern struct obstack *expression_obstack;/* Here is how primitive or already-canonicalized types' hash codes are made. MUST BE CONSISTENT WITH tree.c !!! */#define TYPE_HASH(TYPE) ((HOST_WIDE_INT) (TYPE) & 0777777)/* Construct, lay out and return the type of methods belonging to class BASETYPE and whose arguments are described by ARGTYPES and whose values are described by RETTYPE. If each type exists already, reuse it. */treebuild_cplus_method_type (basetype, rettype, argtypes) tree basetype, rettype, argtypes;{ register tree t; tree ptype; int hashcode; /* Make a node of the sort we want. */ t = make_node (METHOD_TYPE); TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype); TREE_TYPE (t) = rettype; if (IS_SIGNATURE (basetype)) ptype = build_signature_pointer_type (TYPE_MAIN_VARIANT (basetype), TYPE_READONLY (basetype), TYPE_VOLATILE (basetype)); else ptype = build_pointer_type (basetype); /* The actual arglist for this function includes a "hidden" argument which is "this". Put it into the list of argument types. */ argtypes = tree_cons (NULL_TREE, ptype, argtypes); TYPE_ARG_TYPES (t) = argtypes; TREE_SIDE_EFFECTS (argtypes) = 1; /* Mark first argtype as "artificial". */ /* If we already have such a type, use the old one and free this one. Note that it also frees up the above cons cell if found. */ hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) + type_hash_list (argtypes); t = type_hash_canon (hashcode, t); if (TYPE_SIZE (t) == 0) layout_type (t); return t;}static treebuild_cplus_array_type_1 (elt_type, index_type) tree elt_type; tree index_type;{ register struct obstack *ambient_obstack = current_obstack; register struct obstack *ambient_saveable_obstack = saveable_obstack; tree t; /* We need a new one. If both ELT_TYPE and INDEX_TYPE are permanent, make this permanent too. */ if (TREE_PERMANENT (elt_type) && (index_type == 0 || TREE_PERMANENT (index_type))) { current_obstack = &permanent_obstack; saveable_obstack = &permanent_obstack; } if (processing_template_decl) { 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_NEEDS_DESTRUCTOR (t) = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type)); current_obstack = ambient_obstack; saveable_obstack = ambient_saveable_obstack; return t;}treebuild_cplus_array_type (elt_type, index_type) tree elt_type; tree index_type;{ tree t; int constp = TYPE_READONLY (elt_type); int volatilep = TYPE_VOLATILE (elt_type); elt_type = TYPE_MAIN_VARIANT (elt_type); t = build_cplus_array_type_1 (elt_type, index_type); if (constp || volatilep) t = cp_build_type_variant (t, constp, volatilep); return t;}/* Make a variant type in the proper way for C/C++, propagating qualifiers down to the element type of an array. */treecp_build_type_variant (type, constp, volatilep) tree type; int constp, volatilep;{ if (type == error_mark_node) return type; if (TREE_CODE (type) == ARRAY_TYPE) { tree real_main_variant = TYPE_MAIN_VARIANT (type); push_obstacks (TYPE_OBSTACK (real_main_variant), TYPE_OBSTACK (real_main_variant)); type = build_cplus_array_type_1 (cp_build_type_variant (TREE_TYPE (type), constp, volatilep), TYPE_DOMAIN (type)); /* TYPE must be on same obstack as REAL_MAIN_VARIANT. If not, make a copy. (TYPE might have come from the hash table and REAL_MAIN_VARIANT might be in some function's obstack.) */ if (TYPE_OBSTACK (type) != TYPE_OBSTACK (real_main_variant)) { type = copy_node (type); TYPE_POINTER_TO (type) = TYPE_REFERENCE_TO (type) = 0; } TYPE_MAIN_VARIANT (type) = real_main_variant; pop_obstacks (); return type; } return build_type_variant (type, constp, volatilep);}/* Add OFFSET to all base types of T. OFFSET, which is a type offset, is number of bytes. Note that we don't have to worry about having two paths to the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -