diff options
author | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
commit | 0126e157b87f137fc08dc7f46f6c291b9d06ac5d (patch) | |
tree | f8555e3e504eb82b4cd3cba5cec20ae4ce8124ff /gnu/egcs/gcc/cp/decl2.c | |
parent | ff8e9a4356e55ed142306c3a375fa280800abc86 (diff) |
egcs projects compiler system
Exact copy of the snapshot, except for the removal of
texinfo/
gcc/ch/
libchill/
Diffstat (limited to 'gnu/egcs/gcc/cp/decl2.c')
-rw-r--r-- | gnu/egcs/gcc/cp/decl2.c | 5270 |
1 files changed, 5270 insertions, 0 deletions
diff --git a/gnu/egcs/gcc/cp/decl2.c b/gnu/egcs/gcc/cp/decl2.c new file mode 100644 index 00000000000..bb24014d790 --- /dev/null +++ b/gnu/egcs/gcc/cp/decl2.c @@ -0,0 +1,5270 @@ +/* Process declarations and variables for C compiler. + Copyright (C) 1988, 92-98, 1999 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 modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Process declarations and symbol lookup for C front end. + Also constructs types; the standard scalar types at initialization, + and structure, union, array and enum types when they are declared. */ + +/* ??? not all decl nodes are given the most useful possible + line numbers. For example, the CONST_DECLs for enum values. */ + +#include "config.h" +#include "system.h" +#include "tree.h" +#include "rtl.h" +#include "flags.h" +#include "cp-tree.h" +#include "decl.h" +#include "lex.h" +#include "output.h" +#include "except.h" +#include "expr.h" +#include "defaults.h" +#include "toplev.h" +#include "dwarf2out.h" +#include "dwarfout.h" +#include "splay-tree.h" +#include "varray.h" + +#if USE_CPPLIB +#include "cpplib.h" +extern cpp_reader parse_in; +#endif + +/* This structure contains information about the initializations + and/or destructions required for a particular priority level. */ +typedef struct priority_info_s { + /* A label indicating where we should generate the next + initialization with this priority. */ + rtx initialization_sequence; + /* A label indicating where we should generate the next destruction + with this priority. */ + rtx destruction_sequence; + /* Non-zero if there have been any initializations at this priority + throughout the translation unit. */ + int initializations_p; + /* Non-zero if there have been any destructions at this priority + throughout the translation unit. */ + int destructions_p; +} *priority_info; + +static tree get_sentry PROTO((tree)); +static void mark_vtable_entries PROTO((tree)); +static void grok_function_init PROTO((tree, tree)); +static int finish_vtable_vardecl PROTO((tree *, void *)); +static int prune_vtable_vardecl PROTO((tree *, void *)); +static int finish_sigtable_vardecl PROTO((tree *, void *)); +static int is_namespace_ancestor PROTO((tree, tree)); +static void add_using_namespace PROTO((tree, tree, int)); +static tree ambiguous_decl PROTO((tree, tree, tree,int)); +static tree build_anon_union_vars PROTO((tree, tree*, int, int)); +static int acceptable_java_type PROTO((tree)); +static void output_vtable_inherit PROTO((tree)); +static void start_objects PROTO((int, int)); +static void finish_objects PROTO((int, int)); +static tree merge_functions PROTO((tree, tree)); +static tree decl_namespace PROTO((tree)); +static tree validate_nonmember_using_decl PROTO((tree, tree *, tree *)); +static void do_nonmember_using_decl PROTO((tree, tree, tree, tree, + tree *, tree *)); +static void start_static_storage_duration_function PROTO((void)); +static int generate_inits_for_priority PROTO((splay_tree_node, void *)); +static void finish_static_storage_duration_function PROTO((void)); +static priority_info get_priority_info PROTO((int)); +static void do_static_initialization PROTO((tree, tree, tree, int)); +static void do_static_destruction PROTO((tree, tree, int)); +static void do_static_initialization_and_destruction PROTO((tree, tree)); +static void generate_ctor_or_dtor_function PROTO((int, int)); +static int generate_ctor_and_dtor_functions_for_priority + PROTO((splay_tree_node, void *)); +extern int current_class_depth; + +/* A list of virtual function tables we must make sure to write out. */ +tree pending_vtables; + +/* A list of static class variables. This is needed, because a + static class variable can be declared inside the class without + an initializer, and then initialized, staticly, outside the class. */ +static varray_type pending_statics; +static size_t pending_statics_used; + +/* A list of functions which were declared inline, but which we + may need to emit outline anyway. */ +static varray_type saved_inlines; +static size_t saved_inlines_used; + +/* Used to help generate temporary names which are unique within + a function. Reset to 0 by start_function. */ + +int temp_name_counter; + +/* Same, but not reset. Local temp variables and global temp variables + can have the same name. */ +static int global_temp_name_counter; + +/* Flag used when debugging spew.c */ + +extern int spew_debug; + +/* Nonzero if we're done parsing and into end-of-file activities. */ + +int at_eof; + +/* Functions called along with real static constructors and destructors. */ + +tree static_ctors, static_dtors; + +/* The current open namespace, and ::. */ + +tree current_namespace; +tree global_namespace; + +/* The stack for namespaces of current declarations. */ + +static tree decl_namespace_list; + + +/* C (and C++) language-specific option variables. */ + +/* Nonzero means allow type mismatches in conditional expressions; + just make their values `void'. */ + +int flag_cond_mismatch; + +/* Nonzero means give `double' the same size as `float'. */ + +int flag_short_double; + +/* Nonzero means don't recognize the keyword `asm'. */ + +int flag_no_asm; + +/* Nonzero means don't recognize any extension keywords. */ + +int flag_no_gnu_keywords; + +/* Nonzero means don't recognize the non-ANSI builtin functions. */ + +int flag_no_builtin; + +/* Nonzero means don't recognize the non-ANSI builtin functions. + -ansi sets this. */ + +int flag_no_nonansi_builtin; + +/* Nonzero means do some things the same way PCC does. Only provided so + the compiler will link. */ + +int flag_traditional; + +/* Nonzero means to treat bitfields as unsigned unless they say `signed'. */ + +int flag_signed_bitfields = 1; + +/* Nonzero means enable obscure ANSI features and disable GNU extensions + that might cause ANSI-compliant code to be miscompiled. */ + +int flag_ansi; + +/* Nonzero means do emit exported implementations of functions even if + they can be inlined. */ + +int flag_implement_inlines = 1; + +/* Nonzero means do emit exported implementations of templates, instead of + multiple static copies in each file that needs a definition. */ + +int flag_external_templates; + +/* Nonzero means that the decision to emit or not emit the implementation of a + template depends on where the template is instantiated, rather than where + it is defined. */ + +int flag_alt_external_templates; + +/* Nonzero means that implicit instantiations will be emitted if needed. */ + +int flag_implicit_templates = 1; + +/* Nonzero means that implicit instantiations of inline templates will be + emitted if needed, even if instantiations of non-inline templates + aren't. */ + +int flag_implicit_inline_templates = 1; + +/* Nonzero means warn about implicit declarations. */ + +int warn_implicit = 1; + +/* Nonzero means warn about usage of long long when `-pedantic'. */ + +int warn_long_long = 1; + +/* Nonzero means warn when all ctors or dtors are private, and the class + has no friends. */ + +int warn_ctor_dtor_privacy = 1; + +/* True if we want to implement vtables using "thunks". + The default is off. */ + +#ifndef DEFAULT_VTABLE_THUNKS +#define DEFAULT_VTABLE_THUNKS 0 +#endif +int flag_vtable_thunks = DEFAULT_VTABLE_THUNKS; + +/* True if we want to deal with repository information. */ + +int flag_use_repository; + +/* Nonzero if we want to issue diagnostics that the standard says are not + required. */ + +int flag_optional_diags = 1; + +/* Nonzero means give string constants the type `const char *', as mandated + by the standard. */ + +int flag_const_strings = 1; + +/* Nonzero means warn about deprecated conversion from string constant to + `char *'. */ + +int warn_write_strings; + +/* Nonzero means warn about pointer casts that can drop a type qualifier + from the pointer target type. */ + +int warn_cast_qual; + +/* Nonzero means warn about sizeof(function) or addition/subtraction + of function pointers. */ + +int warn_pointer_arith = 1; + +/* Nonzero means warn for any function def without prototype decl. */ + +int warn_missing_prototypes; + +/* Nonzero means warn about multiple (redundant) decls for the same single + variable or function. */ + +int warn_redundant_decls; + +/* Warn if initializer is not completely bracketed. */ + +int warn_missing_braces; + +/* Warn about comparison of signed and unsigned values. */ + +int warn_sign_compare; + +/* Warn about *printf or *scanf format/argument anomalies. */ + +int warn_format; + +/* Warn about a subscript that has type char. */ + +int warn_char_subscripts; + +/* Warn if a type conversion is done that might have confusing results. */ + +int warn_conversion; + +/* Warn if adding () is suggested. */ + +int warn_parentheses; + +/* Non-zero means warn in function declared in derived class has the + same name as a virtual in the base class, but fails to match the + type signature of any virtual function in the base class. */ +int warn_overloaded_virtual; + +/* Non-zero means warn when declaring a class that has a non virtual + destructor, when it really ought to have a virtual one. */ +int warn_nonvdtor; + +/* Non-zero means warn when a function is declared extern and later inline. */ +int warn_extern_inline; + +/* Non-zero means warn when the compiler will reorder code. */ +int warn_reorder; + +/* Non-zero means warn when synthesis behavior differs from Cfront's. */ +int warn_synth; + +/* Non-zero means warn when we convert a pointer to member function + into a pointer to (void or function). */ +int warn_pmf2ptr = 1; + +/* Nonzero means warn about violation of some Effective C++ style rules. */ + +int warn_ecpp; + +/* Nonzero means warn where overload resolution chooses a promotion from + unsigned to signed over a conversion to an unsigned of the same size. */ + +int warn_sign_promo; + +/* Nonzero means warn when an old-style cast is used. */ + +int warn_old_style_cast; + +/* Warn about #pragma directives that are not recognised. */ + +int warn_unknown_pragmas; /* Tri state variable. */ + +/* Nonzero means warn about use of multicharacter literals. */ + +int warn_multichar = 1; + +/* Nonzero means warn when non-templatized friend functions are + declared within a template */ + +int warn_nontemplate_friend = 1; + +/* Nonzero means complain about deprecated features. */ + +int warn_deprecated = 1; + +/* Nonzero means `$' can be in an identifier. */ + +#ifndef DOLLARS_IN_IDENTIFIERS +#define DOLLARS_IN_IDENTIFIERS 1 +#endif +int dollars_in_ident = DOLLARS_IN_IDENTIFIERS; + +/* Nonzero for -fno-strict-prototype switch: do not consider empty + argument prototype to mean function takes no arguments. */ + +int flag_strict_prototype = 2; +int strict_prototype = 1; +int strict_prototypes_lang_c, strict_prototypes_lang_cplusplus = 1; + +/* Nonzero means that labels can be used as first-class objects */ + +int flag_labels_ok; + +/* Non-zero means to collect statistics which might be expensive + and to print them when we are done. */ +int flag_detailed_statistics; + +/* C++ specific flags. */ +/* Zero means that `this' is a *const. This gives nice behavior in the + 2.0 world. 1 gives 1.2-compatible behavior. 2 gives Spring behavior. + -2 means we're constructing an object and it has fixed type. */ + +int flag_this_is_variable; + +/* 3 means write out only virtuals function tables `defined' + in this implementation file. + 0 means write out virtual function tables and give them + (C) static access (default). */ + +int write_virtuals; + +/* Nonzero means we should attempt to elide constructors when possible. */ + +int flag_elide_constructors = 1; + +/* Nonzero means recognize and handle signature language constructs. */ + +int flag_handle_signatures; + +/* Nonzero means that member functions defined in class scope are + inline by default. */ + +int flag_default_inline = 1; + +/* Controls whether compiler generates 'type descriptor' that give + run-time type information. */ +int flag_rtti = 1; + +/* Nonzero if we wish to output cross-referencing information + for the GNU class browser. */ +extern int flag_gnu_xref; + +/* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes) + objects. */ + +int flag_huge_objects; + +/* Nonzero if we want to conserve space in the .o files. We do this + by putting uninitialized data and runtime initialized data into + .common instead of .data at the expense of not flagging multiple + definitions. */ + +int flag_conserve_space; + +/* Nonzero if we want to obey access control semantics. */ + +int flag_access_control = 1; + +/* Nonzero if we want to understand the operator names, i.e. 'bitand'. */ + +int flag_operator_names; + +/* Nonzero if we want to check the return value of new and avoid calling + constructors if it is a null pointer. */ + +int flag_check_new; + +/* Nonzero if we want the new ANSI rules for pushing a new scope for `for' + initialization variables. + 0: Old rules, set by -fno-for-scope. + 2: New ANSI rules, set by -ffor-scope. + 1: Try to implement new ANSI rules, but with backup compatibility + (and warnings). This is the default, for now. */ + +int flag_new_for_scope = 1; + +/* Nonzero if we want to emit defined symbols with common-like linkage as + weak symbols where possible, in order to conform to C++ semantics. + Otherwise, emit them as local symbols. */ + +int flag_weak = 1; + +/* Nonzero to enable experimental ABI changes. */ + +int flag_new_abi; + +/* Nonzero to not ignore namespace std. */ + +int flag_honor_std; + +/* Maximum template instantiation depth. Must be at least 17 for ANSI + compliance. */ + +int max_tinst_depth = 17; + +/* The name-mangling scheme to use. Must be 1 or greater to support + template functions with identical types, but different template + arguments. */ +int name_mangling_version = 2; + +/* Nonzero means that guiding declarations are allowed. */ +int flag_guiding_decls; + +/* Nonzero if squashed mangling is to be performed. + This uses the B and K codes to reference previously seen class types + and class qualifiers. */ +int flag_do_squangling; + +/* Nonzero means output .vtable_{entry,inherit} for use in doing vtable gc. */ + +int flag_vtable_gc; + +/* Nonzero means make the default pedwarns warnings instead of errors. + The value of this flag is ignored if -pedantic is specified. */ + +int flag_permissive; + +/* Table of language-dependent -f options. + STRING is the option name. VARIABLE is the address of the variable. + ON_VALUE is the value to store in VARIABLE + if `-fSTRING' is seen as an option. + (If `-fno-STRING' is seen as an option, the opposite value is stored.) */ + +static struct { const char *string; int *variable; int on_value;} +lang_f_options[] = +{ + /* C/C++ options. */ + {"signed-char", &flag_signed_char, 1}, + {"unsigned-char", &flag_signed_char, 0}, + {"signed-bitfields", &flag_signed_bitfields, 1}, + {"unsigned-bitfields", &flag_signed_bitfields, 0}, + {"short-enums", &flag_short_enums, 1}, + {"short-double", &flag_short_double, 1}, + {"cond-mismatch", &flag_cond_mismatch, 1}, + {"asm", &flag_no_asm, 0}, + {"builtin", &flag_no_builtin, 0}, + + /* C++-only options. */ + {"access-control", &flag_access_control, 1}, + {"check-new", &flag_check_new, 1}, + {"conserve-space", &flag_conserve_space, 1}, + {"const-strings", &flag_const_strings, 1}, + {"default-inline", &flag_default_inline, 1}, + {"dollars-in-identifiers", &dollars_in_ident, 1}, + {"elide-constructors", &flag_elide_constructors, 1}, + {"external-templates", &flag_external_templates, 1}, + {"for-scope", &flag_new_for_scope, 2}, + {"gnu-keywords", &flag_no_gnu_keywords, 0}, + {"handle-exceptions", &flag_exceptions, 1}, + {"handle-signatures", &flag_handle_signatures, 1}, + {"honor-std", &flag_honor_std, 1}, + {"huge-objects", &flag_huge_objects, 1}, + {"implement-inlines", &flag_implement_inlines, 1}, + {"implicit-inline-templates", &flag_implicit_inline_templates, 1}, + {"implicit-templates", &flag_implicit_templates, 1}, + {"labels-ok", &flag_labels_ok, 1}, + {"nonansi-builtins", &flag_no_nonansi_builtin, 0}, + {"operator-names", &flag_operator_names, 1}, + {"optional-diags", &flag_optional_diags, 1}, + {"permissive", &flag_permissive, 1}, + {"repo", &flag_use_repository, 1}, + {"rtti", &flag_rtti, 1}, + {"squangle", &flag_do_squangling, 1}, + {"stats", &flag_detailed_statistics, 1}, + {"strict-prototype", &flag_strict_prototype, 1}, + {"this-is-variable", &flag_this_is_variable, 1}, + {"vtable-gc", &flag_vtable_gc, 1}, + {"vtable-thunks", &flag_vtable_thunks, 1}, + {"weak", &flag_weak, 1}, + {"xref", &flag_gnu_xref, 1} +}; + +/* Decode the string P as a language-specific option. + Return the number of strings consumed for a valid option. + Otherwise return 0. */ + +int +lang_decode_option (argc, argv) + int argc +#if !USE_CPPLIB + ATTRIBUTE_UNUSED +#endif + ; + char **argv; + +{ + int strings_processed; + char *p = argv[0]; +#if USE_CPPLIB + strings_processed = cpp_handle_option (&parse_in, argc, argv); +#else + strings_processed = 0; +#endif /* ! USE_CPPLIB */ + + if (!strcmp (p, "-ftraditional") || !strcmp (p, "-traditional")) + /* ignore */; + else if (p[0] == '-' && p[1] == 'f') + { + /* Some kind of -f option. + P's value is the option sans `-f'. + Search for it in the table of options. */ + int found = 0; + size_t j; + + p += 2; + /* Try special -f options. */ + + if (!strcmp (p, "handle-exceptions") + || !strcmp (p, "no-handle-exceptions")) + warning ("-fhandle-exceptions has been renamed to -fexceptions (and is now on by default)"); + + if (!strcmp (p, "memoize-lookups") + || !strcmp (p, "no-memoize-lookups") + || !strcmp (p, "save-memoized") + || !strcmp (p, "no-save-memoized") + || !strcmp (p, "no-all-virtual") + || !strcmp (p, "no-enum-int-equiv") + || !strcmp (p, "nonnull-objects") + || !strcmp (p, "ansi-overloading")) + { + /* ignore */ + found = 1; + } + else if (!strcmp (p, "all-virtual") + || !strcmp (p, "enum-int-equiv") + || !strcmp (p, "no-nonnull-objects") + || !strcmp (p, "no-ansi-overloading")) + { + warning ("-f%s is no longer supported", p); + found = 1; + } + else if (! strcmp (p, "alt-external-templates")) + { + flag_external_templates = 1; + flag_alt_external_templates = 1; + found = 1; + cp_deprecated ("-falt-external-templates"); + } + else if (! strcmp (p, "no-alt-external-templates")) + { + flag_alt_external_templates = 0; + found = 1; + } + else if (!strcmp (p, "repo")) + { + flag_use_repository = 1; + flag_implicit_templates = 0; + found = 1; + } + else if (!strcmp (p, "guiding-decls")) + { + flag_guiding_decls = 1; + name_mangling_version = 0; + found = 1; + } + else if (!strcmp (p, "no-guiding-decls")) + { + flag_guiding_decls = 0; + found = 1; + } + else if (!strcmp (p, "this-is-variable")) + { + flag_this_is_variable = 1; + found = 1; + cp_deprecated ("-fthis-is-variable"); + } + else if (!strcmp (p, "external-templates")) + { + flag_external_templates = 1; + found = 1; + cp_deprecated ("-fexternal-templates"); + } + else if (!strcmp (p, "new-abi")) + { + flag_new_abi = 1; + flag_do_squangling = 1; + flag_honor_std = 1; + flag_vtable_thunks = 1; + } + else if (!strcmp (p, "no-new-abi")) + { + flag_new_abi = 0; + flag_do_squangling = 0; + flag_honor_std = 0; + } + else if (!strncmp (p, "template-depth-", 15)) + { + max_tinst_depth = + read_integral_parameter (p + 15, p - 2, max_tinst_depth); + } + else if (!strncmp (p, "name-mangling-version-", 22)) + { + name_mangling_version = + read_integral_parameter (p + 22, p - 2, name_mangling_version); + } + else for (j = 0; + !found && j < sizeof (lang_f_options) / sizeof (lang_f_options[0]); + j++) + { + if (!strcmp (p, lang_f_options[j].string)) + { + *lang_f_options[j].variable = lang_f_options[j].on_value; + /* A goto here would be cleaner, + but breaks the vax pcc. */ + found = 1; + } + if (p[0] == 'n' && p[1] == 'o' && p[2] == '-' + && ! strcmp (p+3, lang_f_options[j].string)) + { + *lang_f_options[j].variable = ! lang_f_options[j].on_value; + found = 1; + } + } + return found; + } + else if (p[0] == '-' && p[1] == 'W') + { + int setting = 1; + + /* The -W options control the warning behavior of the compiler. */ + p += 2; + + if (p[0] == 'n' && p[1] == 'o' && p[2] == '-') + setting = 0, p += 3; + + if (!strcmp (p, "implicit")) + warn_implicit = setting; + else if (!strcmp (p, "long-long")) + warn_long_long = setting; + else if (!strcmp (p, "return-type")) + warn_return_type = setting; + else if (!strcmp (p, "ctor-dtor-privacy")) + warn_ctor_dtor_privacy = setting; + else if (!strcmp (p, "write-strings")) + warn_write_strings = setting; + else if (!strcmp (p, "cast-qual")) + warn_cast_qual = setting; + else if (!strcmp (p, "char-subscripts")) + warn_char_subscripts = setting; + else if (!strcmp (p, "pointer-arith")) + warn_pointer_arith = setting; + else if (!strcmp (p, "missing-prototypes")) + warn_missing_prototypes = setting; + else if (!strcmp (p, "redundant-decls")) + warn_redundant_decls = setting; + else if (!strcmp (p, "missing-braces")) + warn_missing_braces = setting; + else if (!strcmp (p, "sign-compare")) + warn_sign_compare = setting; + else if (!strcmp (p, "format")) + warn_format = setting; + else if (!strcmp (p, "conversion")) + warn_conversion = setting; + else if (!strcmp (p, "parentheses")) + warn_parentheses = setting; + else if (!strcmp (p, "non-virtual-dtor")) + warn_nonvdtor = setting; + else if (!strcmp (p, "extern-inline")) + warn_extern_inline = setting; + else if (!strcmp (p, "reorder")) + warn_reorder = setting; + else if (!strcmp (p, "synth")) + warn_synth = setting; + else if (!strcmp (p, "pmf-conversions")) + warn_pmf2ptr = setting; + else if (!strcmp (p, "effc++")) + warn_ecpp = setting; + else if (!strcmp (p, "sign-promo")) + warn_sign_promo = setting; + else if (!strcmp (p, "old-style-cast")) + warn_old_style_cast = setting; + else if (!strcmp (p, "overloaded-virtual")) + warn_overloaded_virtual = setting; + else if (!strcmp (p, "multichar")) + warn_multichar = setting; + else if (!strcmp (p, "unknown-pragmas")) + /* Set to greater than 1, so that even unknown pragmas in + system headers will be warned about. */ + warn_unknown_pragmas = setting * 2; + else if (!strcmp (p, "non-template-friend")) + warn_nontemplate_friend = setting; + else if (!strcmp (p, "deprecated")) + warn_deprecated = setting; + else if (!strcmp (p, "comment")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "comments")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "trigraphs")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "import")) + ; /* cpp handles this one. */ + else if (!strcmp (p, "all")) + { + warn_return_type = setting; + warn_unused = setting; + warn_implicit = setting; + warn_switch = setting; + warn_format = setting; + warn_parentheses = setting; + warn_missing_braces = setting; + warn_sign_compare = setting; + warn_multichar = setting; + /* We save the value of warn_uninitialized, since if they put + -Wuninitialized on the command line, we need to generate a + warning about not using it without also specifying -O. */ + if (warn_uninitialized != 1) + warn_uninitialized = (setting ? 2 : 0); + /* Only warn about unknown pragmas that are not in system + headers. */ + warn_unknown_pragmas = 1; + + /* C++-specific warnings. */ + warn_ctor_dtor_privacy = setting; + warn_nonvdtor = setting; + warn_reorder = setting; + warn_nontemplate_friend = setting; + } + else return strings_processed; + } + else if (!strcmp (p, "-ansi")) + flag_no_nonansi_builtin = 1, flag_ansi = 1, + flag_no_gnu_keywords = 1, flag_operator_names = 1; +#ifdef SPEW_DEBUG + /* Undocumented, only ever used when you're invoking cc1plus by hand, since + it's probably safe to assume no sane person would ever want to use this + under normal circumstances. */ + else if (!strcmp (p, "-spew-debug")) + spew_debug = 1; +#endif + else + return strings_processed; + + return 1; +} + +/* Incorporate `const' and `volatile' qualifiers for member functions. + FUNCTION is a TYPE_DECL or a FUNCTION_DECL. + QUALS is a list of qualifiers. */ + +tree +grok_method_quals (ctype, function, quals) + tree ctype, function, quals; +{ + tree fntype = TREE_TYPE (function); + tree raises = TYPE_RAISES_EXCEPTIONS (fntype); + int type_quals = TYPE_UNQUALIFIED; + int dup_quals = TYPE_UNQUALIFIED; + + do + { + int tq = cp_type_qual_from_rid (TREE_VALUE (quals)); + + if (type_quals & tq) + dup_quals |= tq; + else + type_quals |= tq; + quals = TREE_CHAIN (quals); + } + while (quals); + + if (dup_quals != TYPE_UNQUALIFIED) + cp_error ("duplicate type qualifiers in %s declaration", + TREE_CODE (function) == FUNCTION_DECL + ? "member function" : "type"); + + ctype = cp_build_qualified_type (ctype, type_quals); + fntype = build_cplus_method_type (ctype, TREE_TYPE (fntype), + (TREE_CODE (fntype) == METHOD_TYPE + ? TREE_CHAIN (TYPE_ARG_TYPES (fntype)) + : TYPE_ARG_TYPES (fntype))); + if (raises) + fntype = build_exception_variant (fntype, raises); + + TREE_TYPE (function) = fntype; + return ctype; +} + +/* Warn when -fexternal-templates is used and #pragma + interface/implementation is not used all the times it should be, + inform the user. */ + +void +warn_if_unknown_interface (decl) + tree decl; +{ + static int already_warned = 0; + if (already_warned++) + return; + + if (flag_alt_external_templates) + { + struct tinst_level *til = tinst_for_decl (); + int sl = lineno; + char *sf = input_filename; + + if (til) + { + lineno = til->line; + input_filename = til->file; + } + cp_warning ("template `%#D' instantiated in file without #pragma interface", + decl); + lineno = sl; + input_filename = sf; + } + else + cp_warning_at ("template `%#D' defined in file without #pragma interface", + decl); +} + +/* A subroutine of the parser, to handle a component list. */ + +void +grok_x_components (specs) + tree specs; +{ + struct pending_inline **p; + tree t; + + specs = strip_attrs (specs); + + check_tag_decl (specs); + t = groktypename (build_decl_list (specs, NULL_TREE)); + + /* The only case where we need to do anything additional here is an + anonymous union field, e.g.: `struct S { union { int i; }; };'. */ + if (t == NULL_TREE || !ANON_UNION_TYPE_P (t)) + return; + + fixup_anonymous_union (t); + finish_member_declaration (build_lang_field_decl (FIELD_DECL, + NULL_TREE, + t)); + + /* Ignore any inline function definitions in the anonymous union + since an anonymous union may not have function members. */ + p = &pending_inlines; + for (; *p; *p = (*p)->next) + if (DECL_CONTEXT ((*p)->fndecl) != t) + break; +} + +/* Constructors for types with virtual baseclasses need an "in-charge" flag + saying whether this constructor is responsible for initialization of + virtual baseclasses or not. All destructors also need this "in-charge" + flag, which additionally determines whether or not the destructor should + free the memory for the object. + + This function adds the "in-charge" flag to member function FN if + appropriate. It is called from grokclassfn and tsubst. + FN must be either a constructor or destructor. */ + +void +maybe_retrofit_in_chrg (fn) + tree fn; +{ + tree basetype, arg_types, parms, parm, fntype; + + if (DECL_CONSTRUCTOR_P (fn) + && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CLASS_CONTEXT (fn)) + && ! DECL_CONSTRUCTOR_FOR_VBASE_P (fn)) + /* OK */; + else if (! DECL_CONSTRUCTOR_P (fn) + && TREE_CHAIN (DECL_ARGUMENTS (fn)) == NULL_TREE) + /* OK */; + else + return; + + if (DECL_CONSTRUCTOR_P (fn)) + DECL_CONSTRUCTOR_FOR_VBASE_P (fn) = 1; + + /* First add it to DECL_ARGUMENTS... */ + parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node); + /* Mark the artificial `__in_chrg' parameter as "artificial". */ + SET_DECL_ARTIFICIAL (parm); + DECL_ARG_TYPE (parm) = integer_type_node; + TREE_READONLY (parm) = 1; + parms = DECL_ARGUMENTS (fn); + TREE_CHAIN (parm) = TREE_CHAIN (parms); + TREE_CHAIN (parms) = parm; + + /* ...and then to TYPE_ARG_TYPES. */ + arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn)); + basetype = TREE_TYPE (TREE_VALUE (arg_types)); + arg_types = hash_tree_chain (integer_type_node, TREE_CHAIN (arg_types)); + fntype = build_cplus_method_type (basetype, TREE_TYPE (TREE_TYPE (fn)), + arg_types); + if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))) + fntype = build_exception_variant (fntype, + TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))); + TREE_TYPE (fn) = fntype; +} + +/* Classes overload their constituent function names automatically. + When a function name is declared in a record structure, + its name is changed to it overloaded name. Since names for + constructors and destructors can conflict, we place a leading + '$' for destructors. + + CNAME is the name of the class we are grokking for. + + FUNCTION is a FUNCTION_DECL. It was created by `grokdeclarator'. + + FLAGS contains bits saying what's special about today's + arguments. 1 == DESTRUCTOR. 2 == OPERATOR. + + If FUNCTION is a destructor, then we must add the `auto-delete' field + as a second parameter. There is some hair associated with the fact + that we must "declare" this variable in the manner consistent with the + way the rest of the arguments were declared. + + QUALS are the qualifiers for the this pointer. */ + +void +grokclassfn (ctype, function, flags, quals) + tree ctype, function; + enum overload_flags flags; + tree quals; +{ + tree fn_name = DECL_NAME (function); + tree arg_types; + tree parm; + tree qualtype; + + if (fn_name == NULL_TREE) + { + error ("name missing for member function"); + fn_name = get_identifier ("<anonymous>"); + DECL_NAME (function) = fn_name; + } + + if (quals) + qualtype = grok_method_quals (ctype, function, quals); + else + qualtype = ctype; + + arg_types = TYPE_ARG_TYPES (TREE_TYPE (function)); + if (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE) + { + /* Must add the class instance variable up front. */ + /* Right now we just make this a pointer. But later + we may wish to make it special. */ + tree type = TREE_VALUE (arg_types); + int constp = 1; + + if ((flag_this_is_variable > 0) + && (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function))) + constp = 0; + + parm = build_decl (PARM_DECL, this_identifier, type); + /* Mark the artificial `this' parameter as "artificial". */ + SET_DECL_ARTIFICIAL (parm); + DECL_ARG_TYPE (parm) = type; + /* We can make this a register, so long as we don't + accidentally complain if someone tries to take its address. */ + DECL_REGISTER (parm) = 1; + if (constp) + TREE_READONLY (parm) = 1; + TREE_CHAIN (parm) = last_function_parms; + last_function_parms = parm; + } + + DECL_ARGUMENTS (function) = last_function_parms; + /* First approximations. */ + DECL_CONTEXT (function) = ctype; + DECL_CLASS_CONTEXT (function) = ctype; + + if (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function)) + { + maybe_retrofit_in_chrg (function); + arg_types = TYPE_ARG_TYPES (TREE_TYPE (function)); + } + + if (flags == DTOR_FLAG) + { + DECL_ASSEMBLER_NAME (function) = build_destructor_name (ctype); + TYPE_HAS_DESTRUCTOR (ctype) = 1; + } + else + set_mangled_name_for_decl (function); +} + +/* Work on the expr used by alignof (this is only called by the parser). */ + +tree +grok_alignof (expr) + tree expr; +{ + tree best, t; + int bestalign; + + if (processing_template_decl) + return build_min (ALIGNOF_EXPR, sizetype, expr); + + if (TREE_CODE (expr) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1))) + error ("`__alignof__' applied to a bit-field"); + + if (TREE_CODE (expr) == INDIRECT_REF) + { + best = t = TREE_OPERAND (expr, 0); + bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + + while (TREE_CODE (t) == NOP_EXPR + && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE) + { + int thisalign; + t = TREE_OPERAND (t, 0); + thisalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t))); + if (thisalign > bestalign) + best = t, bestalign = thisalign; + } + return c_alignof (TREE_TYPE (TREE_TYPE (best))); + } + else + { + /* ANSI says arrays and fns are converted inside comma. + But we can't convert them in build_compound_expr + because that would break commas in lvalues. + So do the conversion here if operand was a comma. */ + if (TREE_CODE (expr) == COMPOUND_EXPR + && (TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)) + expr = default_conversion (expr); + return c_alignof (TREE_TYPE (expr)); + } +} + +/* Create an ARRAY_REF, checking for the user doing things backwards + along the way. */ + +tree +grok_array_decl (array_expr, index_exp) + tree array_expr, index_exp; +{ + tree type = TREE_TYPE (array_expr); + tree p1, p2, i1, i2; + + if (type == error_mark_node || index_exp == error_mark_node) + return error_mark_node; + if (processing_template_decl) + return build_min (ARRAY_REF, type ? TREE_TYPE (type) : NULL_TREE, + array_expr, index_exp); + + if (type == NULL_TREE) + { + /* Something has gone very wrong. Assume we are mistakenly reducing + an expression instead of a declaration. */ + error ("parser may be lost: is there a '{' missing somewhere?"); + return NULL_TREE; + } + + if (TREE_CODE (type) == OFFSET_TYPE + || TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + + /* If they have an `operator[]', use that. */ + if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp))) + return build_opfncall (ARRAY_REF, LOOKUP_NORMAL, + array_expr, index_exp, NULL_TREE); + + /* Otherwise, create an ARRAY_REF for a pointer or array type. It + is a little-known fact that, if `a' is an array and `i' is an + int, you can write `i[a]', which means the same thing as `a[i]'. */ + + if (TREE_CODE (type) == ARRAY_TYPE) + p1 = array_expr; + else + p1 = build_expr_type_conversion (WANT_POINTER, array_expr, 0); + + if (TREE_CODE (TREE_TYPE (index_exp)) == ARRAY_TYPE) + p2 = index_exp; + else + p2 = build_expr_type_conversion (WANT_POINTER, index_exp, 0); + + i1 = build_expr_type_conversion (WANT_INT | WANT_ENUM, array_expr, 0); + i2 = build_expr_type_conversion (WANT_INT | WANT_ENUM, index_exp, 0); + + if ((p1 && i2) && (i1 && p2)) + error ("ambiguous conversion for array subscript"); + + if (p1 && i2) + array_expr = p1, index_exp = i2; + else if (i1 && p2) + array_expr = p2, index_exp = i1; + else + { + cp_error ("invalid types `%T[%T]' for array subscript", + type, TREE_TYPE (index_exp)); + return error_mark_node; + } + + if (array_expr == error_mark_node || index_exp == error_mark_node) + error ("ambiguous conversion for array subscript"); + + return build_array_ref (array_expr, index_exp); +} + +/* Given the cast expression EXP, checking out its validity. Either return + an error_mark_node if there was an unavoidable error, return a cast to + void for trying to delete a pointer w/ the value 0, or return the + call to delete. If DOING_VEC is 1, we handle things differently + for doing an array delete. If DOING_VEC is 2, they gave us the + array size as an argument to delete. + Implements ARM $5.3.4. This is called from the parser. */ + +tree +delete_sanity (exp, size, doing_vec, use_global_delete) + tree exp, size; + int doing_vec, use_global_delete; +{ + tree t, type; + /* For a regular vector delete (aka, no size argument) we will pass + this down as a NULL_TREE into build_vec_delete. */ + tree maxindex = NULL_TREE; + + if (exp == error_mark_node) + return exp; + + if (processing_template_decl) + { + t = build_min (DELETE_EXPR, void_type_node, exp, size); + DELETE_EXPR_USE_GLOBAL (t) = use_global_delete; + DELETE_EXPR_USE_VEC (t) = doing_vec; + return t; + } + + if (TREE_CODE (exp) == OFFSET_REF) + exp = resolve_offset_ref (exp); + exp = convert_from_reference (exp); + t = stabilize_reference (exp); + t = build_expr_type_conversion (WANT_POINTER, t, 1); + + if (t == NULL_TREE || t == error_mark_node) + { + cp_error ("type `%#T' argument given to `delete', expected pointer", + TREE_TYPE (exp)); + return error_mark_node; + } + + if (doing_vec == 2) + { + maxindex = build_binary_op (MINUS_EXPR, size, integer_one_node); + pedwarn ("anachronistic use of array size in vector delete"); + } + + type = TREE_TYPE (t); + + /* As of Valley Forge, you can delete a pointer to const. */ + + /* You can't delete functions. */ + if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + { + error ("cannot delete a function"); + return error_mark_node; + } + + /* Deleting ptr to void is undefined behaviour [expr.delete/3]. */ + if (TREE_CODE (TREE_TYPE (type)) == VOID_TYPE) + cp_warning ("`%T' is not a pointer-to-object type", type); + + /* An array can't have been allocated by new, so complain. */ + if (TREE_CODE (t) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (t, 0)) == VAR_DECL + && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == ARRAY_TYPE) + cp_warning ("deleting array `%#D'", TREE_OPERAND (t, 0)); + + /* Deleting a pointer with the value zero is valid and has no effect. */ + if (integer_zerop (t)) + return build1 (NOP_EXPR, void_type_node, t); + + if (doing_vec) + return build_vec_delete (t, maxindex, integer_one_node, + integer_zero_node, use_global_delete); + else + { + if (IS_AGGR_TYPE (TREE_TYPE (type)) + && TYPE_GETS_REG_DELETE (TREE_TYPE (type))) + { + /* Only do access checking here; we'll be calling op delete + from the destructor. */ + tree tmp = build_op_delete_call (DELETE_EXPR, t, size_zero_node, + LOOKUP_NORMAL, NULL_TREE); + if (tmp == error_mark_node) + return error_mark_node; + } + + return build_delete (type, t, integer_three_node, + LOOKUP_NORMAL, use_global_delete); + } +} + +/* Report an error if the indicated template declaration is not the + sort of thing that should be a member template. */ + +void +check_member_template (tmpl) + tree tmpl; +{ + tree decl; + + my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0); + decl = DECL_TEMPLATE_RESULT (tmpl); + + if (TREE_CODE (decl) == FUNCTION_DECL + || (TREE_CODE (decl) == TYPE_DECL + && IS_AGGR_TYPE (TREE_TYPE (decl)))) + { + if (current_function_decl) + /* 14.5.2.2 [temp.mem] + + A local class shall not have member templates. */ + cp_error ("declaration of member template `%#D' in local class", + decl); + + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl)) + { + /* 14.5.2.3 [temp.mem] + + A member function template shall not be virtual. */ + cp_error + ("invalid use of `virtual' in template declaration of `%#D'", + decl); + DECL_VIRTUAL_P (decl) = 0; + } + + /* The debug-information generating code doesn't know what to do + with member templates. */ + DECL_IGNORED_P (tmpl) = 1; + } + else + cp_error ("template declaration of `%#D'", decl); +} + +/* Return true iff TYPE is a valid Java parameter or return type. */ + +static int +acceptable_java_type (type) + tree type; +{ + if (TREE_CODE (type) == VOID_TYPE || TYPE_FOR_JAVA (type)) + return 1; + if (TREE_CODE (type) == POINTER_TYPE) + { + type = TREE_TYPE (type); + if (TREE_CODE (type) == RECORD_TYPE) + { + tree args; int i; + if (! TYPE_FOR_JAVA (type)) + return 0; + if (! CLASSTYPE_TEMPLATE_INFO (type)) + return 1; + args = CLASSTYPE_TI_ARGS (type); + i = TREE_VEC_LENGTH (args); + while (--i >= 0) + { + type = TREE_VEC_ELT (args, i); + if (TREE_CODE (type) == POINTER_TYPE) + type = TREE_TYPE (type); + if (! TYPE_FOR_JAVA (type)) + return 0; + } + return 1; + } + } + return 0; +} + +/* For a METHOD in a Java class CTYPE, return 1 if + the parameter and return types are valid Java types. + Otherwise, print appropriate error messages, and return 0. */ + +int +check_java_method (method) + tree method; +{ + int jerr = 0; + tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (method)); + tree ret_type = TREE_TYPE (TREE_TYPE (method)); + if (! acceptable_java_type (ret_type)) + { + cp_error ("Java method '%D' has non-Java return type `%T'", + method, ret_type); + jerr++; + } + for (; arg_types != NULL_TREE; arg_types = TREE_CHAIN (arg_types)) + { + tree type = TREE_VALUE (arg_types); + if (! acceptable_java_type (type)) + { + cp_error ("Java method '%D' has non-Java parameter type `%T'", + method, type); + jerr++; + } + } + return jerr ? 0 : 1; +} + +/* Sanity check: report error if this function FUNCTION is not + really a member of the class (CTYPE) it is supposed to belong to. + CNAME is the same here as it is for grokclassfn above. */ + +tree +check_classfn (ctype, function) + tree ctype, function; +{ + tree fn_name = DECL_NAME (function); + tree fndecl, fndecls; + tree method_vec = CLASSTYPE_METHOD_VEC (complete_type (ctype)); + tree *methods = 0; + tree *end = 0; + + if (DECL_USE_TEMPLATE (function) + && is_member_template (DECL_TI_TEMPLATE (function))) + /* Since this is a specialization of a member template, + we're not going to find the declaration in the class. + For example, in: + + struct S { template <typename T> void f(T); }; + template <> void S::f(int); + + we're not going to find `S::f(int)', but there's no + reason we should, either. We let our callers know we didn't + find the method, but we don't complain. */ + return NULL_TREE; + + if (method_vec != 0) + { + methods = &TREE_VEC_ELT (method_vec, 0); + end = TREE_VEC_END (method_vec); + + /* First suss out ctors and dtors. */ + if (*methods && fn_name == DECL_NAME (OVL_CURRENT (*methods)) + && DECL_CONSTRUCTOR_P (function)) + goto got_it; + if (*++methods && fn_name == DECL_NAME (OVL_CURRENT (*methods)) + && DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function))) + goto got_it; + + while (++methods != end && *methods) + { + fndecl = *methods; + if (fn_name == DECL_NAME (OVL_CURRENT (*methods))) + { + got_it: + for (fndecls = *methods; fndecls != NULL_TREE; + fndecls = OVL_NEXT (fndecls)) + { + fndecl = OVL_CURRENT (fndecls); + /* The DECL_ASSEMBLER_NAME for a TEMPLATE_DECL, or + for a for member function of a template class, is + not mangled, so the check below does not work + correctly in that case. Since mangled destructor + names do not include the type of the arguments, + we can't use this short-cut for them, either. + (It's not legal to declare arguments for a + destructor, but some people try.) */ + if (!DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function)) + && (DECL_ASSEMBLER_NAME (function) + != DECL_NAME (function)) + && (DECL_ASSEMBLER_NAME (fndecl) + != DECL_NAME (fndecl)) + && (DECL_ASSEMBLER_NAME (function) + == DECL_ASSEMBLER_NAME (fndecl))) + return fndecl; + + /* We cannot simply call decls_match because this + doesn't work for static member functions that are + pretending to be methods, and because the name + may have been changed by asm("new_name"). */ + if (DECL_NAME (function) == DECL_NAME (fndecl)) + { + tree p1 = TYPE_ARG_TYPES (TREE_TYPE (function)); + tree p2 = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); + + /* Get rid of the this parameter on functions that become + static. */ + if (DECL_STATIC_FUNCTION_P (fndecl) + && TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE) + p1 = TREE_CHAIN (p1); + + if (same_type_p (TREE_TYPE (TREE_TYPE (function)), + TREE_TYPE (TREE_TYPE (fndecl))) + && compparms (p1, p2) + && (DECL_TEMPLATE_SPECIALIZATION (function) + == DECL_TEMPLATE_SPECIALIZATION (fndecl)) + && (!DECL_TEMPLATE_SPECIALIZATION (function) + || (DECL_TI_TEMPLATE (function) + == DECL_TI_TEMPLATE (fndecl)))) + return fndecl; + } + } + break; /* loser */ + } + } + } + + if (methods != end && *methods) + { + tree fndecl = *methods; + cp_error ("prototype for `%#D' does not match any in class `%T'", + function, ctype); + cp_error_at ("candidate%s: %+#D", OVL_NEXT (fndecl) ? "s are" : " is", + OVL_CURRENT (fndecl)); + while (fndecl = OVL_NEXT (fndecl), fndecl) + cp_error_at (" %#D", OVL_CURRENT(fndecl)); + } + else + { + methods = 0; + if (TYPE_SIZE (ctype) == 0) + incomplete_type_error (function, ctype); + else + cp_error ("no `%#D' member function declared in class `%T'", + function, ctype); + } + + /* If we did not find the method in the class, add it to avoid + spurious errors (unless the CTYPE is not yet defined, in which + case we'll only confuse ourselves when the function is declared + properly within the class. */ + if (TYPE_SIZE (ctype)) + add_method (ctype, methods, function); + return NULL_TREE; +} + +/* We have just processed the DECL, which is a static data member. + Its initializer, if present, is INIT. The ASMSPEC_TREE, if + present, is the assembly-language name for the data member. + NEED_POP and FLAGS are as for cp_finish_decl. */ + +void +finish_static_data_member_decl (decl, init, asmspec_tree, need_pop, flags) + tree decl; + tree init; + tree asmspec_tree; + int need_pop; + int flags; +{ + char* asmspec = 0; + + if (asmspec_tree) + asmspec = TREE_STRING_POINTER (asmspec_tree); + + my_friendly_assert (TREE_PUBLIC (decl), 0); + + /* We cannot call pushdecl here, because that would fill in the + decl of our TREE_CHAIN. Instead, we modify cp_finish_decl to do + the right thing, namely, to put this decl out straight away. */ + /* current_class_type can be NULL_TREE in case of error. */ + if (!asmspec && current_class_type) + { + DECL_INITIAL (decl) = error_mark_node; + DECL_ASSEMBLER_NAME (decl) + = build_static_name (current_class_type, DECL_NAME (decl)); + } + if (! processing_template_decl) + { + if (!pending_statics) + VARRAY_TREE_INIT (pending_statics, 32, "pending_statics"); + + if (pending_statics_used == pending_statics->num_elements) + VARRAY_GROW (pending_statics, + 2 * pending_statics->num_elements); + VARRAY_TREE (pending_statics, pending_statics_used) = decl; + ++pending_statics_used; + } + + /* Static consts need not be initialized in the class definition. */ + if (init != NULL_TREE && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) + { + static int explanation = 0; + + error ("initializer invalid for static member with constructor"); + if (explanation++ == 0) + error ("(you really want to initialize it separately)"); + init = 0; + } + /* Force the compiler to know when an uninitialized static const + member is being used. */ + if (CP_TYPE_CONST_P (TREE_TYPE (decl)) && init == 0) + TREE_USED (decl) = 1; + DECL_INITIAL (decl) = init; + DECL_IN_AGGR_P (decl) = 1; + DECL_CONTEXT (decl) = current_class_type; + DECL_CLASS_CONTEXT (decl) = current_class_type; + + cp_finish_decl (decl, init, asmspec_tree, need_pop, flags); +} + +/* Process the specs, declarator (NULL if omitted) and width (NULL if omitted) + of a structure component, returning a FIELD_DECL node. + QUALS is a list of type qualifiers for this decl (such as for declaring + const member functions). + + This is done during the parsing of the struct declaration. + The FIELD_DECL nodes are chained together and the lot of them + are ultimately passed to `build_struct' to make the RECORD_TYPE node. + + C++: + + If class A defines that certain functions in class B are friends, then + the way I have set things up, it is B who is interested in permission + granted by A. However, it is in A's context that these declarations + are parsed. By returning a void_type_node, class A does not attempt + to incorporate the declarations of the friends within its structure. + + DO NOT MAKE ANY CHANGES TO THIS CODE WITHOUT MAKING CORRESPONDING + CHANGES TO CODE IN `start_method'. */ + +tree +grokfield (declarator, declspecs, init, asmspec_tree, attrlist) + tree declarator, declspecs, init, asmspec_tree, attrlist; +{ + register tree value; + char *asmspec = 0; + int flags = LOOKUP_ONLYCONVERTING; + + /* Convert () initializers to = initializers. */ + if (init == NULL_TREE && declarator != NULL_TREE + && TREE_CODE (declarator) == CALL_EXPR + && TREE_OPERAND (declarator, 0) + && (TREE_CODE (TREE_OPERAND (declarator, 0)) == IDENTIFIER_NODE + || TREE_CODE (TREE_OPERAND (declarator, 0)) == SCOPE_REF) + && parmlist_is_exprlist (TREE_OPERAND (declarator, 1))) + { + init = TREE_OPERAND (declarator, 1); + declarator = TREE_OPERAND (declarator, 0); + flags = 0; + } + + if (declspecs == NULL_TREE + && TREE_CODE (declarator) == SCOPE_REF + && TREE_CODE (TREE_OPERAND (declarator, 1)) == IDENTIFIER_NODE) + { + /* Access declaration */ + if (! IS_AGGR_TYPE_CODE (TREE_CODE (TREE_OPERAND (declarator, 0)))) + ; + else if (TREE_COMPLEXITY (declarator) == current_class_depth) + pop_nested_class (); + return do_class_using_decl (declarator); + } + + if (init + && TREE_CODE (init) == TREE_LIST + && TREE_VALUE (init) == error_mark_node + && TREE_CHAIN (init) == NULL_TREE) + init = NULL_TREE; + + value = grokdeclarator (declarator, declspecs, FIELD, init != 0, attrlist); + if (! value || value == error_mark_node) + /* friend or constructor went bad. */ + return value; + + /* Pass friendly classes back. */ + if (TREE_CODE (value) == VOID_TYPE) + return void_type_node; + + if (DECL_NAME (value) != NULL_TREE + && IDENTIFIER_POINTER (DECL_NAME (value))[0] == '_' + && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (value)), "_vptr")) + cp_error ("member `%D' conflicts with virtual function table field name", + value); + + /* Stash away type declarations. */ + if (TREE_CODE (value) == TYPE_DECL) + { + DECL_NONLOCAL (value) = 1; + DECL_CONTEXT (value) = current_class_type; + DECL_CLASS_CONTEXT (value) = current_class_type; + + /* Now that we've updated the context, we need to remangle the + name for this TYPE_DECL. */ + DECL_ASSEMBLER_NAME (value) = DECL_NAME (value); + if (!uses_template_parms (value)) + DECL_ASSEMBLER_NAME (value) = + get_identifier (build_overload_name (TREE_TYPE (value), 1, 1)); + + return value; + } + + if (IS_SIGNATURE (current_class_type) + && TREE_CODE (value) != FUNCTION_DECL) + { + error ("field declaration not allowed in signature"); + return void_type_node; + } + + if (DECL_IN_AGGR_P (value)) + { + cp_error ("`%D' is already defined in `%T'", value, + DECL_CONTEXT (value)); + return void_type_node; + } + + if (asmspec_tree) + asmspec = TREE_STRING_POINTER (asmspec_tree); + + if (init) + { + if (IS_SIGNATURE (current_class_type) + && TREE_CODE (value) == FUNCTION_DECL) + { + error ("function declarations cannot have initializers in signature"); + init = NULL_TREE; + } + else if (TREE_CODE (value) == FUNCTION_DECL) + { + grok_function_init (value, init); + init = NULL_TREE; + } + else if (pedantic && TREE_CODE (value) != VAR_DECL) + /* Already complained in grokdeclarator. */ + init = NULL_TREE; + else + { + /* We allow initializers to become parameters to base + initializers. */ + if (TREE_CODE (init) == TREE_LIST) + { + if (TREE_CHAIN (init) == NULL_TREE) + init = TREE_VALUE (init); + else + init = digest_init (TREE_TYPE (value), init, (tree *)0); + } + + if (TREE_CODE (init) == CONST_DECL) + init = DECL_INITIAL (init); + else if (TREE_READONLY_DECL_P (init)) + init = decl_constant_value (init); + else if (TREE_CODE (init) == CONSTRUCTOR) + init = digest_init (TREE_TYPE (value), init, (tree *)0); + my_friendly_assert (TREE_PERMANENT (init), 192); + if (init == error_mark_node) + /* We must make this look different than `error_mark_node' + because `decl_const_value' would mis-interpret it + as only meaning that this VAR_DECL is defined. */ + init = build1 (NOP_EXPR, TREE_TYPE (value), init); + else if (processing_template_decl) + ; + else if (! TREE_CONSTANT (init)) + { + /* We can allow references to things that are effectively + static, since references are initialized with the address. */ + if (TREE_CODE (TREE_TYPE (value)) != REFERENCE_TYPE + || (TREE_STATIC (init) == 0 + && (TREE_CODE_CLASS (TREE_CODE (init)) != 'd' + || DECL_EXTERNAL (init) == 0))) + { + error ("field initializer is not constant"); + init = error_mark_node; + } + } + } + } + + /* The corresponding pop_obstacks is in cp_finish_decl. */ + push_obstacks_nochange (); + + if (processing_template_decl && ! current_function_decl + && (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == FUNCTION_DECL)) + value = push_template_decl (value); + + if (attrlist) + cplus_decl_attributes (value, TREE_PURPOSE (attrlist), + TREE_VALUE (attrlist)); + + if (TREE_CODE (value) == VAR_DECL) + { + finish_static_data_member_decl (value, init, asmspec_tree, + /*need_pop=*/1, flags); + return value; + } + if (TREE_CODE (value) == FIELD_DECL) + { + if (asmspec) + { + /* This must override the asm specifier which was placed + by grokclassfn. Lay this out fresh. */ + DECL_RTL (value) = NULL_RTX; + DECL_ASSEMBLER_NAME (value) = get_identifier (asmspec); + } + if (DECL_INITIAL (value) == error_mark_node) + init = error_mark_node; + cp_finish_decl (value, init, asmspec_tree, 1, flags); + DECL_INITIAL (value) = init; + DECL_IN_AGGR_P (value) = 1; + return value; + } + if (TREE_CODE (value) == FUNCTION_DECL) + { + if (asmspec) + { + /* This must override the asm specifier which was placed + by grokclassfn. Lay this out fresh. */ + DECL_RTL (value) = NULL_RTX; + DECL_ASSEMBLER_NAME (value) = get_identifier (asmspec); + } + cp_finish_decl (value, init, asmspec_tree, 1, flags); + + /* Pass friends back this way. */ + if (DECL_FRIEND_P (value)) + return void_type_node; + +#if 0 /* Just because a fn is declared doesn't mean we'll try to define it. */ + if (current_function_decl && ! IS_SIGNATURE (current_class_type)) + cp_error ("method `%#D' of local class must be defined in class body", + value); +#endif + + DECL_IN_AGGR_P (value) = 1; + return value; + } + my_friendly_abort (21); + /* NOTREACHED */ + return NULL_TREE; +} + +/* Like `grokfield', but for bitfields. + WIDTH is non-NULL for bit fields only, and is an INTEGER_CST node. */ + +tree +grokbitfield (declarator, declspecs, width) + tree declarator, declspecs, width; +{ + register tree value = grokdeclarator (declarator, declspecs, BITFIELD, + 0, NULL_TREE); + + if (! value) return NULL_TREE; /* friends went bad. */ + + /* Pass friendly classes back. */ + if (TREE_CODE (value) == VOID_TYPE) + return void_type_node; + + if (TREE_CODE (value) == TYPE_DECL) + { + cp_error ("cannot declare `%D' to be a bitfield type", value); + return NULL_TREE; + } + + /* Usually, finish_struct_1 catches bitifields with invalid types. + But, in the case of bitfields with function type, we confuse + ourselves into thinking they are member functions, so we must + check here. */ + if (TREE_CODE (value) == FUNCTION_DECL) + { + cp_error ("cannot declare bitfield `%D' with funcion type", + DECL_NAME (value)); + return NULL_TREE; + } + + if (IS_SIGNATURE (current_class_type)) + { + error ("field declaration not allowed in signature"); + return void_type_node; + } + + if (DECL_IN_AGGR_P (value)) + { + cp_error ("`%D' is already defined in the class %T", value, + DECL_CONTEXT (value)); + return void_type_node; + } + + GNU_xref_member (current_class_name, value); + + if (TREE_STATIC (value)) + { + cp_error ("static member `%D' cannot be a bitfield", value); + return NULL_TREE; + } + cp_finish_decl (value, NULL_TREE, NULL_TREE, 0, 0); + + if (width != error_mark_node) + { + constant_expression_warning (width); + DECL_INITIAL (value) = width; + SET_DECL_C_BIT_FIELD (value); + } + + DECL_IN_AGGR_P (value) = 1; + return value; +} + +tree +grokoptypename (declspecs, declarator) + tree declspecs, declarator; +{ + tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL_TREE); + return build_typename_overload (t); +} + +/* When a function is declared with an initializer, + do the right thing. Currently, there are two possibilities: + + class B + { + public: + // initialization possibility #1. + virtual void f () = 0; + int g (); + }; + + class D1 : B + { + public: + int d1; + // error, no f (); + }; + + class D2 : B + { + public: + int d2; + void f (); + }; + + class D3 : B + { + public: + int d3; + // initialization possibility #2 + void f () = B::f; + }; + +*/ + +int +copy_assignment_arg_p (parmtype, virtualp) + tree parmtype; + int virtualp ATTRIBUTE_UNUSED; +{ + if (current_class_type == NULL_TREE) + return 0; + + if (TREE_CODE (parmtype) == REFERENCE_TYPE) + parmtype = TREE_TYPE (parmtype); + + if ((TYPE_MAIN_VARIANT (parmtype) == current_class_type) +#if 0 + /* Non-standard hack to support old Booch components. */ + || (! virtualp && DERIVED_FROM_P (parmtype, current_class_type)) +#endif + ) + return 1; + + return 0; +} + +static void +grok_function_init (decl, init) + tree decl; + tree init; +{ + /* An initializer for a function tells how this function should + be inherited. */ + tree type = TREE_TYPE (decl); + + if (TREE_CODE (type) == FUNCTION_TYPE) + cp_error ("initializer specified for non-member function `%D'", decl); +#if 0 + /* We'll check for this in finish_struct_1. */ + else if (DECL_VINDEX (decl) == NULL_TREE) + cp_error ("initializer specified for non-virtual method `%D'", decl); +#endif + else if (integer_zerop (init)) + { +#if 0 + /* Mark this function as being "defined". */ + DECL_INITIAL (decl) = error_mark_node; + /* pure virtual destructors must be defined. */ + /* pure virtual needs to be defined (as abort) only when put in + vtbl. For wellformed call, it should be itself. pr4737 */ + if (!DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl))) + { + extern tree abort_fndecl; + /* Give this node rtl from `abort'. */ + DECL_RTL (decl) = DECL_RTL (abort_fndecl); + } +#endif + DECL_ABSTRACT_VIRTUAL_P (decl) = 1; + if (DECL_NAME (decl) == ansi_opname [(int) MODIFY_EXPR]) + { + tree parmtype + = TREE_VALUE (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl)))); + + if (copy_assignment_arg_p (parmtype, 1)) + TYPE_HAS_ABSTRACT_ASSIGN_REF (current_class_type) = 1; + } + } + else + cp_error ("invalid initializer for virtual method `%D'", decl); +} + +void +cplus_decl_attributes (decl, attributes, prefix_attributes) + tree decl, attributes, prefix_attributes; +{ + if (decl == NULL_TREE || decl == void_type_node) + return; + + if (TREE_CODE (decl) == TEMPLATE_DECL) + decl = DECL_TEMPLATE_RESULT (decl); + + decl_attributes (decl, attributes, prefix_attributes); + + if (TREE_CODE (decl) == TYPE_DECL) + SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (decl), TREE_TYPE (decl)); +} + +/* CONSTRUCTOR_NAME: + Return the name for the constructor (or destructor) for the + specified class. Argument can be RECORD_TYPE, TYPE_DECL, or + IDENTIFIER_NODE. When given a template, this routine doesn't + lose the specialization. */ + +tree +constructor_name_full (thing) + tree thing; +{ + if (TREE_CODE (thing) == TEMPLATE_TYPE_PARM + || TREE_CODE (thing) == TEMPLATE_TEMPLATE_PARM + || TREE_CODE (thing) == TYPENAME_TYPE) + thing = TYPE_NAME (thing); + else if (IS_AGGR_TYPE_CODE (TREE_CODE (thing))) + { + if (TYPE_WAS_ANONYMOUS (thing) && TYPE_HAS_CONSTRUCTOR (thing)) + thing = DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (thing), 0))); + else + thing = TYPE_NAME (thing); + } + if (TREE_CODE (thing) == TYPE_DECL + || (TREE_CODE (thing) == TEMPLATE_DECL + && TREE_CODE (DECL_TEMPLATE_RESULT (thing)) == TYPE_DECL)) + thing = DECL_NAME (thing); + my_friendly_assert (TREE_CODE (thing) == IDENTIFIER_NODE, 197); + return thing; +} + +/* CONSTRUCTOR_NAME: + Return the name for the constructor (or destructor) for the + specified class. Argument can be RECORD_TYPE, TYPE_DECL, or + IDENTIFIER_NODE. When given a template, return the plain + unspecialized name. */ + +tree +constructor_name (thing) + tree thing; +{ + tree t; + thing = constructor_name_full (thing); + t = IDENTIFIER_TEMPLATE (thing); + if (!t) + return thing; + return t; +} + +/* Cache the value of this class's main virtual function table pointer + in a register variable. This will save one indirection if a + more than one virtual function call is made this function. */ + +void +setup_vtbl_ptr () +{ + extern tree base_init_expr; + + if (base_init_expr == 0 + && DECL_CONSTRUCTOR_P (current_function_decl)) + { + if (processing_template_decl) + add_tree (build_min_nt + (CTOR_INITIALIZER, + current_member_init_list, current_base_init_list)); + else + emit_base_init (current_class_type, 0); + } +} + +/* Record the existence of an addressable inline function. */ + +void +mark_inline_for_output (decl) + tree decl; +{ + decl = DECL_MAIN_VARIANT (decl); + if (DECL_SAVED_INLINE (decl)) + return; + my_friendly_assert (TREE_PERMANENT (decl), 363); + DECL_SAVED_INLINE (decl) = 1; + if (!saved_inlines) + VARRAY_TREE_INIT (saved_inlines, 32, "saved_inlines"); + + if (saved_inlines_used == saved_inlines->num_elements) + VARRAY_GROW (saved_inlines, + 2 * saved_inlines->num_elements); + VARRAY_TREE (saved_inlines, saved_inlines_used) = decl; + ++saved_inlines_used; +} + +void +clear_temp_name () +{ + temp_name_counter = 0; +} + +/* Hand off a unique name which can be used for variable we don't really + want to know about anyway, for example, the anonymous variables which + are needed to make references work. Declare this thing so we can use it. + The variable created will be of type TYPE. + + STATICP is nonzero if this variable should be static. */ + +tree +get_temp_name (type, staticp) + tree type; + int staticp; +{ + char buf[sizeof (AUTO_TEMP_FORMAT) + 20]; + tree decl; + int toplev = toplevel_bindings_p (); + + push_obstacks_nochange (); + if (toplev || staticp) + { + end_temporary_allocation (); + sprintf (buf, AUTO_TEMP_FORMAT, global_temp_name_counter++); + decl = pushdecl_top_level (build_decl (VAR_DECL, get_identifier (buf), type)); + } + else + { + sprintf (buf, AUTO_TEMP_FORMAT, temp_name_counter++); + decl = pushdecl (build_decl (VAR_DECL, get_identifier (buf), type)); + } + TREE_USED (decl) = 1; + TREE_STATIC (decl) = staticp; + DECL_ARTIFICIAL (decl) = 1; + + /* If this is a local variable, then lay out its rtl now. + Otherwise, callers of this function are responsible for dealing + with this variable's rtl. */ + if (! toplev) + { + expand_decl (decl); + expand_decl_init (decl); + } + pop_obstacks (); + + return decl; +} + +/* Get a variable which we can use for multiple assignments. + It is not entered into current_binding_level, because + that breaks things when it comes time to do final cleanups + (which take place "outside" the binding contour of the function). */ + +tree +get_temp_regvar (type, init) + tree type, init; +{ + tree decl; + + decl = build_decl (VAR_DECL, NULL_TREE, type); + TREE_USED (decl) = 1; + DECL_REGISTER (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + + DECL_RTL (decl) = assign_temp (type, 2, 0, 1); + /* We can expand these without fear, since they cannot need + constructors or destructors. */ + expand_expr (build_modify_expr (decl, INIT_EXPR, init), + NULL_RTX, VOIDmode, 0); + + return decl; +} + +/* Hunts through the global anonymous union ANON_DECL, building + appropriate VAR_DECLs. Stores cleanups on the list of ELEMS, and + returns a VAR_DECL whose size is the same as the size of the + ANON_DECL, if one is available. */ + +static tree +build_anon_union_vars (anon_decl, elems, static_p, external_p) + tree anon_decl; + tree* elems; + int static_p; + int external_p; +{ + tree type = TREE_TYPE (anon_decl); + tree main_decl = NULL_TREE; + tree field; + + for (field = TYPE_FIELDS (type); + field != NULL_TREE; + field = TREE_CHAIN (field)) + { + tree decl; + + if (DECL_ARTIFICIAL (field)) + continue; + if (TREE_CODE (field) != FIELD_DECL) + { + cp_pedwarn_at ("`%#D' invalid; an anonymous union can only have non-static data members", + field); + continue; + } + + if (TREE_PRIVATE (field)) + cp_pedwarn_at ("private member `%#D' in anonymous union", field); + else if (TREE_PROTECTED (field)) + cp_pedwarn_at ("protected member `%#D' in anonymous union", field); + + if (DECL_NAME (field) == NULL_TREE + && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) + { + decl = build_anon_union_vars (field, elems, static_p, external_p); + if (!decl) + continue; + } + else if (DECL_NAME (field) == NULL_TREE) + continue; + else + { + decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field)); + /* tell `pushdecl' that this is not tentative. */ + DECL_INITIAL (decl) = error_mark_node; + TREE_PUBLIC (decl) = 0; + TREE_STATIC (decl) = static_p; + DECL_EXTERNAL (decl) = external_p; + decl = pushdecl (decl); + DECL_INITIAL (decl) = NULL_TREE; + } + + /* Only write out one anon union element--choose the one that + can hold them all. */ + if (main_decl == NULL_TREE + && simple_cst_equal (DECL_SIZE (decl), + DECL_SIZE (anon_decl)) == 1) + main_decl = decl; + else + /* ??? This causes there to be no debug info written out + about this decl. */ + TREE_ASM_WRITTEN (decl) = 1; + + if (DECL_NAME (field) == NULL_TREE + && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) + /* The remainder of the processing was already done in the + recursive call. */ + continue; + + /* If there's a cleanup to do, it belongs in the + TREE_PURPOSE of the following TREE_LIST. */ + *elems = scratch_tree_cons (NULL_TREE, decl, *elems); + TREE_TYPE (*elems) = type; + } + + return main_decl; +} + +/* Finish off the processing of a UNION_TYPE structure. + If there are static members, then all members are + static, and must be laid out together. If the + union is an anonymous union, we arrange for that + as well. PUBLIC_P is nonzero if this union is + not declared static. */ + +void +finish_anon_union (anon_union_decl) + tree anon_union_decl; +{ + tree type = TREE_TYPE (anon_union_decl); + tree elems = NULL_TREE; + tree main_decl; + int public_p = TREE_PUBLIC (anon_union_decl); + int static_p = TREE_STATIC (anon_union_decl); + int external_p = DECL_EXTERNAL (anon_union_decl); + + if (TYPE_FIELDS (type) == NULL_TREE) + return; + + if (public_p) + { + error ("global anonymous unions must be declared static"); + return; + } + + main_decl = build_anon_union_vars (anon_union_decl, &elems, + static_p, external_p); + + if (main_decl == NULL_TREE) + { + warning ("anonymous union with no members"); + return; + } + + if (static_p) + { + make_decl_rtl (main_decl, 0, toplevel_bindings_p ()); + DECL_RTL (anon_union_decl) = DECL_RTL (main_decl); + } + + /* The following call assumes that there are never any cleanups + for anonymous unions--a reasonable assumption. */ + expand_anon_union_decl (anon_union_decl, NULL_TREE, elems); +} + +/* Finish processing a builtin type TYPE. It's name is NAME, + its fields are in the array FIELDS. LEN is the number of elements + in FIELDS minus one, or put another way, it is the maximum subscript + used in FIELDS. + + It is given the same alignment as ALIGN_TYPE. */ + +void +finish_builtin_type (type, name, fields, len, align_type) + tree type; + const char *name; + tree fields[]; + int len; + tree align_type; +{ + register int i; + + TYPE_FIELDS (type) = fields[0]; + for (i = 0; i < len; i++) + { + layout_type (TREE_TYPE (fields[i])); + DECL_FIELD_CONTEXT (fields[i]) = type; + TREE_CHAIN (fields[i]) = fields[i+1]; + } + DECL_FIELD_CONTEXT (fields[i]) = type; + DECL_CLASS_CONTEXT (fields[i]) = type; + TYPE_ALIGN (type) = TYPE_ALIGN (align_type); + layout_type (type); +#if 0 /* not yet, should get fixed properly later */ + TYPE_NAME (type) = make_type_decl (get_identifier (name), type); +#else + TYPE_NAME (type) = build_decl (TYPE_DECL, get_identifier (name), type); +#endif + TYPE_STUB_DECL (type) = TYPE_NAME (type); + layout_decl (TYPE_NAME (type), 0); +} + +/* Auxiliary functions to make type signatures for + `operator new' and `operator delete' correspond to + what compiler will be expecting. */ + +tree +coerce_new_type (type) + tree type; +{ + int e1 = 0, e2 = 0; + + if (TREE_CODE (type) == METHOD_TYPE) + type = build_function_type (TREE_TYPE (type), TREE_CHAIN (TYPE_ARG_TYPES (type))); + if (! same_type_p (TREE_TYPE (type), ptr_type_node)) + e1 = 1, error ("`operator new' must return type `void *'"); + + /* Technically the type must be `size_t', but we may not know + what that is. */ + if (TYPE_ARG_TYPES (type) == NULL_TREE) + e1 = 1, error ("`operator new' takes type `size_t' parameter"); + else if (! same_type_p (TREE_VALUE (TYPE_ARG_TYPES (type)), sizetype)) + e2 = 1, error ("`operator new' takes type `size_t' as first parameter"); + if (e2) + type = build_function_type (ptr_type_node, tree_cons (NULL_TREE, sizetype, TREE_CHAIN (TYPE_ARG_TYPES (type)))); + else if (e1) + type = build_function_type (ptr_type_node, TYPE_ARG_TYPES (type)); + return type; +} + +tree +coerce_delete_type (type) + tree type; +{ + int e1 = 0, e2 = 0; +#if 0 + e3 = 0; +#endif + tree arg_types = TYPE_ARG_TYPES (type); + + if (TREE_CODE (type) == METHOD_TYPE) + { + type = build_function_type (TREE_TYPE (type), TREE_CHAIN (arg_types)); + arg_types = TREE_CHAIN (arg_types); + } + + if (TREE_TYPE (type) != void_type_node) + e1 = 1, error ("`operator delete' must return type `void'"); + + if (arg_types == NULL_TREE + || ! same_type_p (TREE_VALUE (arg_types), ptr_type_node)) + e2 = 1, error ("`operator delete' takes type `void *' as first parameter"); + +#if 0 + if (arg_types + && TREE_CHAIN (arg_types) + && TREE_CHAIN (arg_types) != void_list_node) + { + /* Again, technically this argument must be `size_t', but again + we may not know what that is. */ + tree t2 = TREE_VALUE (TREE_CHAIN (arg_types)); + if (! same_type_p (t2, sizetype)) + e3 = 1, error ("second argument to `operator delete' must be of type `size_t'"); + else if (TREE_CHAIN (TREE_CHAIN (arg_types)) != void_list_node) + { + e3 = 1; + if (TREE_CHAIN (TREE_CHAIN (arg_types))) + error ("too many arguments in declaration of `operator delete'"); + else + error ("`...' invalid in specification of `operator delete'"); + } + } + + if (e3) + arg_types = tree_cons (NULL_TREE, ptr_type_node, + build_tree_list (NULL_TREE, sizetype)); + else if (e3 |= e2) + { + if (arg_types == NULL_TREE) + arg_types = tree_cons (NULL_TREE, ptr_type_node, void_list_node); + else + arg_types = tree_cons (NULL_TREE, ptr_type_node, TREE_CHAIN (arg_types)); + } + else e3 |= e1; +#endif + + if (e2) + arg_types = tree_cons (NULL_TREE, ptr_type_node, + arg_types ? TREE_CHAIN (arg_types): NULL_TREE); + if (e2 || e1) + type = build_function_type (void_type_node, arg_types); + + return type; +} + +extern tree abort_fndecl; + +static void +mark_vtable_entries (decl) + tree decl; +{ + tree entries = CONSTRUCTOR_ELTS (DECL_INITIAL (decl)); + + for (; entries; entries = TREE_CHAIN (entries)) + { + tree fnaddr; + tree fn; + + if (TREE_CODE (TREE_VALUE (entries)) == NOP_EXPR) + /* RTTI offset. */ + continue; + + fnaddr = (flag_vtable_thunks ? TREE_VALUE (entries) + : FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (entries))); + fn = TREE_OPERAND (fnaddr, 0); + TREE_ADDRESSABLE (fn) = 1; + if (DECL_LANG_SPECIFIC (fn) && DECL_ABSTRACT_VIRTUAL_P (fn)) + { + TREE_OPERAND (fnaddr, 0) = fn = copy_node (fn); + DECL_RTL (fn) = DECL_RTL (abort_fndecl); + mark_used (abort_fndecl); + } + if (TREE_CODE (fn) == THUNK_DECL && DECL_EXTERNAL (fn)) + { + DECL_EXTERNAL (fn) = 0; + emit_thunk (fn); + } + mark_used (fn); + } +} + +/* Set DECL up to have the closest approximation of "initialized common" + linkage available. */ + +void +comdat_linkage (decl) + tree decl; +{ + if (flag_weak) + make_decl_one_only (decl); + else if (TREE_CODE (decl) == FUNCTION_DECL || DECL_VIRTUAL_P (decl)) + /* We can just emit functions and vtables statically; it doesn't really + matter if we have multiple copies. */ + TREE_PUBLIC (decl) = 0; + else + { + /* Static data member template instantiations, however, cannot + have multiple copies. */ + if (DECL_INITIAL (decl) == 0 + || DECL_INITIAL (decl) == error_mark_node) + DECL_COMMON (decl) = 1; + else if (EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl))) + { + DECL_COMMON (decl) = 1; + DECL_INITIAL (decl) = error_mark_node; + } + else + { + /* We can't do anything useful; leave vars for explicit + instantiation. */ + DECL_EXTERNAL (decl) = 1; + DECL_NOT_REALLY_EXTERN (decl) = 0; + } + } + + if (DECL_LANG_SPECIFIC (decl)) + DECL_COMDAT (decl) = 1; +} + +/* For win32 we also want to put explicit instantiations in + linkonce sections, so that they will be merged with implicit + instantiations; otherwise we get duplicate symbol errors. */ + +void +maybe_make_one_only (decl) + tree decl; +{ + /* This is not necessary on targets that support weak symbols, because + the implicit instantiations will defer to the explicit one. */ + if (! supports_one_only () || SUPPORTS_WEAK) + return; + + /* We can't set DECL_COMDAT on functions, or finish_file will think + we can get away with not emitting them if they aren't used. We need + to for variables so that cp_finish_decl will update their linkage, + because their DECL_INITIAL may not have been set properly yet. */ + + make_decl_one_only (decl); + + if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl)) + DECL_COMDAT (decl) = 1; +} + +/* Set TREE_PUBLIC and/or DECL_EXTERN on the vtable DECL, + based on TYPE and other static flags. + + Note that anything public is tagged TREE_PUBLIC, whether + it's public in this file or in another one. */ + +void +import_export_vtable (decl, type, final) + tree decl, type; + int final; +{ + if (DECL_INTERFACE_KNOWN (decl)) + return; + + if (TYPE_FOR_JAVA (type)) + { + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = 1; + DECL_INTERFACE_KNOWN (decl) = 1; + } + else if (CLASSTYPE_INTERFACE_KNOWN (type)) + { + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = ! CLASSTYPE_VTABLE_NEEDS_WRITING (type); + DECL_INTERFACE_KNOWN (decl) = 1; + } + else + { + /* We can only wait to decide if we have real non-inline virtual + functions in our class, or if we come from a template. */ + + int found = CLASSTYPE_TEMPLATE_INSTANTIATION (type); + + if (! found && ! final) + { + tree method; + for (method = TYPE_METHODS (type); method != NULL_TREE; + method = TREE_CHAIN (method)) + if (DECL_VINDEX (method) != NULL_TREE + && ! DECL_THIS_INLINE (method) + && ! DECL_ABSTRACT_VIRTUAL_P (method)) + { + found = 1; + break; + } + } + + if (final || ! found) + { + comdat_linkage (decl); + DECL_EXTERNAL (decl) = 0; + } + else + { + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = 1; + } + } +} + +/* Determine whether or not we want to specifically import or export CTYPE, + using various heuristics. */ + +void +import_export_class (ctype) + tree ctype; +{ + /* -1 for imported, 1 for exported. */ + int import_export = 0; + + if (CLASSTYPE_INTERFACE_KNOWN (ctype)) + return; + + /* If MULTIPLE_SYMBOL_SPACES is defined and we saw a #pragma interface, + we will have CLASSTYPE_INTERFACE_ONLY set but not + CLASSTYPE_INTERFACE_KNOWN. In that case, we don't want to use this + heuristic because someone will supply a #pragma implementation + elsewhere, and deducing it here would produce a conflict. */ + if (CLASSTYPE_INTERFACE_ONLY (ctype)) + return; + +#ifdef VALID_MACHINE_TYPE_ATTRIBUTE + /* FIXME this should really use some sort of target-independent macro. */ + if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype))) + import_export = -1; + else if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype))) + import_export = 1; +#endif + + /* If we got -fno-implicit-templates, we import template classes that + weren't explicitly instantiated. */ + if (import_export == 0 + && CLASSTYPE_IMPLICIT_INSTANTIATION (ctype) + && ! flag_implicit_templates) + import_export = -1; + + /* Base our import/export status on that of the first non-inline, + non-abstract virtual function, if any. */ + if (import_export == 0 + && TYPE_VIRTUAL_P (ctype) + && ! CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)) + { + tree method; + for (method = TYPE_METHODS (ctype); method != NULL_TREE; + method = TREE_CHAIN (method)) + { + if (DECL_VINDEX (method) != NULL_TREE + && !DECL_THIS_INLINE (method) + && !DECL_ABSTRACT_VIRTUAL_P (method)) + { + import_export = (DECL_REALLY_EXTERN (method) ? -1 : 1); + break; + } + } + } + +#ifdef MULTIPLE_SYMBOL_SPACES + if (import_export == -1) + import_export = 0; +#endif + + if (import_export) + { + SET_CLASSTYPE_INTERFACE_KNOWN (ctype); + CLASSTYPE_VTABLE_NEEDS_WRITING (ctype) = (import_export > 0); + CLASSTYPE_INTERFACE_ONLY (ctype) = (import_export < 0); + } +} + +/* We need to describe to the assembler the relationship between + a vtable and the vtable of the parent class. */ + +static void +output_vtable_inherit (vars) + tree vars; +{ + tree parent; + rtx op[2]; + + op[0] = XEXP (DECL_RTL (vars), 0); /* strip the mem ref */ + + parent = binfo_for_vtable (vars); + + if (parent == TYPE_BINFO (DECL_CONTEXT (vars))) + op[1] = const0_rtx; + else if (parent) + { + parent = TYPE_BINFO_VTABLE (BINFO_TYPE (parent)); + op[1] = XEXP (DECL_RTL (parent), 0); /* strip the mem ref */ + } + else + my_friendly_abort (980826); + + output_asm_insn (".vtable_inherit %c0, %c1", op); +} + +static int +finish_vtable_vardecl (t, data) + tree *t; + void *data ATTRIBUTE_UNUSED; +{ + tree vars = *t; + tree ctype = DECL_CONTEXT (vars); + import_export_class (ctype); + import_export_vtable (vars, ctype, 1); + + if (! DECL_EXTERNAL (vars) + && (DECL_INTERFACE_KNOWN (vars) + || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (vars)) + || (hack_decl_function_context (vars) && TREE_USED (vars))) + && ! TREE_ASM_WRITTEN (vars)) + { + /* Write it out. */ + mark_vtable_entries (vars); + if (TREE_TYPE (DECL_INITIAL (vars)) == 0) + store_init_value (vars, DECL_INITIAL (vars)); + + if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG) + { + /* Mark the VAR_DECL node representing the vtable itself as a + "gratuitous" one, thereby forcing dwarfout.c to ignore it. + It is rather important that such things be ignored because + any effort to actually generate DWARF for them will run + into trouble when/if we encounter code like: + + #pragma interface + struct S { virtual void member (); }; + + because the artificial declaration of the vtable itself (as + manufactured by the g++ front end) will say that the vtable + is a static member of `S' but only *after* the debug output + for the definition of `S' has already been output. This causes + grief because the DWARF entry for the definition of the vtable + will try to refer back to an earlier *declaration* of the + vtable as a static member of `S' and there won't be one. + We might be able to arrange to have the "vtable static member" + attached to the member list for `S' before the debug info for + `S' get written (which would solve the problem) but that would + require more intrusive changes to the g++ front end. */ + + DECL_IGNORED_P (vars) = 1; + } + + /* Always make vtables weak. */ + if (flag_weak) + comdat_linkage (vars); + + rest_of_decl_compilation (vars, NULL_PTR, 1, 1); + + if (flag_vtable_gc) + output_vtable_inherit (vars); + + return 1; + } + else if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (vars))) + /* We don't know what to do with this one yet. */ + return 0; + + *t = TREE_CHAIN (vars); + return 0; +} + +static int +prune_vtable_vardecl (t, data) + tree *t; + void *data ATTRIBUTE_UNUSED; +{ + *t = TREE_CHAIN (*t); + return 1; +} + +static int +finish_sigtable_vardecl (t, data) + tree *t; + void *data ATTRIBUTE_UNUSED; +{ + /* We don't need to mark sigtable entries as addressable here as is done + for vtables. Since sigtables, unlike vtables, are always written out, + that was already done in build_signature_table_constructor. */ + + rest_of_decl_compilation (*t, NULL_PTR, 1, 1); + *t = TREE_CHAIN (*t); + return 1; +} + +/* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an + inline function or template instantiation at end-of-file. */ + +void +import_export_decl (decl) + tree decl; +{ + if (DECL_INTERFACE_KNOWN (decl)) + return; + + if (DECL_TEMPLATE_INSTANTIATION (decl) + || DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl)) + { + DECL_NOT_REALLY_EXTERN (decl) = 1; + if ((DECL_IMPLICIT_INSTANTIATION (decl) + || DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl)) + && (flag_implicit_templates + || (flag_implicit_inline_templates && DECL_THIS_INLINE (decl)))) + { + if (!TREE_PUBLIC (decl)) + /* Templates are allowed to have internal linkage. See + [basic.link]. */ + ; + else + comdat_linkage (decl); + } + else + DECL_NOT_REALLY_EXTERN (decl) = 0; + } + else if (DECL_FUNCTION_MEMBER_P (decl)) + { + tree ctype = DECL_CLASS_CONTEXT (decl); + import_export_class (ctype); + if (CLASSTYPE_INTERFACE_KNOWN (ctype) + && (! DECL_ARTIFICIAL (decl) || DECL_VINDEX (decl))) + { + DECL_NOT_REALLY_EXTERN (decl) + = ! (CLASSTYPE_INTERFACE_ONLY (ctype) + || (DECL_THIS_INLINE (decl) && ! flag_implement_inlines + && !DECL_VINDEX (decl))); + + /* Always make artificials weak. */ + if (DECL_ARTIFICIAL (decl) && flag_weak) + comdat_linkage (decl); + else + maybe_make_one_only (decl); + } + else + comdat_linkage (decl); + } + else if (DECL_TINFO_FN_P (decl)) + { + tree ctype = TREE_TYPE (DECL_NAME (decl)); + + if (IS_AGGR_TYPE (ctype)) + import_export_class (ctype); + + if (IS_AGGR_TYPE (ctype) && CLASSTYPE_INTERFACE_KNOWN (ctype) + && TYPE_VIRTUAL_P (ctype) + /* If the type is a cv-qualified variant of a type, then we + must emit the tinfo function in this translation unit + since it will not be emitted when the vtable for the type + is output (which is when the unqualified version is + generated). */ + && ctype == TYPE_MAIN_VARIANT (ctype)) + { + DECL_NOT_REALLY_EXTERN (decl) + = ! (CLASSTYPE_INTERFACE_ONLY (ctype) + || (DECL_THIS_INLINE (decl) && ! flag_implement_inlines + && !DECL_VINDEX (decl))); + + /* Always make artificials weak. */ + if (flag_weak) + comdat_linkage (decl); + } + else if (TYPE_BUILT_IN (ctype) && ctype == TYPE_MAIN_VARIANT (ctype)) + DECL_NOT_REALLY_EXTERN (decl) = 0; + else + comdat_linkage (decl); + } + else + comdat_linkage (decl); + + DECL_INTERFACE_KNOWN (decl) = 1; +} + +tree +build_cleanup (decl) + tree decl; +{ + tree temp; + tree type = TREE_TYPE (decl); + + if (TREE_CODE (type) == ARRAY_TYPE) + temp = decl; + else + { + mark_addressable (decl); + temp = build1 (ADDR_EXPR, build_pointer_type (type), decl); + } + temp = build_delete (TREE_TYPE (temp), temp, + integer_two_node, + LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); + return temp; +} + +extern int parse_time, varconst_time; + +static tree +get_sentry (base) + tree base; +{ + tree sname = get_id_2 ("__sn", base); + /* For struct X foo __attribute__((weak)), there is a counter + __snfoo. Since base is already an assembler name, sname should + be globally unique */ + tree sentry = IDENTIFIER_GLOBAL_VALUE (sname); + if (! sentry) + { + push_obstacks_nochange (); + end_temporary_allocation (); + sentry = build_decl (VAR_DECL, sname, integer_type_node); + TREE_PUBLIC (sentry) = 1; + DECL_ARTIFICIAL (sentry) = 1; + TREE_STATIC (sentry) = 1; + TREE_USED (sentry) = 1; + DECL_COMMON (sentry) = 1; + pushdecl_top_level (sentry); + cp_finish_decl (sentry, NULL_TREE, NULL_TREE, 0, 0); + pop_obstacks (); + } + return sentry; +} + +/* Start the process of running a particular set of global constructors + or destructors. Subroutine of do_[cd]tors. */ + +static void +start_objects (method_type, initp) + int method_type, initp; +{ + tree fnname; + char type[10]; + + /* Make ctor or dtor function. METHOD_TYPE may be 'I' or 'D'. */ + + if (initp != DEFAULT_INIT_PRIORITY) + { + char joiner; + +#ifdef JOINER + joiner = JOINER; +#else + joiner = '_'; +#endif + + sprintf (type, "%c%c%.5u", method_type, joiner, initp); + } + else + sprintf (type, "%c", method_type); + + fnname = get_file_function_name_long (type); + + start_function (void_list_node, + make_call_declarator (fnname, void_list_node, NULL_TREE, + NULL_TREE), + NULL_TREE, 0); + +#if defined(ASM_OUTPUT_CONSTRUCTOR) && defined(ASM_OUTPUT_DESTRUCTOR) + /* It can be a static function as long as collect2 does not have + to scan the object file to find its ctor/dtor routine. */ + TREE_PUBLIC (current_function_decl) = 0; +#endif + + store_parm_decls (); + pushlevel (0); + clear_last_expr (); + push_momentary (); + expand_start_bindings (0); + + /* We cannot allow these functions to be elided, even if they do not + have external linkage. And, there's no point in deferring + copmilation of thes functions; they're all going to have to be + out anyhow. */ + current_function_cannot_inline + = "static constructors and destructors cannot be inlined"; +} + +/* Finish the process of running a particular set of global constructors + or destructors. Subroutine of do_[cd]tors. */ + +static void +finish_objects (method_type, initp) + int method_type, initp; +{ + char *fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + + /* Finish up. */ + expand_end_bindings (getdecls (), 1, 0); + poplevel (1, 0, 0); + pop_momentary (); + finish_function (lineno, 0, 0); + + if (initp == DEFAULT_INIT_PRIORITY) + { + if (method_type == 'I') + assemble_constructor (fnname); + else + assemble_destructor (fnname); + } + +#if defined (ASM_OUTPUT_SECTION_NAME) && defined (ASM_OUTPUT_CONSTRUCTOR) + /* If we're using init priority we can't use assemble_*tor, but on ELF + targets we can stick the references into named sections for GNU ld + to collect. */ + else + { + char buf[15]; + sprintf (buf, ".%ctors.%.5u", method_type == 'I' ? 'c' : 'd', + /* invert the numbering so the linker puts us in the proper + order; constructors are run from right to left, and the + linker sorts in increasing order. */ + MAX_INIT_PRIORITY - initp); + named_section (NULL_TREE, buf, 0); + assemble_integer (gen_rtx_SYMBOL_REF (Pmode, fnname), + POINTER_SIZE / BITS_PER_UNIT, 1); + } +#endif +} + +/* The names of the parameters to the function created to handle + initializations and destructions for objects with static storage + duration. */ +#define INITIALIZE_P_IDENTIFIER "__initialize_p" +#define PRIORITY_IDENTIFIER "__priority" + +/* The name of the function we create to handle initializations and + destructions for objects with static storage duration. */ +#define SSDF_IDENTIFIER "__static_initialization_and_destruction" + +/* The declaration for the __INITIALIZE_P argument. */ +static tree initialize_p_decl; + +/* The declaration for the __PRIORITY argument. */ +static tree priority_decl; + +/* The declaration for the static storage duration function. */ +static tree ssdf_decl; + +/* All the static storage duration functions created in this + translation unit. */ +static varray_type ssdf_decls; +static size_t ssdf_decls_used; + +/* A map from priority levels to information about that priority + level. There may be many such levels, so efficient lookup is + important. */ +static splay_tree priority_info_map; + +/* Begins the generation of the function that will handle all + initialization and destruction of objects with static storage + duration. The function generated takes two parameters of type + `int': __INITIALIZE_P and __PRIORITY. If __INITIALIZE_P is + non-zero, it performs initializations. Otherwise, it performs + destructions. It only performs those initializations or + destructions with the indicated __PRIORITY. The generated function + returns no value. + + It is assumed that this function will only be called once per + translation unit. */ + +static void +start_static_storage_duration_function () +{ + static unsigned ssdf_number; + + tree parm_types; + tree type; + char id[sizeof (SSDF_IDENTIFIER) + 1 /* '\0' */ + 32]; + + /* Create the identifier for this function. It will be of the form + SSDF_IDENTIFIER_<number>. */ + sprintf (id, "%s_%u", SSDF_IDENTIFIER, ssdf_number++); + if (ssdf_number == 0) + { + /* Overflow occurred. That means there are at least 4 billion + initialization functions. */ + sorry ("too many initialization functions required"); + my_friendly_abort (19990430); + } + + /* Create the parameters. */ + parm_types = void_list_node; + parm_types = perm_tree_cons (NULL_TREE, integer_type_node, parm_types); + parm_types = perm_tree_cons (NULL_TREE, integer_type_node, parm_types); + type = build_function_type (void_type_node, parm_types); + + /* Create the FUNCTION_DECL itself. */ + ssdf_decl = build_lang_decl (FUNCTION_DECL, + get_identifier (id), + type); + TREE_PUBLIC (ssdf_decl) = 0; + DECL_ARTIFICIAL (ssdf_decl) = 1; + + /* Put this function in the list of functions to be called from the + static constructors and destructors. */ + if (!ssdf_decls) + { + VARRAY_TREE_INIT (ssdf_decls, 32, "ssdf_decls"); + + /* Take this opportunity to initialize the map from priority + numbers to information about that priority level. */ + priority_info_map = splay_tree_new (splay_tree_compare_ints, + /*delete_key_fn=*/0, + /*delete_value_fn=*/ + (splay_tree_delete_value_fn) &free); + + /* We always need to generate functions for the + DEFAULT_INIT_PRIORITY so enter it now. That way when we walk + priorities later, we'll be sure to find the + DEFAULT_INIT_PRIORITY. */ + get_priority_info (DEFAULT_INIT_PRIORITY); + } + + if (ssdf_decls_used == ssdf_decls->num_elements) + VARRAY_GROW (ssdf_decls, 2 * ssdf_decls_used); + VARRAY_TREE (ssdf_decls, ssdf_decls_used) = ssdf_decl; + ++ssdf_decls_used; + + /* Create the argument list. */ + initialize_p_decl = build_decl (PARM_DECL, + get_identifier (INITIALIZE_P_IDENTIFIER), + integer_type_node); + DECL_CONTEXT (initialize_p_decl) = ssdf_decl; + DECL_ARG_TYPE (initialize_p_decl) = integer_type_node; + TREE_USED (initialize_p_decl) = 1; + priority_decl = build_decl (PARM_DECL, get_identifier (PRIORITY_IDENTIFIER), + integer_type_node); + DECL_CONTEXT (priority_decl) = ssdf_decl; + DECL_ARG_TYPE (priority_decl) = integer_type_node; + TREE_USED (priority_decl) = 1; + + TREE_CHAIN (initialize_p_decl) = priority_decl; + DECL_ARGUMENTS (ssdf_decl) = initialize_p_decl; + + /* Start the function itself. This is equivalent to declarating the + function as: + + static inline void __ssdf (int __initialize_p, init __priority_p); + + It is static because we only need to call this function from the + various constructor and destructor functions for this module. */ + start_function (/*specs=*/NULL_TREE, + ssdf_decl, + /*attrs=*/NULL_TREE, + /*pre_parsed_p=*/1); + + /* Set up the scope of the outermost block in the function. */ + store_parm_decls (); + pushlevel (0); + clear_last_expr (); + push_momentary (); + expand_start_bindings (0); + + /* This function must not be deferred because we are depending on + its compilation to tell us what is TREE_SYMBOL_REFERENCED. */ + current_function_cannot_inline + = "static storage duration functions cannot be inlined"; +} + +/* Generate the initialization code for the priority indicated in N. */ + +static int +generate_inits_for_priority (n, data) + splay_tree_node n; + void *data ATTRIBUTE_UNUSED; +{ + int priority = (int) n->key; + priority_info pi = (priority_info) n->value; + + /* For each priority N which has been used generate code which looks + like: + + if (__priority == N) { + if (__initialize_p) + ... + else + ... + } + + We use the sequences we've accumulated to fill in the `...'s. */ + expand_start_cond (build_binary_op (EQ_EXPR, + priority_decl, + build_int_2 (priority, 0)), + /*exit_flag=*/0); + + /* Do the initializations. */ + expand_start_cond (build_binary_op (NE_EXPR, + initialize_p_decl, + integer_zero_node), + /*exit_flag=*/0); + if (pi->initialization_sequence) + { + rtx insns; + + push_to_sequence (pi->initialization_sequence); + insns = gen_sequence (); + end_sequence (); + + emit_insn (insns); + pi->initialization_sequence = NULL_RTX; + pi->initializations_p = 1; + } + + /* Do the destructions. */ + expand_start_else (); + if (pi->destruction_sequence) + { + rtx insns; + + push_to_sequence (pi->destruction_sequence); + insns = gen_sequence (); + end_sequence (); + + emit_insn (insns); + pi->destruction_sequence = NULL_RTX; + pi->destructions_p = 1; + } + + /* Close out the conditionals. */ + expand_end_cond (); + expand_end_cond (); + + /* Don't stop iterating. */ + return 0; +} + +/* Finish the generation of the function which performs initialization + and destruction of objects with static storage duration. After + this point, no more such objects can be created. */ + +static void +finish_static_storage_duration_function () +{ + splay_tree_foreach (priority_info_map, + generate_inits_for_priority, + /*data=*/0); + + /* Close out the function. */ + expand_end_bindings (getdecls (), 1, 0); + poplevel (1, 0, 0); + pop_momentary (); + finish_function (lineno, 0, 0); +} + +/* Return the information about the indicated PRIORITY level. If no + code to handle this level has yet been generated, generate the + appropriate prologue. */ + +static priority_info +get_priority_info (priority) + int priority; +{ + priority_info pi; + splay_tree_node n; + + n = splay_tree_lookup (priority_info_map, + (splay_tree_key) priority); + if (!n) + { + /* Create a new priority information structure, and insert it + into the map. */ + pi = (priority_info) xmalloc (sizeof (struct priority_info_s)); + pi->initialization_sequence = NULL_RTX; + pi->destruction_sequence = NULL_RTX; + pi->initializations_p = 0; + pi->destructions_p = 0; + splay_tree_insert (priority_info_map, + (splay_tree_key) priority, + (splay_tree_value) pi); + } + else + pi = (priority_info) n->value; + + return pi; +} + +/* Generate code to do the static initialization of DECL. The + initialization is INIT. If DECL may be initialized more than once + in different object files, SENTRY is the guard variable to + check. PRIORITY is the priority for the initialization. */ + +static void +do_static_initialization (decl, init, sentry, priority) + tree decl; + tree init; + tree sentry; + int priority; +{ + priority_info pi; + + /* Get the priority information for this PRIORITY, */ + pi = get_priority_info (priority); + if (!pi->initialization_sequence) + start_sequence (); + else + push_to_sequence (pi->initialization_sequence); + + /* Tell the debugger that we are at the location of the static + variable in question. */ + emit_note (input_filename, lineno); + + /* If there's a SENTRY, we only do the initialization if it is + zero, i.e., if we are the first to initialize it. */ + if (sentry) + expand_start_cond (build_binary_op (EQ_EXPR, + build_unary_op (PREINCREMENT_EXPR, + sentry, + /*noconvert=*/0), + integer_one_node), + /*exit_flag=*/0); + + /* Prepare a binding level for temporaries created during the + initialization. */ + expand_start_target_temps (); + + if (IS_AGGR_TYPE (TREE_TYPE (decl)) + || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + expand_aggr_init (decl, init, 0); + else if (TREE_CODE (init) == TREE_VEC) + expand_expr (expand_vec_init (decl, TREE_VEC_ELT (init, 0), + TREE_VEC_ELT (init, 1), + TREE_VEC_ELT (init, 2), 0), + const0_rtx, VOIDmode, EXPAND_NORMAL); + else + expand_assignment (decl, init, 0, 0); + + /* The expression might have involved increments and decrements. */ + emit_queue (); + + /* Cleanup any temporaries needed for the initial value. */ + expand_end_target_temps (); + + /* Cleanup any deferred pops from function calls. This would be done + by expand_end_cond, but we also need it when !SENTRY, since we are + constructing these sequences by parts. */ + do_pending_stack_adjust (); + + /* Close the conditional opened above. */ + if (sentry) + expand_end_cond (); + + /* Save the sequence for later use. */ + pi->initialization_sequence = get_insns (); + end_sequence (); +} + +/* Generate code to do the static destruction of DECL. If DECL may be + initialized more than once in different object files, SENTRY is the + guard variable to check. PRIORITY is the priority for the + destruction. */ + +static void +do_static_destruction (decl, sentry, priority) + tree decl; + tree sentry; + int priority; +{ + rtx new_insns; + priority_info pi; + + /* If we don't need a destructor, there's nothing to do. */ + if (!TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl))) + return; + + /* Get the priority information for this PRIORITY, */ + pi = get_priority_info (priority); + if (!pi->destruction_sequence) + start_sequence (); + else + push_to_sequence (pi->destruction_sequence); + + /* Start a new sequence to handle just this destruction. */ + start_sequence (); + + /* Tell the debugger that we are at the location of the static + variable in question. */ + emit_note (input_filename, lineno); + + /* If there's a SENTRY, we only do the destruction if it is one, + i.e., if we are the last to destroy it. */ + if (sentry) + expand_start_cond (build_binary_op (EQ_EXPR, + build_unary_op (PREDECREMENT_EXPR, + sentry, + /*nonconvert=*/1), + integer_zero_node), + /*exit_flag=*/0); + + /* Actually to the destruction. */ + expand_expr_stmt (build_cleanup (decl)); + + /* Cleanup any deferred pops from function calls. This would be done + by expand_end_cond, but we also need it when !SENTRY, since we are + constructing these sequences by parts. */ + do_pending_stack_adjust (); + + /* Close the conditional opened above. */ + if (sentry) + expand_end_cond (); + + /* Insert the NEW_INSNS before the current insns. (Destructions are + run in reverse order of initializations.) */ + new_insns = gen_sequence (); + end_sequence (); + if (pi->destruction_sequence) + emit_insn_before (new_insns, pi->destruction_sequence); + else + emit_insn (new_insns); + + /* Save the sequence for later use. */ + pi->destruction_sequence = get_insns (); + end_sequence (); +} + +/* Add code to the static storage duration function that will handle + DECL (a static variable that needs initializing and/or destruction) + with the indicated PRIORITY. If DECL needs initializing, INIT is + the initializer. */ + +static void +do_static_initialization_and_destruction (decl, init) + tree decl; + tree init; +{ + tree sentry = NULL_TREE; + int priority; + + /* Deal gracefully with error. */ + if (decl == error_mark_node) + return; + + /* The only things that can be initialized are variables. */ + my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 19990420); + + /* If this object is not defined, we don't need to do anything + here. */ + if (DECL_EXTERNAL (decl)) + return; + + /* Also, if the initializer already contains errors, we can bail out + now. */ + if (init && TREE_CODE (init) == TREE_LIST + && value_member (error_mark_node, init)) + return; + + /* Trick the compiler into thinking we are at the file and line + where DECL was declared so that error-messages make sense, and so + that the debugger will show somewhat sensible file and line + information. */ + input_filename = DECL_SOURCE_FILE (decl); + lineno = DECL_SOURCE_LINE (decl); + + /* Because of: + + [class.access.spec] + + Access control for implicit calls to the constructors, + the conversion functions, or the destructor called to + create and destroy a static data member is performed as + if these calls appeared in the scope of the member's + class. + + we pretend we are in a static member function of the class of + which the DECL is a member. */ + if (member_p (decl)) + { + DECL_CLASS_CONTEXT (current_function_decl) = DECL_CONTEXT (decl); + DECL_STATIC_FUNCTION_P (current_function_decl) = 1; + } + + /* We need a sentry if this is an object with external linkage that + might be initialized in more than one place. */ + if (TREE_PUBLIC (decl) && (DECL_COMMON (decl) + || DECL_ONE_ONLY (decl) + || DECL_WEAK (decl))) + sentry = get_sentry (DECL_ASSEMBLER_NAME (decl)); + + /* Generate the code to actually do the intialization and + destruction. */ + priority = DECL_INIT_PRIORITY (decl); + if (!priority) + priority = DEFAULT_INIT_PRIORITY; + do_static_initialization (decl, init, sentry, priority); + do_static_destruction (decl, sentry, priority); + + /* Now that we're done with DECL we don't need to pretend to be a + member of its class any longer. */ + DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE; + DECL_STATIC_FUNCTION_P (current_function_decl) = 0; +} + +/* Generate a static constructor (if CONSTRUCTOR_P) or destructor + (otherwise) that will initialize all gobal objects with static + storage duration having the indicated PRIORITY. */ + +static void +generate_ctor_or_dtor_function (constructor_p, priority) + int constructor_p; + int priority; +{ + char function_key; + tree arguments; + size_t i; + + /* We use `I' to indicate initialization and `D' to indicate + destruction. */ + if (constructor_p) + function_key = 'I'; + else + function_key = 'D'; + + /* Begin the function. */ + start_objects (function_key, priority); + + /* Call the static storage duration function with appropriate + arguments. */ + for (i = 0; i < ssdf_decls_used; ++i) + { + arguments = tree_cons (NULL_TREE, build_int_2 (priority, 0), + NULL_TREE); + arguments = tree_cons (NULL_TREE, build_int_2 (constructor_p, 0), + arguments); + expand_expr_stmt (build_function_call (VARRAY_TREE (ssdf_decls, i), + arguments)); + } + + /* If we're generating code for the DEFAULT_INIT_PRIORITY, throw in + calls to any functions marked with attributes indicating that + they should be called at initialization- or destruction-time. */ + if (priority == DEFAULT_INIT_PRIORITY) + { + tree fns; + + for (fns = constructor_p ? static_ctors : static_dtors; + fns; + fns = TREE_CHAIN (fns)) + expand_expr_stmt (build_function_call (TREE_VALUE (fns), NULL_TREE)); + } + + /* Close out the function. */ + finish_objects (function_key, priority); +} + +/* Generate constructor and destructor functions for the priority + indicated by N. */ + +static int +generate_ctor_and_dtor_functions_for_priority (n, data) + splay_tree_node n; + void *data ATTRIBUTE_UNUSED; +{ + int priority = (int) n->key; + priority_info pi = (priority_info) n->value; + + /* Generate the functions themselves, but only if they are really + needed. */ + if (pi->initializations_p + || (priority == DEFAULT_INIT_PRIORITY && static_ctors)) + generate_ctor_or_dtor_function (/*constructor_p=*/1, + priority); + if (pi->destructions_p + || (priority == DEFAULT_INIT_PRIORITY && static_dtors)) + generate_ctor_or_dtor_function (/*constructor_p=*/0, + priority); + + /* Keep iterating. */ + return 0; +} + +/* This routine is called from the last rule in yyparse (). + Its job is to create all the code needed to initialize and + destroy the global aggregates. We do the destruction + first, since that way we only need to reverse the decls once. */ + +void +finish_file () +{ + extern int lineno; + int start_time, this_time; + tree vars; + int reconsider; + size_t i; + + at_eof = 1; + + /* Bad parse errors. Just forget about it. */ + if (! global_bindings_p () || current_class_type || decl_namespace_list) + return; + + start_time = get_run_time (); + + /* Otherwise, GDB can get confused, because in only knows + about source for LINENO-1 lines. */ + lineno -= 1; + + interface_unknown = 1; + interface_only = 0; + + /* We now have to write out all the stuff we put off writing out. + These include: + + o Template specializations that we have not yet instantiated, + but which are needed. + o Initialization and destruction for non-local objects with + static storage duration. (Local objects with static storage + duration are initialized when their scope is first entered, + and are cleaned up via atexit.) + o Virtual function tables. + + All of these may cause others to be needed. For example, + instantiating one function may cause another to be needed, and + generating the intiailzer for an object may cause templates to be + instantiated, etc., etc. */ + + this_time = get_run_time (); + parse_time -= this_time - start_time; + varconst_time += this_time - start_time; + start_time = get_run_time (); + permanent_allocation (1); + + do + { + /* We need to start a new initialization function each time + through the loop. That's because we need to know which + vtables have been referenced, and TREE_SYMBOL_REFERENCED + isn't computed until a function is finished, and written out. + That's a deficiency in the back-end. When this is fixed, + these initialization functions could all become inline, with + resulting performance improvements. */ + start_static_storage_duration_function (); + push_to_top_level (); + + reconsider = 0; + + /* If there are templates that we've put off instantiating, do + them now. */ + instantiate_pending_templates (); + + /* Write out signature-tables and virtual tables as required. + Note that writing out the virtual table for a template class + may cause the instantiation of members of that class. */ + if (flag_handle_signatures + && walk_globals (sigtable_decl_p, + finish_sigtable_vardecl, + /*data=*/0)) + reconsider = 1; + if (walk_globals (vtable_decl_p, + finish_vtable_vardecl, + /*data=*/0)) + reconsider = 1; + + /* Come back to the static storage duration function; we're + about to emit instructions there for static initializations + and such. */ + pop_from_top_level (); + /* The list of objects with static storage duration is built up + in reverse order, so we reverse it here. We also clear + STATIC_AGGREGATES so that any new aggregates added during the + initialization of these will be initialized in the correct + order when we next come around the loop. */ + vars = nreverse (static_aggregates); + static_aggregates = NULL_TREE; + while (vars) + { + if (! TREE_ASM_WRITTEN (TREE_VALUE (vars))) + rest_of_decl_compilation (TREE_VALUE (vars), 0, 1, 1); + do_static_initialization_and_destruction (TREE_VALUE (vars), + TREE_PURPOSE (vars)); + reconsider = 1; + vars = TREE_CHAIN (vars); + } + + /* Finish up the static storage duration function for this + round. */ + finish_static_storage_duration_function (); + + /* Go through the various inline functions, and see if any need + synthesizing. */ + for (i = 0; i < saved_inlines_used; ++i) + { + tree decl = VARRAY_TREE (saved_inlines, i); + import_export_decl (decl); + if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl) + && TREE_USED (decl) + && (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl))) + { + /* Even though we're already at the top-level, we push + there again. That way, when we pop back a few lines + hence, all of our state is restored. Otherwise, + finish_function doesn't clean things up, and we end + up with CURRENT_FUNCTION_DECL set. */ + push_to_top_level (); + if (DECL_TINFO_FN_P (decl)) + synthesize_tinfo_fn (decl); + else + synthesize_method (decl); + pop_from_top_level (); + reconsider = 1; + } + } + + /* Mark all functions that might deal with exception-handling as + referenced. */ + mark_all_runtime_matches (); + + /* We lie to the back-end, pretending that some functions are + not defined when they really are. This keeps these functions + from being put out unncessarily. But, we must stop lying + when the functions are referenced, or if they are not comdat + since they need to be put out now. */ + for (i = 0; i < saved_inlines_used; ++i) + { + tree decl = VARRAY_TREE (saved_inlines, i); + + if (DECL_NOT_REALLY_EXTERN (decl) + && DECL_INITIAL (decl) + && (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) + || !DECL_COMDAT (decl))) + DECL_EXTERNAL (decl) = 0; + } + + if (saved_inlines_used + && wrapup_global_declarations (&VARRAY_TREE (saved_inlines, 0), + saved_inlines_used)) + reconsider = 1; + if (walk_namespaces (wrapup_globals_for_namespace, /*data=*/0)) + reconsider = 1; + + /* Static data members are just like namespace-scope globals. */ + for (i = 0; i < pending_statics_used; ++i) + { + tree decl = VARRAY_TREE (pending_statics, i); + if (TREE_ASM_WRITTEN (decl)) + continue; + import_export_decl (decl); + if (DECL_NOT_REALLY_EXTERN (decl) && ! DECL_IN_AGGR_P (decl)) + DECL_EXTERNAL (decl) = 0; + } + if (pending_statics + && wrapup_global_declarations (&VARRAY_TREE (pending_statics, 0), + pending_statics_used)) + reconsider = 1; + } + while (reconsider); + + /* We give C linkage to static constructors and destructors. */ + push_lang_context (lang_name_c); + + /* Generate initialization and destruction functions for all + priorities for which they are required. */ + if (priority_info_map) + splay_tree_foreach (priority_info_map, + generate_ctor_and_dtor_functions_for_priority, + /*data=*/0); + + /* We're done with the splay-tree now. */ + if (priority_info_map) + splay_tree_delete (priority_info_map); + + /* We're done with static constructors, so we can go back to "C++" + linkage now. */ + pop_lang_context (); + + /* Now delete from the chain of variables all virtual function tables. + We output them all ourselves, because each will be treated + specially. */ + walk_globals (vtable_decl_p, prune_vtable_vardecl, /*data=*/0); + + /* Now, issue warnings about static, but not defined, functions, + etc. */ + walk_namespaces (wrapup_globals_for_namespace, /*data=*/&reconsider); + + finish_repo (); + + this_time = get_run_time (); + parse_time -= this_time - start_time; + varconst_time += this_time - start_time; + + if (flag_detailed_statistics) + { + dump_tree_statistics (); + dump_time_statistics (); + } +} + +/* This is something of the form 'A()()()()()+1' that has turned out to be an + expr. Since it was parsed like a type, we need to wade through and fix + that. Unfortunately, since operator() is left-associative, we can't use + tail recursion. In the above example, TYPE is `A', and DECL is + `()()()()()'. + + Maybe this shouldn't be recursive, but how often will it actually be + used? (jason) */ + +tree +reparse_absdcl_as_expr (type, decl) + tree type, decl; +{ + /* do build_functional_cast (type, NULL_TREE) at bottom */ + if (TREE_OPERAND (decl, 0) == NULL_TREE) + return build_functional_cast (type, NULL_TREE); + + /* recurse */ + decl = reparse_absdcl_as_expr (type, TREE_OPERAND (decl, 0)); + + decl = build_x_function_call (decl, NULL_TREE, current_class_ref); + + if (TREE_CODE (decl) == CALL_EXPR + && (! TREE_TYPE (decl) + || TREE_CODE (TREE_TYPE (decl)) != VOID_TYPE)) + decl = require_complete_type (decl); + + return decl; +} + +/* This is something of the form `int ((int)(int)(int)1)' that has turned + out to be an expr. Since it was parsed like a type, we need to wade + through and fix that. Since casts are right-associative, we are + reversing the order, so we don't have to recurse. + + In the above example, DECL is the `(int)(int)(int)', and EXPR is the + `1'. */ + +tree +reparse_absdcl_as_casts (decl, expr) + tree decl, expr; +{ + tree type; + + if (TREE_CODE (expr) == CONSTRUCTOR + && TREE_TYPE (expr) == 0) + { + type = groktypename (TREE_VALUE (TREE_OPERAND (decl, 1))); + decl = TREE_OPERAND (decl, 0); + + if (IS_SIGNATURE (type)) + { + error ("cast specifies signature type"); + return error_mark_node; + } + + expr = digest_init (type, expr, (tree *) 0); + if (TREE_CODE (type) == ARRAY_TYPE && TYPE_SIZE (type) == 0) + { + int failure = complete_array_type (type, expr, 1); + if (failure) + my_friendly_abort (78); + } + } + + while (decl) + { + type = groktypename (TREE_VALUE (TREE_OPERAND (decl, 1))); + decl = TREE_OPERAND (decl, 0); + expr = build_c_cast (type, expr); + } + + if (warn_old_style_cast) + warning ("use of old-style cast"); + + return expr; +} + +/* Given plain tree nodes for an expression, build up the full semantics. */ + +tree +build_expr_from_tree (t) + tree t; +{ + if (t == NULL_TREE || t == error_mark_node) + return t; + + switch (TREE_CODE (t)) + { + case IDENTIFIER_NODE: + return do_identifier (t, 0, NULL_TREE); + + case LOOKUP_EXPR: + if (LOOKUP_EXPR_GLOBAL (t)) + return do_scoped_id (TREE_OPERAND (t, 0), 0); + else + return do_identifier (TREE_OPERAND (t, 0), 0, NULL_TREE); + + case TEMPLATE_ID_EXPR: + return (lookup_template_function + (build_expr_from_tree (TREE_OPERAND (t, 0)), + build_expr_from_tree (TREE_OPERAND (t, 1)))); + + case INDIRECT_REF: + return build_x_indirect_ref + (build_expr_from_tree (TREE_OPERAND (t, 0)), "unary *"); + + case CAST_EXPR: + return build_functional_cast + (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0))); + + case REINTERPRET_CAST_EXPR: + return build_reinterpret_cast + (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0))); + + case CONST_CAST_EXPR: + return build_const_cast + (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0))); + + case DYNAMIC_CAST_EXPR: + return build_dynamic_cast + (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0))); + + case STATIC_CAST_EXPR: + return build_static_cast + (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0))); + + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case ABS_EXPR: + case TRUTH_NOT_EXPR: + case ADDR_EXPR: + case CONVERT_EXPR: /* Unary + */ + if (TREE_TYPE (t)) + return t; + return build_x_unary_op (TREE_CODE (t), + build_expr_from_tree (TREE_OPERAND (t, 0))); + + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case EXACT_DIV_EXPR: + case BIT_AND_EXPR: + case BIT_ANDTC_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case RSHIFT_EXPR: + case LSHIFT_EXPR: + case RROTATE_EXPR: + case LROTATE_EXPR: + case EQ_EXPR: + case NE_EXPR: + case MAX_EXPR: + case MIN_EXPR: + case LE_EXPR: + case GE_EXPR: + case LT_EXPR: + case GT_EXPR: + case MEMBER_REF: + return build_x_binary_op + (TREE_CODE (t), + build_expr_from_tree (TREE_OPERAND (t, 0)), + build_expr_from_tree (TREE_OPERAND (t, 1))); + + case DOTSTAR_EXPR: + return build_m_component_ref + (build_expr_from_tree (TREE_OPERAND (t, 0)), + build_expr_from_tree (TREE_OPERAND (t, 1))); + + case SCOPE_REF: + return build_offset_ref (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1)); + + case ARRAY_REF: + if (TREE_OPERAND (t, 0) == NULL_TREE) + /* new-type-id */ + return build_parse_node (ARRAY_REF, NULL_TREE, + build_expr_from_tree (TREE_OPERAND (t, 1))); + return grok_array_decl (build_expr_from_tree (TREE_OPERAND (t, 0)), + build_expr_from_tree (TREE_OPERAND (t, 1))); + + case SIZEOF_EXPR: + case ALIGNOF_EXPR: + { + tree r = build_expr_from_tree (TREE_OPERAND (t, 0)); + if (TREE_CODE_CLASS (TREE_CODE (r)) != 't') + r = TREE_TYPE (r); + return TREE_CODE (t) == SIZEOF_EXPR ? c_sizeof (r) : c_alignof (r); + } + + case MODOP_EXPR: + return build_x_modify_expr + (build_expr_from_tree (TREE_OPERAND (t, 0)), + TREE_CODE (TREE_OPERAND (t, 1)), + build_expr_from_tree (TREE_OPERAND (t, 2))); + + case ARROW_EXPR: + return build_x_arrow + (build_expr_from_tree (TREE_OPERAND (t, 0))); + + case NEW_EXPR: + return build_new + (build_expr_from_tree (TREE_OPERAND (t, 0)), + build_expr_from_tree (TREE_OPERAND (t, 1)), + build_expr_from_tree (TREE_OPERAND (t, 2)), + NEW_EXPR_USE_GLOBAL (t)); + + case DELETE_EXPR: + return delete_sanity + (build_expr_from_tree (TREE_OPERAND (t, 0)), + build_expr_from_tree (TREE_OPERAND (t, 1)), + DELETE_EXPR_USE_VEC (t), DELETE_EXPR_USE_GLOBAL (t)); + + case COMPOUND_EXPR: + if (TREE_OPERAND (t, 1) == NULL_TREE) + return build_x_compound_expr + (build_expr_from_tree (TREE_OPERAND (t, 0))); + else + my_friendly_abort (42); + + case METHOD_CALL_EXPR: + if (TREE_CODE (TREE_OPERAND (t, 0)) == SCOPE_REF) + { + tree ref = TREE_OPERAND (t, 0); + return build_scoped_method_call + (build_expr_from_tree (TREE_OPERAND (t, 1)), + build_expr_from_tree (TREE_OPERAND (ref, 0)), + TREE_OPERAND (ref, 1), + build_expr_from_tree (TREE_OPERAND (t, 2))); + } + else + { + tree fn = TREE_OPERAND (t, 0); + + /* We can get a TEMPLATE_ID_EXPR here on code like: + + x->f<2>(); + + so we must resolve that. However, we can also get things + like a BIT_NOT_EXPR here, when referring to a destructor, + and things like that are not correctly resolved by + build_expr_from_tree. So, just use build_expr_from_tree + when we really need it. */ + if (TREE_CODE (fn) == TEMPLATE_ID_EXPR) + fn = build_expr_from_tree (fn); + + return build_method_call + (build_expr_from_tree (TREE_OPERAND (t, 1)), + fn, + build_expr_from_tree (TREE_OPERAND (t, 2)), + NULL_TREE, LOOKUP_NORMAL); + } + + case CALL_EXPR: + if (TREE_CODE (TREE_OPERAND (t, 0)) == SCOPE_REF) + { + tree ref = TREE_OPERAND (t, 0); + return build_member_call + (build_expr_from_tree (TREE_OPERAND (ref, 0)), + TREE_OPERAND (ref, 1), + build_expr_from_tree (TREE_OPERAND (t, 1))); + } + else + { + tree name = TREE_OPERAND (t, 0); + tree id; + tree args = build_expr_from_tree (TREE_OPERAND (t, 1)); + if (args != NULL_TREE && TREE_CODE (name) == LOOKUP_EXPR + && !LOOKUP_EXPR_GLOBAL (name) + && TREE_CODE ((id = TREE_OPERAND (name, 0))) == IDENTIFIER_NODE + && (!current_class_type + || !lookup_member (current_class_type, id, 0, 0))) + { + /* Do Koenig lookup if there are no class members. */ + name = do_identifier (id, 0, args); + } + else if (TREE_CODE (name) == TEMPLATE_ID_EXPR + || ! really_overloaded_fn (name)) + name = build_expr_from_tree (name); + return build_x_function_call (name, args, current_class_ref); + } + + case COND_EXPR: + return build_x_conditional_expr + (build_expr_from_tree (TREE_OPERAND (t, 0)), + build_expr_from_tree (TREE_OPERAND (t, 1)), + build_expr_from_tree (TREE_OPERAND (t, 2))); + + case TREE_LIST: + { + tree purpose, value, chain; + + if (t == void_list_node) + return t; + + purpose = TREE_PURPOSE (t); + if (purpose) + purpose = build_expr_from_tree (purpose); + value = TREE_VALUE (t); + if (value) + value = build_expr_from_tree (value); + chain = TREE_CHAIN (t); + if (chain && chain != void_type_node) + chain = build_expr_from_tree (chain); + return expr_tree_cons (purpose, value, chain); + } + + case COMPONENT_REF: + { + tree object = build_expr_from_tree (TREE_OPERAND (t, 0)); + tree field = TREE_OPERAND (t, 1); + + /* We use a COMPONENT_REF to indicate things of the form `x.b' + and `x.A::b'. We must distinguish between those cases + here. */ + if (TREE_CODE (field) == SCOPE_REF) + return build_object_ref (object, + TREE_OPERAND (field, 0), + TREE_OPERAND (field, 1)); + else + return build_x_component_ref (object, field, + NULL_TREE, 1); + } + + case THROW_EXPR: + return build_throw (build_expr_from_tree (TREE_OPERAND (t, 0))); + + case CONSTRUCTOR: + { + tree r; + + /* digest_init will do the wrong thing if we let it. */ + if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t))) + return t; + + r = build_nt (CONSTRUCTOR, NULL_TREE, + build_expr_from_tree (CONSTRUCTOR_ELTS (t))); + TREE_HAS_CONSTRUCTOR (r) = TREE_HAS_CONSTRUCTOR (t); + + if (TREE_TYPE (t)) + return digest_init (TREE_TYPE (t), r, 0); + return r; + } + + case TYPEID_EXPR: + if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, 0))) == 't') + return get_typeid (TREE_OPERAND (t, 0)); + return build_x_typeid (build_expr_from_tree (TREE_OPERAND (t, 0))); + + case VAR_DECL: + return convert_from_reference (t); + + default: + return t; + } +} + +/* This is something of the form `int (*a)++' that has turned out to be an + expr. It was only converted into parse nodes, so we need to go through + and build up the semantics. Most of the work is done by + build_expr_from_tree, above. + + In the above example, TYPE is `int' and DECL is `*a'. */ + +tree +reparse_decl_as_expr (type, decl) + tree type, decl; +{ + decl = build_expr_from_tree (decl); + if (type) + return build_functional_cast (type, build_expr_list (NULL_TREE, decl)); + else + return decl; +} + +/* This is something of the form `int (*a)' that has turned out to be a + decl. It was only converted into parse nodes, so we need to do the + checking that make_{pointer,reference}_declarator do. */ + +tree +finish_decl_parsing (decl) + tree decl; +{ + extern int current_class_depth; + + switch (TREE_CODE (decl)) + { + case IDENTIFIER_NODE: + return decl; + case INDIRECT_REF: + return make_pointer_declarator + (NULL_TREE, finish_decl_parsing (TREE_OPERAND (decl, 0))); + case ADDR_EXPR: + return make_reference_declarator + (NULL_TREE, finish_decl_parsing (TREE_OPERAND (decl, 0))); + case BIT_NOT_EXPR: + TREE_OPERAND (decl, 0) = finish_decl_parsing (TREE_OPERAND (decl, 0)); + return decl; + case SCOPE_REF: + push_nested_class (TREE_TYPE (TREE_OPERAND (decl, 0)), 3); + TREE_COMPLEXITY (decl) = current_class_depth; + return decl; + case ARRAY_REF: + TREE_OPERAND (decl, 0) = finish_decl_parsing (TREE_OPERAND (decl, 0)); + return decl; + case TREE_LIST: + /* For attribute handling. */ + TREE_VALUE (decl) = finish_decl_parsing (TREE_VALUE (decl)); + return decl; + default: + my_friendly_abort (5); + return NULL_TREE; + } +} + +tree +check_cp_case_value (value) + tree value; +{ + if (value == NULL_TREE) + return value; + + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ + STRIP_TYPE_NOPS (value); + + if (TREE_READONLY_DECL_P (value)) + { + value = decl_constant_value (value); + STRIP_TYPE_NOPS (value); + } + value = fold (value); + + if (TREE_CODE (value) != INTEGER_CST + && value != error_mark_node) + { + cp_error ("case label `%E' does not reduce to an integer constant", + value); + value = error_mark_node; + } + else + /* Promote char or short to int. */ + value = default_conversion (value); + + constant_expression_warning (value); + + return value; +} + +/* Return 1 if root encloses child. */ + +static int +is_namespace_ancestor (root, child) + tree root, child; +{ + if (root == child) + return 1; + if (root == global_namespace) + return 1; + if (child == global_namespace) + return 0; + return is_namespace_ancestor (root, CP_DECL_CONTEXT (child)); +} + + +/* Return the namespace that is the common ancestor + of two given namespaces. */ + +tree +namespace_ancestor (ns1, ns2) + tree ns1, ns2; +{ + if (is_namespace_ancestor (ns1, ns2)) + return ns1; + return namespace_ancestor (CP_DECL_CONTEXT (ns1), ns2); +} + +/* Insert used into the using list of user. Set indirect_flag if this + directive is not directly from the source. Also find the common + ancestor and let our users know about the new namespace */ +static void +add_using_namespace (user, used, indirect) + tree user; + tree used; + int indirect; +{ + tree t; + /* Using oneself is a no-op. */ + if (user == used) + return; + my_friendly_assert (TREE_CODE (user) == NAMESPACE_DECL, 380); + my_friendly_assert (TREE_CODE (used) == NAMESPACE_DECL, 380); + /* Check if we already have this. */ + t = purpose_member (used, DECL_NAMESPACE_USING (user)); + if (t != NULL_TREE) + { + if (!indirect) + /* Promote to direct usage. */ + TREE_INDIRECT_USING (t) = 0; + return; + } + + /* Add used to the user's using list. */ + DECL_NAMESPACE_USING (user) + = perm_tree_cons (used, namespace_ancestor (user, used), + DECL_NAMESPACE_USING (user)); + + TREE_INDIRECT_USING (DECL_NAMESPACE_USING (user)) = indirect; + + /* Add user to the used's users list. */ + DECL_NAMESPACE_USERS (used) + = perm_tree_cons (user, 0, DECL_NAMESPACE_USERS (used)); + + /* Recursively add all namespaces used. */ + for (t = DECL_NAMESPACE_USING (used); t; t = TREE_CHAIN (t)) + /* indirect usage */ + add_using_namespace (user, TREE_PURPOSE (t), 1); + + /* Tell everyone using us about the new used namespaces. */ + for (t = DECL_NAMESPACE_USERS (user); t; t = TREE_CHAIN (t)) + add_using_namespace (TREE_PURPOSE (t), used, 1); +} + +/* Combines two sets of overloaded functions into an OVERLOAD chain, removing + duplicates. The first list becomes the tail of the result. + + The algorithm is O(n^2). We could get this down to O(n log n) by + doing a sort on the addresses of the functions, if that becomes + necessary. */ + +static tree +merge_functions (s1, s2) + tree s1; + tree s2; +{ + for (; s2; s2 = OVL_NEXT (s2)) + { + tree fn = OVL_CURRENT (s2); + if (! ovl_member (fn, s1)) + s1 = build_overload (fn, s1); + } + return s1; +} + +/* This should return an error not all definitions define functions. + It is not an error if we find two functions with exactly the + same signature, only if these are selected in overload resolution. + old is the current set of bindings, new the freshly-found binding. + XXX Do we want to give *all* candidates in case of ambiguity? + XXX In what way should I treat extern declarations? + XXX I don't want to repeat the entire duplicate_decls here */ + +static tree +ambiguous_decl (name, old, new, flags) + tree name; + tree old; + tree new; + int flags; +{ + tree val, type; + my_friendly_assert (old != NULL_TREE, 393); + /* Copy the value. */ + val = BINDING_VALUE (new); + if (val) + switch (TREE_CODE (val)) + { + case TEMPLATE_DECL: + /* If we expect types or namespaces, and not templates, + or this is not a template class. */ + if (LOOKUP_QUALIFIERS_ONLY (flags) + && !DECL_CLASS_TEMPLATE_P (val)) + val = NULL_TREE; + break; + case TYPE_DECL: + if (LOOKUP_NAMESPACES_ONLY (flags)) + val = NULL_TREE; + break; + case NAMESPACE_DECL: + if (LOOKUP_TYPES_ONLY (flags)) + val = NULL_TREE; + break; + default: + if (LOOKUP_QUALIFIERS_ONLY (flags)) + val = NULL_TREE; + } + + if (!BINDING_VALUE (old)) + BINDING_VALUE (old) = val; + else if (val && val != BINDING_VALUE (old)) + { + if (is_overloaded_fn (BINDING_VALUE (old)) + && is_overloaded_fn (val)) + { + BINDING_VALUE (old) = merge_functions (BINDING_VALUE (old), + val); + } + else + { + /* Some declarations are functions, some are not. */ + if (flags & LOOKUP_COMPLAIN) + { + /* If we've already given this error for this lookup, + BINDING_VALUE (old) is error_mark_node, so let's not + repeat ourselves. */ + if (BINDING_VALUE (old) != error_mark_node) + { + cp_error ("use of `%D' is ambiguous", name); + cp_error_at (" first declared as `%#D' here", + BINDING_VALUE (old)); + } + cp_error_at (" also declared as `%#D' here", val); + } + return error_mark_node; + } + } + /* ... and copy the type. */ + type = BINDING_TYPE (new); + if (LOOKUP_NAMESPACES_ONLY (flags)) + type = NULL_TREE; + if (!BINDING_TYPE (old)) + BINDING_TYPE (old) = type; + else if (type && BINDING_TYPE (old) != type) + { + if (flags & LOOKUP_COMPLAIN) + { + cp_error ("`%D' denotes an ambiguous type",name); + cp_error_at (" first type here", BINDING_TYPE (old)); + cp_error_at (" other type here", type); + } + } + return old; +} + +/* Add the bindings of name in used namespaces to val. + The using list is defined by usings, and the lookup goes to scope. + Returns zero on errors. */ + +int +lookup_using_namespace (name, val, usings, scope, flags) + tree name, val, usings, scope; + int flags; +{ + tree iter; + tree val1; + /* Iterate over all used namespaces in current, searching for using + directives of scope. */ + for (iter = usings; iter; iter = TREE_CHAIN (iter)) + if (TREE_VALUE (iter) == scope) + { + val1 = binding_for_name (name, TREE_PURPOSE (iter)); + /* Resolve ambiguities. */ + val = ambiguous_decl (name, val, val1, flags); + } + return val != error_mark_node; +} + +/* [namespace.qual] + Excepts the name to lookup and its qualifying scope. + Returns the name/type pair found into the CPLUS_BINDING result, + or 0 on error. */ + +int +qualified_lookup_using_namespace (name, scope, result, flags) + tree name; + tree scope; + tree result; + int flags; +{ + /* Maintain a list of namespaces visited... */ + tree seen = NULL_TREE; + /* ... and a list of namespace yet to see. */ + tree todo = NULL_TREE; + tree usings; + while (scope && (result != error_mark_node)) + { + seen = temp_tree_cons (scope, NULL_TREE, seen); + result = ambiguous_decl (name, result, + binding_for_name (name, scope), flags); + if (!BINDING_VALUE (result) && !BINDING_TYPE (result)) + /* Consider using directives. */ + for (usings = DECL_NAMESPACE_USING (scope); usings; + usings = TREE_CHAIN (usings)) + /* If this was a real directive, and we have not seen it. */ + if (!TREE_INDIRECT_USING (usings) + && !purpose_member (TREE_PURPOSE (usings), seen)) + todo = temp_tree_cons (TREE_PURPOSE (usings), NULL_TREE, todo); + if (todo) + { + scope = TREE_PURPOSE (todo); + todo = TREE_CHAIN (todo); + } + else + scope = NULL_TREE; /* If there never was a todo list. */ + } + return result != error_mark_node; +} + +/* [namespace.memdef]/2 */ + +/* Set the context of a declaration to scope. Complain if we are not + outside scope. */ + +void +set_decl_namespace (decl, scope, friendp) + tree decl; + tree scope; + int friendp; +{ + tree old; + if (scope == std_node) + scope = global_namespace; + /* Get rid of namespace aliases. */ + scope = ORIGINAL_NAMESPACE (scope); + + /* It is ok for friends to be qualified in parallel space. */ + if (!friendp && !is_namespace_ancestor (current_namespace, scope)) + cp_error ("declaration of `%D' not in a namespace surrounding `%D'", + decl, scope); + DECL_CONTEXT (decl) = FROB_CONTEXT (scope); + if (scope != current_namespace) + { + /* See whether this has been declared in the namespace. */ + old = namespace_binding (DECL_NAME (decl), scope); + if (!old) + /* No old declaration at all. */ + goto complain; + if (!is_overloaded_fn (decl)) + /* Don't compare non-function decls with decls_match here, + since it can't check for the correct constness at this + point. pushdecl will find those errors later. */ + return; + /* Since decl is a function, old should contain a function decl. */ + if (!is_overloaded_fn (old)) + goto complain; + for (; old; old = OVL_NEXT (old)) + if (decls_match (decl, OVL_CURRENT (old))) + return; + } + else + return; + complain: + cp_error ("`%D' should have been declared inside `%D'", + decl, scope); +} + +/* Compute the namespace where a declaration is defined. */ + +static tree +decl_namespace (decl) + tree decl; +{ + while (DECL_CONTEXT (decl)) + { + decl = DECL_CONTEXT (decl); + if (TREE_CODE (decl) == NAMESPACE_DECL) + return decl; + if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't') + decl = TYPE_STUB_DECL (decl); + my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd', 390); + } + + return global_namespace; +} + +/* Return the namespace where the current declaration is declared. */ + +tree +current_decl_namespace () +{ + tree result; + /* If we have been pushed into a different namespace, use it. */ + if (decl_namespace_list) + return TREE_PURPOSE (decl_namespace_list); + + if (current_class_type) + result = decl_namespace (TYPE_STUB_DECL (current_class_type)); + else if (current_function_decl) + result = decl_namespace (current_function_decl); + else + result = current_namespace; + return result; +} + +/* Temporarily set the namespace for the current declaration. */ + +void +push_decl_namespace (decl) + tree decl; +{ + if (TREE_CODE (decl) != NAMESPACE_DECL) + decl = decl_namespace (decl); + decl_namespace_list = tree_cons (decl, NULL_TREE, decl_namespace_list); +} + +void +pop_decl_namespace () +{ + decl_namespace_list = TREE_CHAIN (decl_namespace_list); +} + +/* Enter a class or namespace scope. */ + +void +push_scope (t) + tree t; +{ + if (TREE_CODE (t) == NAMESPACE_DECL) + push_decl_namespace (t); + else + pushclass (t, 2); +} + +/* Leave scope pushed by push_scope. */ + +void +pop_scope (t) + tree t; +{ + if (TREE_CODE (t) == NAMESPACE_DECL) + pop_decl_namespace (); + else + popclass (); +} + +/* [basic.lookup.koenig] */ +/* A non-zero return value in the functions below indicates an error. + All nodes allocated in the procedure are on the scratch obstack. */ + +struct arg_lookup +{ + tree name; + tree namespaces; + tree classes; + tree functions; +}; + +static int arg_assoc PROTO((struct arg_lookup*, tree)); +static int arg_assoc_args PROTO((struct arg_lookup*, tree)); +static int arg_assoc_type PROTO((struct arg_lookup*, tree)); +static int add_function PROTO((struct arg_lookup *, tree)); +static int arg_assoc_namespace PROTO((struct arg_lookup *, tree)); +static int arg_assoc_class PROTO((struct arg_lookup *, tree)); + +/* Add a function to the lookup structure. + Returns 1 on error. */ + +static int +add_function (k, fn) + struct arg_lookup *k; + tree fn; +{ + if (ovl_member (fn, k->functions)) + return 0; + /* We must find only functions, or exactly one non-function. */ + if (k->functions && is_overloaded_fn (k->functions) + && is_overloaded_fn (fn)) + k->functions = build_overload (fn, k->functions); + else + if(k->functions) + { + tree f1 = OVL_CURRENT (k->functions); + tree f2 = fn; + if (is_overloaded_fn (f1)) + { + fn = f1; f1 = f2; f2 = fn; + } + cp_error_at ("`%D' is not a function,", f1); + cp_error_at (" conflict with `%D'", f2); + cp_error (" in call to `%D'", k->name); + return 1; + } + else + k->functions = fn; + return 0; +} + +/* Add functions of a namespace to the lookup structure. + Returns 1 on error. */ + +static int +arg_assoc_namespace (k, scope) + struct arg_lookup *k; + tree scope; +{ + tree value; + + if (purpose_member (scope, k->namespaces)) + return 0; + k->namespaces = tree_cons (scope, NULL_TREE, k->namespaces); + + value = namespace_binding (k->name, scope); + if (!value) + return 0; + + for (; value; value = OVL_NEXT (value)) + if (add_function (k, OVL_CURRENT (value))) + return 1; + + return 0; +} + +/* Adds everything associated with class to the lookup structure. + Returns 1 on error. */ + +static int +arg_assoc_class (k, type) + struct arg_lookup* k; + tree type; +{ + tree list, friends, context; + int i; + + if (purpose_member (type, k->classes)) + return 0; + k->classes = tree_cons (type, NULL_TREE, k->classes); + + context = decl_namespace (TYPE_MAIN_DECL (type)); + if (arg_assoc_namespace (k, context)) + return 1; + + /* Process baseclasses. */ + for (i = 0; i < CLASSTYPE_N_BASECLASSES (type); i++) + if (arg_assoc_class (k, TYPE_BINFO_BASETYPE (type, i))) + return 1; + + /* Process friends. */ + for (list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type)); list; + list = TREE_CHAIN (list)) + if (k->name == TREE_PURPOSE (list)) + for (friends = TREE_VALUE (list); friends; + friends = TREE_CHAIN (friends)) + /* Only interested in global functions with potentially hidden + (i.e. unqualified) declarations. */ + if (TREE_PURPOSE (list) == error_mark_node && TREE_VALUE (list) + && decl_namespace (TREE_VALUE (list)) == context) + if (add_function (k, TREE_VALUE (list))) + return 1; + + /* Process template arguments. */ + if (CLASSTYPE_TEMPLATE_INFO (type)) + { + list = innermost_args (CLASSTYPE_TI_ARGS (type)); + for (i = 0; i < TREE_VEC_LENGTH (list); ++i) + arg_assoc (k, TREE_VEC_ELT (list, i)); + } + + return 0; +} + +/* Adds everything associated with a given type. + Returns 1 on error. */ + +static int +arg_assoc_type (k, type) + struct arg_lookup *k; + tree type; +{ + switch (TREE_CODE (type)) + { + case VOID_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case COMPLEX_TYPE: + case CHAR_TYPE: + case BOOLEAN_TYPE: + return 0; + case RECORD_TYPE: + if (TYPE_PTRMEMFUNC_P (type)) + return arg_assoc_type (k, TYPE_PTRMEMFUNC_FN_TYPE (type)); + return arg_assoc_class (k, type); + case POINTER_TYPE: + case REFERENCE_TYPE: + case ARRAY_TYPE: + return arg_assoc_type (k, TREE_TYPE (type)); + case UNION_TYPE: + case ENUMERAL_TYPE: + return arg_assoc_namespace (k, decl_namespace (TYPE_MAIN_DECL (type))); + case OFFSET_TYPE: + /* Pointer to member: associate class type and value type. */ + if (arg_assoc_type (k, TYPE_OFFSET_BASETYPE (type))) + return 1; + return arg_assoc_type (k, TREE_TYPE (type)); + case METHOD_TYPE: + /* The basetype is referenced in the first arg type, so just + fall through. */ + case FUNCTION_TYPE: + /* Associate the parameter types. */ + if (arg_assoc_args (k, TYPE_ARG_TYPES (type))) + return 1; + /* Associate the return type. */ + return arg_assoc_type (k, TREE_TYPE (type)); + case TEMPLATE_TYPE_PARM: + case TEMPLATE_TEMPLATE_PARM: + return 0; + case LANG_TYPE: + if (type == unknown_type_node) + return 0; + /* else fall through */ + default: + my_friendly_abort (390); + } + return 0; +} + +/* Adds everything associated with arguments. Returns 1 on error. */ + +static int +arg_assoc_args (k, args) + struct arg_lookup* k; + tree args; +{ + for (; args; args = TREE_CHAIN (args)) + if (arg_assoc (k, TREE_VALUE (args))) + return 1; + return 0; +} + +/* Adds everything associated with a given tree_node. Returns 1 on error. */ + +static int +arg_assoc (k, n) + struct arg_lookup* k; + tree n; +{ + if (n == error_mark_node) + return 0; + + if (TREE_CODE_CLASS (TREE_CODE (n)) == 't') + return arg_assoc_type (k, n); + + if (! type_unknown_p (n)) + return arg_assoc_type (k, TREE_TYPE (n)); + + if (TREE_CODE (n) == ADDR_EXPR) + n = TREE_OPERAND (n, 0); + if (TREE_CODE (n) == COMPONENT_REF) + n = TREE_OPERAND (n, 1); + if (TREE_CODE (n) == OFFSET_REF) + n = TREE_OPERAND (n, 1); + while (TREE_CODE (n) == TREE_LIST) + n = TREE_VALUE (n); + + if (TREE_CODE (n) == FUNCTION_DECL) + return arg_assoc_type (k, TREE_TYPE (n)); + if (TREE_CODE (n) == TEMPLATE_ID_EXPR) + { + /* [basic.lookup.koenig] + + If T is a template-id, its associated namespaces and classes + are the namespace in which the template is defined; for + member templates, the member template's class; the namespaces + and classes associated with the types of the template + arguments provided for template type parameters (excluding + template template parameters); the namespaces in which any + template template arguments are defined; and the classes in + which any member templates used as template template + arguments are defined. [Note: non-type template arguments do + not contribute to the set of associated namespaces. ] */ + tree template = TREE_OPERAND (n, 0); + tree args = TREE_OPERAND (n, 1); + tree ctx; + tree arg; + + /* First, the template. There may actually be more than one if + this is an overloaded function template. But, in that case, + we only need the first; all the functions will be in the same + namespace. */ + template = OVL_CURRENT (template); + + ctx = CP_DECL_CONTEXT (template); + + if (TREE_CODE (ctx) == NAMESPACE_DECL) + { + if (arg_assoc_namespace (k, ctx) == 1) + return 1; + } + /* It must be a member template. */ + else if (arg_assoc_class (k, ctx) == 1) + return 1; + + /* Now the arguments. */ + for (arg = args; arg != NULL_TREE; arg = TREE_CHAIN (arg)) + { + tree t = TREE_VALUE (arg); + + if (TREE_CODE (t) == TEMPLATE_DECL) + { + ctx = CP_DECL_CONTEXT (t); + if (TREE_CODE (ctx) == NAMESPACE_DECL) + { + if (arg_assoc_namespace (k, ctx) == 1) + return 1; + } + else if (arg_assoc_class (k, ctx) == 1) + return 1; + } + else if (TREE_CODE_CLASS (TREE_CODE (t)) == 't' + && arg_assoc_type (k, t) == 1) + return 1; + } + } + else + { + my_friendly_assert (TREE_CODE (n) == OVERLOAD, 980715); + + for (; n; n = OVL_CHAIN (n)) + if (arg_assoc_type (k, TREE_TYPE (OVL_FUNCTION (n)))) + return 1; + } + + return 0; +} + +/* Performs Koenig lookup depending on arguments, where fns + are the functions found in normal lookup. */ + +tree +lookup_arg_dependent (name, fns, args) + tree name; + tree fns; + tree args; +{ + struct arg_lookup k; + k.name = name; + k.functions = fns; + k.namespaces = NULL_TREE; + k.classes = NULL_TREE; + + push_scratch_obstack (); + arg_assoc_args (&k, args); + pop_obstacks (); + return k.functions; +} + +/* Process a namespace-alias declaration. */ + +void +do_namespace_alias (alias, namespace) + tree alias, namespace; +{ + if (TREE_CODE (namespace) != NAMESPACE_DECL) + { + /* The parser did not find it, so it's not there. */ + cp_error ("unknown namespace `%D'", namespace); + return; + } + + namespace = ORIGINAL_NAMESPACE (namespace); + + /* Build the alias. */ + alias = build_lang_decl (NAMESPACE_DECL, alias, void_type_node); + DECL_NAMESPACE_ALIAS (alias) = namespace; + pushdecl (alias); +} + +/* Check a non-member using-declaration. Return the name and scope + being used, and the USING_DECL, or NULL_TREE on failure. */ + +static tree +validate_nonmember_using_decl (decl, scope, name) + tree decl; + tree *scope; + tree *name; +{ + if (TREE_CODE (decl) == SCOPE_REF + && TREE_OPERAND (decl, 0) == std_node) + { + if (namespace_bindings_p () + && current_namespace == global_namespace) + /* There's no need for a using declaration at all, here, + since `std' is the same as `::'. We can't just pass this + on because we'll complain later about declaring something + in the same scope as a using declaration with the same + name. We return NULL_TREE which indicates to the caller + that there's no need to do any further processing. */ + return NULL_TREE; + + *scope = global_namespace; + *name = TREE_OPERAND (decl, 1); + } + else if (TREE_CODE (decl) == SCOPE_REF) + { + *scope = TREE_OPERAND (decl, 0); + *name = TREE_OPERAND (decl, 1); + + /* [namespace.udecl] + + A using-declaration for a class member shall be a + member-declaration. */ + if (TREE_CODE (*scope) != NAMESPACE_DECL) + { + if (TYPE_P (*scope)) + cp_error ("`%T' is not a namespace", *scope); + else + cp_error ("`%D' is not a namespace", *scope); + return NULL_TREE; + } + } + else if (TREE_CODE (decl) == IDENTIFIER_NODE + || TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == TEMPLATE_DECL) + { + *scope = global_namespace; + *name = decl; + } + else + my_friendly_abort (382); + if (TREE_CODE_CLASS (TREE_CODE (*name)) == 'd') + *name = DECL_NAME (*name); + /* Make a USING_DECL. */ + return push_using_decl (*scope, *name); +} + +/* Process local and global using-declarations. */ + +static void +do_nonmember_using_decl (scope, name, oldval, oldtype, newval, newtype) + tree scope, name; + tree oldval, oldtype; + tree *newval, *newtype; +{ + tree decls; + struct tree_binding _decls; + + *newval = *newtype = NULL_TREE; + decls = binding_init (&_decls); + if (!qualified_lookup_using_namespace (name, scope, decls, 0)) + /* Lookup error */ + return; + + if (!BINDING_VALUE (decls) && !BINDING_TYPE (decls)) + { + cp_error ("`%D' not declared", name); + return; + } + + /* Check for using functions. */ + if (BINDING_VALUE (decls) && is_overloaded_fn (BINDING_VALUE (decls))) + { + tree tmp, tmp1; + + if (oldval && !is_overloaded_fn (oldval)) + { + duplicate_decls (OVL_CURRENT (BINDING_VALUE (decls)), oldval); + oldval = NULL_TREE; + } + + *newval = oldval; + for (tmp = BINDING_VALUE (decls); tmp; tmp = OVL_NEXT (tmp)) + { + tree new_fn = OVL_CURRENT (tmp); + + /* [namespace.udecl] + + If a function declaration in namespace scope or block + scope has the same name and the same parameter types as a + function introduced by a using declaration the program is + ill-formed. */ + for (tmp1 = oldval; tmp1; tmp1 = OVL_NEXT (tmp1)) + { + tree old_fn = OVL_CURRENT (tmp1); + + if (!OVL_USED (tmp1) + && compparms (TYPE_ARG_TYPES (TREE_TYPE (new_fn)), + TYPE_ARG_TYPES (TREE_TYPE (old_fn)))) + { + /* There was already a non-using declaration in + this scope with the same parameter types. */ + cp_error ("`%D' is already declared in this scope", + name); + break; + } + else if (duplicate_decls (new_fn, old_fn)) + /* We're re-using something we already used + before. We don't need to add it again. */ + break; + } + + /* If we broke out of the loop, there's no reason to add + this function to the using declarations for this + scope. */ + if (tmp1) + continue; + + *newval = build_overload (OVL_CURRENT (tmp), *newval); + if (TREE_CODE (*newval) != OVERLOAD) + *newval = ovl_cons (*newval, NULL_TREE); + OVL_USED (*newval) = 1; + } + } + else + { + *newval = BINDING_VALUE (decls); + if (oldval) + duplicate_decls (*newval, oldval); + } + + *newtype = BINDING_TYPE (decls); + if (oldtype && *newtype && oldtype != *newtype) + { + cp_error ("using directive `%D' introduced ambiguous type `%T'", + name, oldtype); + return; + } +} + +/* Process a using-declaration not appearing in class or local scope. */ + +void +do_toplevel_using_decl (decl) + tree decl; +{ + tree scope, name, binding; + tree oldval, oldtype, newval, newtype; + + decl = validate_nonmember_using_decl (decl, &scope, &name); + if (decl == NULL_TREE) + return; + + binding = binding_for_name (name, current_namespace); + + oldval = BINDING_VALUE (binding); + oldtype = BINDING_TYPE (binding); + + do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype); + + /* Copy declarations found. */ + if (newval) + BINDING_VALUE (binding) = newval; + if (newtype) + BINDING_TYPE (binding) = newtype; + return; +} + +/* Process a using-declaration at function scope. */ + +void +do_local_using_decl (decl) + tree decl; +{ + tree scope, name; + tree oldval, oldtype, newval, newtype; + + decl = validate_nonmember_using_decl (decl, &scope, &name); + if (decl == NULL_TREE) + return; + + oldval = lookup_name_current_level (name); + oldtype = lookup_type_current_level (name); + + do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype); + + if (newval) + { + if (is_overloaded_fn (newval)) + { + tree fn, term; + + /* We only need to push declarations for those functions + that were not already bound in the current level. + The old value might be NULL_TREE, it might be a single + function, or an OVERLOAD. */ + if (oldval && TREE_CODE (oldval) == OVERLOAD) + term = OVL_FUNCTION (oldval); + else + term = oldval; + for (fn = newval; fn && OVL_CURRENT (fn) != term; + fn = OVL_NEXT (fn)) + push_overloaded_decl (OVL_CURRENT (fn), + PUSH_LOCAL | PUSH_USING); + } + else + push_local_binding (name, newval, PUSH_USING); + } + if (newtype) + set_identifier_type_value (name, newtype); +} + +tree +do_class_using_decl (decl) + tree decl; +{ + tree name, value; + + if (TREE_CODE (decl) != SCOPE_REF + || TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (decl, 0))) != 't') + { + cp_error ("using-declaration for non-member at class scope"); + return NULL_TREE; + } + name = TREE_OPERAND (decl, 1); + if (TREE_CODE (name) == BIT_NOT_EXPR) + { + cp_error ("using-declaration for destructor"); + return NULL_TREE; + } + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + + my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 980716); + + value = build_lang_field_decl (USING_DECL, name, void_type_node); + DECL_INITIAL (value) = TREE_OPERAND (decl, 0); + return value; +} + +/* Process a using-directive. */ + +void +do_using_directive (namespace) + tree namespace; +{ + if (namespace == std_node) + return; + /* using namespace A::B::C; */ + if (TREE_CODE (namespace) == SCOPE_REF) + namespace = TREE_OPERAND (namespace, 1); + if (TREE_CODE (namespace) == IDENTIFIER_NODE) + { + /* Lookup in lexer did not find a namespace. */ + cp_error ("namespace `%T' undeclared", namespace); + return; + } + if (TREE_CODE (namespace) != NAMESPACE_DECL) + { + cp_error ("`%T' is not a namespace", namespace); + return; + } + namespace = ORIGINAL_NAMESPACE (namespace); + if (!toplevel_bindings_p ()) + push_using_directive (namespace); + else + /* direct usage */ + add_using_namespace (current_namespace, namespace, 0); +} + +void +check_default_args (x) + tree x; +{ + tree arg = TYPE_ARG_TYPES (TREE_TYPE (x)); + int saw_def = 0, i = 0 - (TREE_CODE (TREE_TYPE (x)) == METHOD_TYPE); + for (; arg && arg != void_list_node; arg = TREE_CHAIN (arg), ++i) + { + if (TREE_PURPOSE (arg)) + saw_def = 1; + else if (saw_def) + { + cp_error_at ("default argument missing for parameter %P of `%+#D'", + i, x); + break; + } + } +} + +void +mark_used (decl) + tree decl; +{ + TREE_USED (decl) = 1; + if (processing_template_decl) + return; + assemble_external (decl); + + /* Is it a synthesized method that needs to be synthesized? */ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_CLASS_CONTEXT (decl) + && DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl) + /* Kludge: don't synthesize for default args. */ + && current_function_decl) + synthesize_method (decl); + + /* If this is a function or variable that is an instance of some + template, we now know that we will need to actually do the + instantiation. A TEMPLATE_DECL may also have DECL_TEMPLATE_INFO, + if it's a partial instantiation, but there's no need to + instantiate such a thing. We check that DECL is not an explicit + instantiation because that is not checked in instantiate_decl. */ + if (TREE_CODE (decl) != TEMPLATE_DECL + && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) + && !DECL_EXPLICIT_INSTANTIATION (decl)) + instantiate_decl (decl); +} + +/* Helper function for named_class_head_sans_basetype nonterminal. We + have just seen something of the form `AGGR SCOPE::ID'. Return a + TYPE_DECL for the type declared by ID in SCOPE. */ + +tree +handle_class_head (aggr, scope, id) + tree aggr, scope, id; +{ + tree decl; + + if (TREE_CODE (id) == TYPE_DECL) + decl = id; + else if (DECL_CLASS_TEMPLATE_P (id)) + decl = DECL_TEMPLATE_RESULT (id); + else + { + if (scope) + cp_error ("`%T' does not have a nested type named `%D'", scope, id); + else + cp_error ("no file-scope type named `%D'", id); + + decl = TYPE_MAIN_DECL (xref_tag (aggr, make_anon_name (), 1)); + } + + /* This syntax is only allowed when we're defining a type, so we + enter the SCOPE. */ + push_scope (CP_DECL_CONTEXT (decl)); + + /* If we see something like: + + template <typename T> struct S::I .... + + we must create a TEMPLATE_DECL for the nested type. */ + if (PROCESSING_REAL_TEMPLATE_DECL_P ()) + decl = push_template_decl (decl); + + return decl; +} |