Mercurial > hg > CbC > CbC_gcc
diff gcc/cp/lex.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gcc/cp/lex.c Fri Oct 27 22:46:09 2017 +0900 @@ -0,0 +1,865 @@ +/* Separate lexical analyzer for GNU C++. + Copyright (C) 1987-2017 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 3, 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 COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + + +/* This file is the lexical analyzer for GNU C++. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "cp-tree.h" +#include "stringpool.h" +#include "c-family/c-pragma.h" +#include "c-family/c-objc.h" + +static int interface_strcmp (const char *); +static void init_cp_pragma (void); + +static tree parse_strconst_pragma (const char *, int); +static void handle_pragma_vtable (cpp_reader *); +static void handle_pragma_unit (cpp_reader *); +static void handle_pragma_interface (cpp_reader *); +static void handle_pragma_implementation (cpp_reader *); + +static void init_operators (void); +static void copy_lang_type (tree); + +/* A constraint that can be tested at compile time. */ +#define CONSTRAINT(name, expr) extern int constraint_##name [(expr) ? 1 : -1] + +/* Functions and data structures for #pragma interface. + + `#pragma implementation' means that the main file being compiled + is considered to implement (provide) the classes that appear in + its main body. I.e., if this is file "foo.cc", and class `bar' + is defined in "foo.cc", then we say that "foo.cc implements bar". + + All main input files "implement" themselves automagically. + + `#pragma interface' means that unless this file (of the form "foo.h" + is not presently being included by file "foo.cc", the + CLASSTYPE_INTERFACE_ONLY bit gets set. The effect is that none + of the vtables nor any of the inline functions defined in foo.h + will ever be output. + + There are cases when we want to link files such as "defs.h" and + "main.cc". In this case, we give "defs.h" a `#pragma interface', + and "main.cc" has `#pragma implementation "defs.h"'. */ + +struct impl_files +{ + const char *filename; + struct impl_files *next; +}; + +static struct impl_files *impl_file_chain; + +void +cxx_finish (void) +{ + c_common_finish (); +} + +/* A mapping from tree codes to operator name information. */ +operator_name_info_t operator_name_info[(int) MAX_TREE_CODES]; +/* Similar, but for assignment operators. */ +operator_name_info_t assignment_operator_name_info[(int) MAX_TREE_CODES]; + +/* Initialize data structures that keep track of operator names. */ + +#define DEF_OPERATOR(NAME, C, M, AR, AP) \ + CONSTRAINT (C, sizeof "operator " + sizeof NAME <= 256); +#include "operators.def" +#undef DEF_OPERATOR + +/* Get the name of the kind of identifier T. */ + +const char * +get_identifier_kind_name (tree id) +{ + /* Keep in sync with cp_id_kind enumeration. */ + static const char *const names[cik_max] = { + "normal", "keyword", "constructor", "destructor", + "assign-op", "op-assign-op", "simple-op", "conv-op", }; + + unsigned kind = 0; + kind |= IDENTIFIER_KIND_BIT_2 (id) << 2; + kind |= IDENTIFIER_KIND_BIT_1 (id) << 1; + kind |= IDENTIFIER_KIND_BIT_0 (id) << 0; + + return names[kind]; +} + +/* Set the identifier kind, which we expect to currently be zero. */ + +void +set_identifier_kind (tree id, cp_identifier_kind kind) +{ + gcc_checking_assert (!IDENTIFIER_KIND_BIT_2 (id) + & !IDENTIFIER_KIND_BIT_1 (id) + & !IDENTIFIER_KIND_BIT_0 (id)); + IDENTIFIER_KIND_BIT_2 (id) |= (kind >> 2) & 1; + IDENTIFIER_KIND_BIT_1 (id) |= (kind >> 1) & 1; + IDENTIFIER_KIND_BIT_0 (id) |= (kind >> 0) & 1; +} + +static void +init_operators (void) +{ + tree identifier; + char buffer[256]; + struct operator_name_info_t *oni; + +#define DEF_OPERATOR(NAME, CODE, MANGLING, ARITY, KIND) \ + sprintf (buffer, "operator%s%s", !NAME[0] \ + || NAME[0] == '_' || ISALPHA (NAME[0]) ? " " : "", NAME); \ + identifier = get_identifier (buffer); \ + \ + if (KIND != cik_simple_op || !IDENTIFIER_ANY_OP_P (identifier)) \ + set_identifier_kind (identifier, KIND); \ + \ + oni = (KIND == cik_assign_op \ + ? &assignment_operator_name_info[(int) CODE] \ + : &operator_name_info[(int) CODE]); \ + oni->identifier = identifier; \ + oni->name = NAME; \ + oni->mangled_name = MANGLING; \ + oni->arity = ARITY; + +#include "operators.def" +#undef DEF_OPERATOR + + operator_name_info[(int) TYPE_EXPR] = operator_name_info[(int) CAST_EXPR]; + operator_name_info[(int) ERROR_MARK].identifier + = get_identifier ("<invalid operator>"); + + /* Handle some special cases. These operators are not defined in + the language, but can be produced internally. We may need them + for error-reporting. (Eventually, we should ensure that this + does not happen. Error messages involving these operators will + be confusing to users.) */ + + operator_name_info [(int) INIT_EXPR].name + = operator_name_info [(int) MODIFY_EXPR].name; + + operator_name_info [(int) EXACT_DIV_EXPR].name = "(ceiling /)"; + operator_name_info [(int) CEIL_DIV_EXPR].name = "(ceiling /)"; + operator_name_info [(int) FLOOR_DIV_EXPR].name = "(floor /)"; + operator_name_info [(int) ROUND_DIV_EXPR].name = "(round /)"; + operator_name_info [(int) CEIL_MOD_EXPR].name = "(ceiling %)"; + operator_name_info [(int) FLOOR_MOD_EXPR].name = "(floor %)"; + operator_name_info [(int) ROUND_MOD_EXPR].name = "(round %)"; + + operator_name_info [(int) ABS_EXPR].name = "abs"; + operator_name_info [(int) TRUTH_AND_EXPR].name = "strict &&"; + operator_name_info [(int) TRUTH_OR_EXPR].name = "strict ||"; + operator_name_info [(int) RANGE_EXPR].name = "..."; + operator_name_info [(int) UNARY_PLUS_EXPR].name = "+"; + + assignment_operator_name_info [(int) EXACT_DIV_EXPR].name = "(exact /=)"; + assignment_operator_name_info [(int) CEIL_DIV_EXPR].name = "(ceiling /=)"; + assignment_operator_name_info [(int) FLOOR_DIV_EXPR].name = "(floor /=)"; + assignment_operator_name_info [(int) ROUND_DIV_EXPR].name = "(round /=)"; + assignment_operator_name_info [(int) CEIL_MOD_EXPR].name = "(ceiling %=)"; + assignment_operator_name_info [(int) FLOOR_MOD_EXPR].name = "(floor %=)"; + assignment_operator_name_info [(int) ROUND_MOD_EXPR].name = "(round %=)"; +} + +/* Initialize the reserved words. */ + +void +init_reswords (void) +{ + unsigned int i; + tree id; + int mask = 0; + + if (cxx_dialect < cxx11) + mask |= D_CXX11; + if (!flag_concepts) + mask |= D_CXX_CONCEPTS; + if (!flag_tm) + mask |= D_TRANSMEM; + if (flag_no_asm) + mask |= D_ASM | D_EXT; + if (flag_no_gnu_keywords) + mask |= D_EXT; + + /* The Objective-C keywords are all context-dependent. */ + mask |= D_OBJC; + + ridpointers = ggc_cleared_vec_alloc<tree> ((int) RID_MAX); + for (i = 0; i < num_c_common_reswords; i++) + { + if (c_common_reswords[i].disable & D_CONLY) + continue; + id = get_identifier (c_common_reswords[i].word); + C_SET_RID_CODE (id, c_common_reswords[i].rid); + ridpointers [(int) c_common_reswords[i].rid] = id; + if (! (c_common_reswords[i].disable & mask)) + set_identifier_kind (id, cik_keyword); + } + + for (i = 0; i < NUM_INT_N_ENTS; i++) + { + char name[50]; + sprintf (name, "__int%d", int_n_data[i].bitsize); + id = get_identifier (name); + C_SET_RID_CODE (id, RID_FIRST_INT_N + i); + set_identifier_kind (id, cik_keyword); + } +} + +static void +init_cp_pragma (void) +{ + c_register_pragma (0, "vtable", handle_pragma_vtable); + c_register_pragma (0, "unit", handle_pragma_unit); + c_register_pragma (0, "interface", handle_pragma_interface); + c_register_pragma (0, "implementation", handle_pragma_implementation); + c_register_pragma ("GCC", "interface", handle_pragma_interface); + c_register_pragma ("GCC", "implementation", handle_pragma_implementation); +} + +/* TRUE if a code represents a statement. */ + +bool statement_code_p[MAX_TREE_CODES]; + +/* Initialize the C++ front end. This function is very sensitive to + the exact order that things are done here. It would be nice if the + initialization done by this routine were moved to its subroutines, + and the ordering dependencies clarified and reduced. */ +bool +cxx_init (void) +{ + location_t saved_loc; + unsigned int i; + static const enum tree_code stmt_codes[] = { + CTOR_INITIALIZER, TRY_BLOCK, HANDLER, + EH_SPEC_BLOCK, USING_STMT, TAG_DEFN, + IF_STMT, CLEANUP_STMT, FOR_STMT, + RANGE_FOR_STMT, WHILE_STMT, DO_STMT, + BREAK_STMT, CONTINUE_STMT, SWITCH_STMT, + EXPR_STMT + }; + + memset (&statement_code_p, 0, sizeof (statement_code_p)); + for (i = 0; i < ARRAY_SIZE (stmt_codes); i++) + statement_code_p[stmt_codes[i]] = true; + + saved_loc = input_location; + input_location = BUILTINS_LOCATION; + + init_reswords (); + init_tree (); + init_cp_semantics (); + init_operators (); + init_method (); + + current_function_decl = NULL; + + class_type_node = ridpointers[(int) RID_CLASS]; + + cxx_init_decl_processing (); + + if (c_common_init () == false) + { + input_location = saved_loc; + return false; + } + + init_cp_pragma (); + + init_repo (); + + input_location = saved_loc; + return true; +} + +/* Return nonzero if S is not considered part of an + INTERFACE/IMPLEMENTATION pair. Otherwise, return 0. */ + +static int +interface_strcmp (const char* s) +{ + /* Set the interface/implementation bits for this scope. */ + struct impl_files *ifiles; + const char *s1; + + for (ifiles = impl_file_chain; ifiles; ifiles = ifiles->next) + { + const char *t1 = ifiles->filename; + s1 = s; + + if (*s1 == 0 || filename_ncmp (s1, t1, 1) != 0) + continue; + + while (*s1 != 0 && filename_ncmp (s1, t1, 1) == 0) + s1++, t1++; + + /* A match. */ + if (*s1 == *t1) + return 0; + + /* Don't get faked out by xxx.yyy.cc vs xxx.zzz.cc. */ + if (strchr (s1, '.') || strchr (t1, '.')) + continue; + + if (*s1 == '\0' || s1[-1] != '.' || t1[-1] != '.') + continue; + + /* A match. */ + return 0; + } + + /* No matches. */ + return 1; +} + + + +/* Parse a #pragma whose sole argument is a string constant. + If OPT is true, the argument is optional. */ +static tree +parse_strconst_pragma (const char* name, int opt) +{ + tree result, x; + enum cpp_ttype t; + + t = pragma_lex (&result); + if (t == CPP_STRING) + { + if (pragma_lex (&x) != CPP_EOF) + warning (0, "junk at end of #pragma %s", name); + return result; + } + + if (t == CPP_EOF && opt) + return NULL_TREE; + + error ("invalid #pragma %s", name); + return error_mark_node; +} + +static void +handle_pragma_vtable (cpp_reader* /*dfile*/) +{ + parse_strconst_pragma ("vtable", 0); + sorry ("#pragma vtable no longer supported"); +} + +static void +handle_pragma_unit (cpp_reader* /*dfile*/) +{ + /* Validate syntax, but don't do anything. */ + parse_strconst_pragma ("unit", 0); +} + +static void +handle_pragma_interface (cpp_reader* /*dfile*/) +{ + tree fname = parse_strconst_pragma ("interface", 1); + struct c_fileinfo *finfo; + const char *filename; + + if (fname == error_mark_node) + return; + else if (fname == 0) + filename = lbasename (LOCATION_FILE (input_location)); + else + filename = TREE_STRING_POINTER (fname); + + finfo = get_fileinfo (LOCATION_FILE (input_location)); + + if (impl_file_chain == 0) + { + /* If this is zero at this point, then we are + auto-implementing. */ + if (main_input_filename == 0) + main_input_filename = LOCATION_FILE (input_location); + } + + finfo->interface_only = interface_strcmp (filename); + /* If MULTIPLE_SYMBOL_SPACES is set, we cannot assume that we can see + a definition in another file. */ + if (!MULTIPLE_SYMBOL_SPACES || !finfo->interface_only) + finfo->interface_unknown = 0; +} + +/* Note that we have seen a #pragma implementation for the key MAIN_FILENAME. + We used to only allow this at toplevel, but that restriction was buggy + in older compilers and it seems reasonable to allow it in the headers + themselves, too. It only needs to precede the matching #p interface. + + We don't touch finfo->interface_only or finfo->interface_unknown; + the user must specify a matching #p interface for this to have + any effect. */ + +static void +handle_pragma_implementation (cpp_reader* /*dfile*/) +{ + tree fname = parse_strconst_pragma ("implementation", 1); + const char *filename; + struct impl_files *ifiles = impl_file_chain; + + if (fname == error_mark_node) + return; + + if (fname == 0) + { + if (main_input_filename) + filename = main_input_filename; + else + filename = LOCATION_FILE (input_location); + filename = lbasename (filename); + } + else + { + filename = TREE_STRING_POINTER (fname); + if (cpp_included_before (parse_in, filename, input_location)) + warning (0, "#pragma implementation for %qs appears after " + "file is included", filename); + } + + for (; ifiles; ifiles = ifiles->next) + { + if (! filename_cmp (ifiles->filename, filename)) + break; + } + if (ifiles == 0) + { + ifiles = XNEW (struct impl_files); + ifiles->filename = xstrdup (filename); + ifiles->next = impl_file_chain; + impl_file_chain = ifiles; + } +} + +/* Issue an error message indicating that the lookup of NAME (an + IDENTIFIER_NODE) failed. Returns the ERROR_MARK_NODE. */ + +tree +unqualified_name_lookup_error (tree name, location_t loc) +{ + if (loc == UNKNOWN_LOCATION) + loc = EXPR_LOC_OR_LOC (name, input_location); + + if (IDENTIFIER_ANY_OP_P (name)) + { + if (name != cp_operator_id (ERROR_MARK)) + error_at (loc, "%qD not defined", name); + } + else + { + if (!objc_diagnose_private_ivar (name)) + { + error_at (loc, "%qD was not declared in this scope", name); + suggest_alternatives_for (loc, name, true); + } + /* Prevent repeated error messages by creating a VAR_DECL with + this NAME in the innermost block scope. */ + if (local_bindings_p ()) + { + tree decl = build_decl (loc, VAR_DECL, name, error_mark_node); + TREE_USED (decl) = true; + pushdecl (decl); + } + } + + return error_mark_node; +} + +/* Like unqualified_name_lookup_error, but NAME_EXPR is an unqualified-id + NAME, encapsulated with its location in a CP_EXPR, used as a function. + Returns an appropriate expression for NAME. */ + +tree +unqualified_fn_lookup_error (cp_expr name_expr) +{ + tree name = name_expr.get_value (); + location_t loc = name_expr.get_location (); + if (loc == UNKNOWN_LOCATION) + loc = input_location; + + if (processing_template_decl) + { + /* In a template, it is invalid to write "f()" or "f(3)" if no + declaration of "f" is available. Historically, G++ and most + other compilers accepted that usage since they deferred all name + lookup until instantiation time rather than doing unqualified + name lookup at template definition time; explain to the user what + is going wrong. + + Note that we have the exact wording of the following message in + the manual (trouble.texi, node "Name lookup"), so they need to + be kept in synch. */ + permerror (loc, "there are no arguments to %qD that depend on a template " + "parameter, so a declaration of %qD must be available", + name, name); + + if (!flag_permissive) + { + static bool hint; + if (!hint) + { + inform (loc, "(if you use %<-fpermissive%>, G++ will accept your " + "code, but allowing the use of an undeclared name is " + "deprecated)"); + hint = true; + } + } + return name; + } + + return unqualified_name_lookup_error (name, loc); +} + + +/* Hasher for the conversion operator name hash table. */ +struct conv_type_hasher : ggc_ptr_hash<tree_node> +{ + /* Hash NODE, an identifier node in the table. TYPE_UID is + suitable, as we're not concerned about matching canonicalness + here. */ + static hashval_t hash (tree node) + { + return (hashval_t) TYPE_UID (TREE_TYPE (node)); + } + + /* Compare NODE, an identifier node in the table, against TYPE, an + incoming TYPE being looked up. */ + static bool equal (tree node, tree type) + { + return TREE_TYPE (node) == type; + } +}; + +/* This hash table maps TYPEs to the IDENTIFIER for a conversion + operator to TYPE. The nodes are IDENTIFIERs whose TREE_TYPE is the + TYPE. */ + +static GTY (()) hash_table<conv_type_hasher> *conv_type_names; + +/* Return an identifier for a conversion operator to TYPE. We can get + from the returned identifier to the type. We store TYPE, which is + not necessarily the canonical type, which allows us to report the + form the user used in error messages. All these identifiers are + not in the identifier hash table, and have the same string name. + These IDENTIFIERS are not in the identifier hash table, and all + have the same IDENTIFIER_STRING. */ + +tree +make_conv_op_name (tree type) +{ + if (type == error_mark_node) + return error_mark_node; + + if (conv_type_names == NULL) + conv_type_names = hash_table<conv_type_hasher>::create_ggc (31); + + tree *slot = conv_type_names->find_slot_with_hash + (type, (hashval_t) TYPE_UID (type), INSERT); + tree identifier = *slot; + if (!identifier) + { + /* Create a raw IDENTIFIER outside of the identifier hash + table. */ + identifier = copy_node (conv_op_identifier); + + /* Just in case something managed to bind. */ + IDENTIFIER_BINDING (identifier) = NULL; + + /* Hang TYPE off the identifier so it can be found easily later + when performing conversions. */ + TREE_TYPE (identifier) = type; + + *slot = identifier; + } + + return identifier; +} + +/* Wrapper around build_lang_decl_loc(). Should gradually move to + build_lang_decl_loc() and then rename build_lang_decl_loc() back to + build_lang_decl(). */ + +tree +build_lang_decl (enum tree_code code, tree name, tree type) +{ + return build_lang_decl_loc (input_location, code, name, type); +} + +/* Build a decl from CODE, NAME, TYPE declared at LOC, and then add + DECL_LANG_SPECIFIC info to the result. */ + +tree +build_lang_decl_loc (location_t loc, enum tree_code code, tree name, tree type) +{ + tree t; + + t = build_decl (loc, code, name, type); + retrofit_lang_decl (t); + + return t; +} + +/* Maybe add a raw lang_decl to T, a decl. Return true if it needed + one. */ + +static bool +maybe_add_lang_decl_raw (tree t, bool decomp_p) +{ + size_t size; + lang_decl_selector sel; + + if (decomp_p) + sel = lds_decomp, size = sizeof (struct lang_decl_decomp); + else if (TREE_CODE (t) == FUNCTION_DECL) + sel = lds_fn, size = sizeof (struct lang_decl_fn); + else if (TREE_CODE (t) == NAMESPACE_DECL) + sel = lds_ns, size = sizeof (struct lang_decl_ns); + else if (TREE_CODE (t) == PARM_DECL) + sel = lds_parm, size = sizeof (struct lang_decl_parm); + else if (LANG_DECL_HAS_MIN (t)) + sel = lds_min, size = sizeof (struct lang_decl_min); + else + return false; + + struct lang_decl *ld + = (struct lang_decl *) ggc_internal_cleared_alloc (size); + + ld->u.base.selector = sel; + DECL_LANG_SPECIFIC (t) = ld; + + if (sel == lds_ns) + /* Who'd create a namespace, only to put nothing in it? */ + ld->u.ns.bindings = hash_table<named_decl_hash>::create_ggc (499); + + if (GATHER_STATISTICS) + { + tree_node_counts[(int)lang_decl] += 1; + tree_node_sizes[(int)lang_decl] += size; + } + return true; +} + +/* T has just had a decl_lang_specific added. Initialize its + linkage. */ + +static void +set_decl_linkage (tree t) +{ + if (current_lang_name == lang_name_cplusplus + || decl_linkage (t) == lk_none) + SET_DECL_LANGUAGE (t, lang_cplusplus); + else if (current_lang_name == lang_name_c) + SET_DECL_LANGUAGE (t, lang_c); + else + gcc_unreachable (); +} + +/* T is a VAR_DECL node that needs to be a decomposition of BASE. */ + +void +fit_decomposition_lang_decl (tree t, tree base) +{ + if (struct lang_decl *orig_ld = DECL_LANG_SPECIFIC (t)) + { + if (orig_ld->u.base.selector == lds_min) + { + maybe_add_lang_decl_raw (t, true); + memcpy (DECL_LANG_SPECIFIC (t), orig_ld, + sizeof (struct lang_decl_min)); + /* Reset selector, which will have been bashed by the + memcpy. */ + DECL_LANG_SPECIFIC (t)->u.base.selector = lds_decomp; + } + else + gcc_checking_assert (orig_ld->u.base.selector == lds_decomp); + } + else + { + maybe_add_lang_decl_raw (t, true); + set_decl_linkage (t); + } + + DECL_DECOMP_BASE (t) = base; +} + +/* Add DECL_LANG_SPECIFIC info to T, if it needs one. Generally + every C++ decl needs one, but C builtins etc do not. */ + +void +retrofit_lang_decl (tree t) +{ + if (DECL_LANG_SPECIFIC (t)) + return; + + if (maybe_add_lang_decl_raw (t, false)) + set_decl_linkage (t); +} + +void +cxx_dup_lang_specific_decl (tree node) +{ + int size; + + if (! DECL_LANG_SPECIFIC (node)) + return; + + switch (DECL_LANG_SPECIFIC (node)->u.base.selector) + { + case lds_min: + size = sizeof (struct lang_decl_min); + break; + case lds_fn: + size = sizeof (struct lang_decl_fn); + break; + case lds_ns: + size = sizeof (struct lang_decl_ns); + break; + case lds_parm: + size = sizeof (struct lang_decl_parm); + break; + case lds_decomp: + size = sizeof (struct lang_decl_decomp); + break; + default: + gcc_unreachable (); + } + + struct lang_decl *ld = (struct lang_decl *) ggc_internal_alloc (size); + memcpy (ld, DECL_LANG_SPECIFIC (node), size); + DECL_LANG_SPECIFIC (node) = ld; + + if (GATHER_STATISTICS) + { + tree_node_counts[(int)lang_decl] += 1; + tree_node_sizes[(int)lang_decl] += size; + } +} + +/* Copy DECL, including any language-specific parts. */ + +tree +copy_decl (tree decl MEM_STAT_DECL) +{ + tree copy; + + copy = copy_node (decl PASS_MEM_STAT); + cxx_dup_lang_specific_decl (copy); + return copy; +} + +/* Replace the shared language-specific parts of NODE with a new copy. */ + +static void +copy_lang_type (tree node) +{ + if (! TYPE_LANG_SPECIFIC (node)) + return; + + struct lang_type *lt + = (struct lang_type *) ggc_internal_alloc (sizeof (struct lang_type)); + + memcpy (lt, TYPE_LANG_SPECIFIC (node), (sizeof (struct lang_type))); + TYPE_LANG_SPECIFIC (node) = lt; + + if (GATHER_STATISTICS) + { + tree_node_counts[(int)lang_type] += 1; + tree_node_sizes[(int)lang_type] += sizeof (struct lang_type); + } +} + +/* Copy TYPE, including any language-specific parts. */ + +tree +copy_type (tree type MEM_STAT_DECL) +{ + tree copy; + + copy = copy_node (type PASS_MEM_STAT); + copy_lang_type (copy); + return copy; +} + +/* Add a raw lang_type to T, a type, should it need one. */ + +static bool +maybe_add_lang_type_raw (tree t) +{ + if (!RECORD_OR_UNION_CODE_P (TREE_CODE (t))) + return false; + + TYPE_LANG_SPECIFIC (t) + = (struct lang_type *) (ggc_internal_cleared_alloc + (sizeof (struct lang_type))); + + if (GATHER_STATISTICS) + { + tree_node_counts[(int)lang_type] += 1; + tree_node_sizes[(int)lang_type] += sizeof (struct lang_type); + } + + return true; +} + +tree +cxx_make_type (enum tree_code code) +{ + tree t = make_node (code); + + if (maybe_add_lang_type_raw (t)) + { + /* Set up some flags that give proper default behavior. */ + struct c_fileinfo *finfo = + get_fileinfo (LOCATION_FILE (input_location)); + SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, finfo->interface_unknown); + CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only; + } + + return t; +} + +tree +make_class_type (enum tree_code code) +{ + tree t = cxx_make_type (code); + SET_CLASS_TYPE_P (t, 1); + return t; +} + +/* Returns true if we are currently in the main source file, or in a + template instantiation started from the main source file. */ + +bool +in_main_input_context (void) +{ + struct tinst_level *tl = outermost_tinst_level(); + + if (tl) + return filename_cmp (main_input_filename, + LOCATION_FILE (tl->locus)) == 0; + else + return filename_cmp (main_input_filename, LOCATION_FILE (input_location)) == 0; +} + +#include "gt-cp-lex.h"