aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/decl2.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/decl2.c')
-rw-r--r--gcc/cp/decl2.c2577
1 files changed, 1734 insertions, 843 deletions
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index e945a72f2a8..f70867a9e5a 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -40,18 +40,27 @@ Boston, MA 02111-1307, USA. */
#include "expr.h"
#include "defaults.h"
#include "toplev.h"
+#include "dwarf2out.h"
+#include "dwarfout.h"
+
+#if USE_CPPLIB
+#include "cpplib.h"
+extern cpp_reader parse_in;
+extern cpp_options parse_options;
+static int cpp_initialized;
+#endif
static tree get_sentry PROTO((tree));
static void mark_vtable_entries PROTO((tree));
-static void import_export_template PROTO((tree));
static void grok_function_init PROTO((tree, tree));
static int finish_vtable_vardecl PROTO((tree, tree));
static int prune_vtable_vardecl PROTO((tree, tree));
static void finish_sigtable_vardecl PROTO((tree, tree));
static int is_namespace_ancestor PROTO((tree, tree));
-static tree namespace_ancestor PROTO((tree, tree));
static void add_using_namespace PROTO((tree, tree, int));
-static tree ambiguous_decl PROTO((tree, tree, tree));
+static tree ambiguous_decl PROTO((tree, tree, tree,int));
+static tree build_anon_union_vars PROTO((tree, tree*, int, int));
+static void check_decl_namespace PROTO((void));
extern int current_class_depth;
@@ -88,11 +97,15 @@ int at_eof;
tree static_ctors, static_dtors;
-/* The current open namespace, and :: */
+/* 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. */
@@ -160,10 +173,28 @@ int flag_alt_external_templates;
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 allow numerical priorities on constructors. */
+
+#ifdef USE_INIT_PRIORITY
+int flag_init_priority = 1;
+#else
+int flag_init_priority;
+#endif
+
/* 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. */
@@ -181,9 +212,18 @@ int flag_vtable_thunks = DEFAULT_VTABLE_THUNKS;
int flag_use_repository;
-/* Nonzero means give string constants the type `const char *'
- to get extra warnings from them. These warnings will be too numerous
- to be useful, except in thoroughly ANSIfied programs. */
+/* 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;
@@ -192,11 +232,6 @@ int warn_write_strings;
int warn_cast_qual;
-/* Nonzero means warn that dbx info for template class methods isn't fully
- supported yet. */
-
-int warn_template_debugging;
-
/* Nonzero means warn about sizeof(function) or addition/subtraction
of function pointers. */
@@ -272,7 +307,16 @@ int warn_old_style_cast;
/* Warn about #pragma directives that are not recognised. */
-int warn_unknown_pragmas = 0; /* Tri state variable. */
+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 `$' can be in an identifier. */
@@ -297,40 +341,22 @@ int flag_labels_ok;
int flag_detailed_statistics;
/* C++ specific flags. */
-/* Nonzero for -fall-virtual: make every member function (except
- constructors) lay down in the virtual function table. Calls
- can then either go through the virtual function table or not,
- depending. */
-
-int flag_all_virtual;
-
/* 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;
-/* Nonzero means memoize our member lookups. */
-
-int flag_memoize_lookups; int flag_save_memoized_contexts;
-
/* 3 means write out only virtuals function tables `defined'
in this implementation file.
- 2 means write out only specific virtual function tables
- and give them (C) public access.
- 1 means write out virtual function tables and give them
- (C) public access.
0 means write out virtual function tables and give them
- (C) static access (default).
- -1 means declare virtual function tables extern. */
+ (C) static access (default). */
int write_virtuals;
-/* Nonzero means we should attempt to elide constructors when possible.
- FIXME: This flag is obsolete, and should be torn out along with the
- old overloading code. */
+/* Nonzero means we should attempt to elide constructors when possible. */
-int flag_elide_constructors;
+int flag_elide_constructors = 1;
/* Nonzero means recognize and handle signature language constructs. */
@@ -341,11 +367,6 @@ int flag_handle_signatures;
int flag_default_inline = 1;
-/* Controls whether enums and ints freely convert.
- 1 means with complete freedom.
- 0 means enums can convert to ints, but not vice-versa. */
-int flag_int_enum_equivalence;
-
/* Controls whether compiler generates 'type descriptor' that give
run-time type information. */
int flag_rtti = 1;
@@ -354,18 +375,6 @@ int flag_rtti = 1;
for the GNU class browser. */
extern int flag_gnu_xref;
-/* Nonzero if compiler can make `reasonable' assumptions about
- references and objects. For example, the compiler must be
- conservative about the following and not assume that `a' is nonnull:
-
- obj &a = g ();
- a.f (2);
-
- In general, it is `reasonable' to assume that for many programs,
- and better code can be generated in that case. */
-
-int flag_assume_nonnull_objects = 1;
-
/* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes)
objects. */
@@ -410,6 +419,10 @@ int flag_weak = 1;
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. */
@@ -428,6 +441,9 @@ int flag_guiding_decls;
and class qualifiers. */
int flag_do_squangling;
+/* Nonzero means output .vtable_{entry,inherit} for use in doing vtable gc. */
+
+int flag_vtable_gc;
/* Table of language-dependent -f options.
STRING is the option name. VARIABLE is the address of the variable.
@@ -449,30 +465,32 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
{"builtin", &flag_no_builtin, 0},
{"ident", &flag_no_ident, 0},
{"labels-ok", &flag_labels_ok, 1},
+ {"const-strings", &flag_const_strings, 1},
{"stats", &flag_detailed_statistics, 1},
{"this-is-variable", &flag_this_is_variable, 1},
{"strict-prototype", &flag_strict_prototype, 1},
- {"all-virtual", &flag_all_virtual, 1},
- {"memoize-lookups", &flag_memoize_lookups, 1},
{"elide-constructors", &flag_elide_constructors, 1},
{"handle-exceptions", &flag_exceptions, 1},
{"handle-signatures", &flag_handle_signatures, 1},
{"default-inline", &flag_default_inline, 1},
{"dollars-in-identifiers", &dollars_in_ident, 1},
- {"enum-int-equiv", &flag_int_enum_equivalence, 1},
+ {"honor-std", &flag_honor_std, 1},
{"rtti", &flag_rtti, 1},
{"xref", &flag_gnu_xref, 1},
- {"nonnull-objects", &flag_assume_nonnull_objects, 1},
{"implement-inlines", &flag_implement_inlines, 1},
{"external-templates", &flag_external_templates, 1},
{"implicit-templates", &flag_implicit_templates, 1},
+ {"implicit-inline-templates", &flag_implicit_inline_templates, 1},
+ {"init-priority", &flag_init_priority, 1},
{"huge-objects", &flag_huge_objects, 1},
{"conserve-space", &flag_conserve_space, 1},
+ {"vtable-gc", &flag_vtable_gc, 1},
{"vtable-thunks", &flag_vtable_thunks, 1},
{"access-control", &flag_access_control, 1},
{"nonansi-builtins", &flag_no_nonansi_builtin, 0},
{"gnu-keywords", &flag_no_gnu_keywords, 0},
{"operator-names", &flag_operator_names, 1},
+ {"optional-diags", &flag_optional_diags, 1},
{"check-new", &flag_check_new, 1},
{"repo", &flag_use_repository, 1},
{"for-scope", &flag_new_for_scope, 2},
@@ -480,32 +498,36 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
};
/* Decode the string P as a language-specific option.
- Return 1 if it is recognized (and handle it);
- return 0 if not recognized. */
+ Return the number of strings consumed for a valid option.
+ Otherwise return 0. */
int
-lang_decode_option (p)
- char *p;
+lang_decode_option (argc, argv)
+ int argc
+#if !USE_CPPLIB
+ ATTRIBUTE_UNUSED
+#endif
+ ;
+ char **argv;
+
{
- if (!strcmp (p, "-ftraditional") || !strcmp (p, "-traditional"))
- flag_writable_strings = 1,
- flag_this_is_variable = 1, flag_new_for_scope = 0;
- /* The +e options are for cfront compatibility. They come in as
- `-+eN', to kludge around gcc.c's argument handling. */
- else if (p[0] == '-' && p[1] == '+' && p[2] == 'e')
- {
- int old_write_virtuals = write_virtuals;
- if (p[3] == '1')
- write_virtuals = 1;
- else if (p[3] == '0')
- write_virtuals = -1;
- else if (p[3] == '2')
- write_virtuals = 2;
- else error ("invalid +e option");
- if (old_write_virtuals != 0
- && write_virtuals != old_write_virtuals)
- error ("conflicting +e options given");
+ int strings_processed;
+ char *p = argv[0];
+#if USE_CPPLIB
+ if (! cpp_initialized)
+ {
+ cpp_reader_init (&parse_in);
+ parse_in.data = &parse_options;
+ cpp_options_init (&parse_options);
+ cpp_initialized = 1;
}
+ 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.
@@ -521,16 +543,24 @@ lang_decode_option (p)
|| !strcmp (p, "no-handle-exceptions"))
warning ("-fhandle-exceptions has been renamed to -fexceptions (and is now on by default)");
- if (!strcmp (p, "save-memoized"))
+ 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"))
{
- flag_memoize_lookups = 1;
- flag_save_memoized_contexts = 1;
+ /* ignore */
found = 1;
}
- else if (!strcmp (p, "no-save-memoized"))
+ else if (!strcmp (p, "all-virtual")
+ || !strcmp (p, "enum-int-equiv")
+ || !strcmp (p, "no-nonnull-objects")
+ || !strcmp (p, "no-ansi-overloading"))
{
- flag_memoize_lookups = 0;
- flag_save_memoized_contexts = 0;
+ warning ("-f%s is no longer supported", p);
found = 1;
}
else if (! strcmp (p, "alt-external-templates"))
@@ -561,23 +591,18 @@ lang_decode_option (p)
flag_guiding_decls = 0;
found = 1;
}
- else if (!strcmp (p, "ansi-overloading"))
- found = 1;
- else if (!strcmp (p, "no-ansi-overloading"))
- {
- error ("-fno-ansi-overloading is no longer supported");
- found = 1;
- }
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))
{
@@ -643,6 +668,8 @@ lang_decode_option (p)
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"))
@@ -685,10 +712,16 @@ lang_decode_option (p)
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, "comment"))
; /* cpp handles this one. */
else if (!strcmp (p, "comments"))
@@ -710,22 +743,20 @@ lang_decode_option (p)
warn_sign_compare = setting;
warn_extern_inline = setting;
warn_nonvdtor = 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);
- warn_template_debugging = setting;
warn_reorder = setting;
warn_sign_promo = setting;
/* Only warn about unknown pragmas that are not in system
headers. */
- warn_unknown_pragmas = 1;
+ warn_unknown_pragmas = 1;
+ warn_nontemplate_friend = setting;
}
-
- else if (!strcmp (p, "overloaded-virtual"))
- warn_overloaded_virtual = setting;
- else return 0;
+ else return strings_processed;
}
else if (!strcmp (p, "-ansi"))
flag_no_nonansi_builtin = 1, flag_ansi = 1,
@@ -738,7 +769,7 @@ lang_decode_option (p)
spew_debug = 1;
#endif
else
- return 0;
+ return strings_processed;
return 1;
}
@@ -829,123 +860,88 @@ warn_if_unknown_interface (decl)
/* A subroutine of the parser, to handle a component list. */
-tree
-grok_x_components (specs, components)
- tree specs, components;
+void
+grok_x_components (specs)
+ tree specs;
{
- register tree t, x, tcode;
-
- /* We just got some friends. They have been recorded elsewhere. */
- if (components == void_type_node)
- return NULL_TREE;
+ struct pending_inline **p;
+ tree t;
- if (components == NULL_TREE)
+ t = groktypename (build_decl_list (strip_attrs (specs), NULL_TREE));
+
+ if (t == NULL_TREE)
{
- t = groktypename (build_decl_list (specs, NULL_TREE));
-
- if (t == NULL_TREE)
- {
- error ("error in component specification");
- return NULL_TREE;
- }
-
- switch (TREE_CODE (t))
- {
- case VAR_DECL:
- /* Static anonymous unions come out as VAR_DECLs. */
- if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TREE_TYPE (t))))
- return t;
-
- /* We return SPECS here, because in the parser it was ending
- up with not doing anything to $$, which is what SPECS
- represents. */
- return specs;
- break;
+ cp_error ("invalid member declaration");
+ return;
+ }
- case RECORD_TYPE:
- /* This code may be needed for UNION_TYPEs as
- well. */
- tcode = record_type_node;
- if (CLASSTYPE_DECLARED_CLASS (t))
- tcode = class_type_node;
- else if (IS_SIGNATURE (t))
- tcode = signature_type_node;
-
- if (CLASSTYPE_IS_TEMPLATE (t))
- /* In this case, the TYPE_IDENTIFIER will be something
- like S<T>, rather than S, so to get the correct name we
- look at the template. */
- x = DECL_NAME (CLASSTYPE_TI_TEMPLATE (t));
- else
- x = TYPE_IDENTIFIER (t);
+ /* The only case where we need to do anything additional here is an
+ anonymous union field, e.g.: `struct S { union { int i; }; };'. */
+ if (!ANON_UNION_TYPE_P (t))
+ return;
- t = xref_tag (tcode, x, NULL_TREE, 0);
- return NULL_TREE;
- break;
+ fixup_anonymous_union (t);
+ finish_member_declaration (build_lang_field_decl (FIELD_DECL,
+ NULL_TREE,
+ t));
- case UNION_TYPE:
- case ENUMERAL_TYPE:
- if (TREE_CODE (t) == UNION_TYPE)
- tcode = union_type_node;
- else
- tcode = enum_type_node;
+ /* 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;
+}
- t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0);
- if (TREE_CODE (t) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
- {
- /* See also shadow_tag. */
-
- struct pending_inline **p;
- tree *q;
- x = build_lang_field_decl (FIELD_DECL, NULL_TREE, t);
-
- /* Wipe out memory of synthesized methods */
- TYPE_HAS_CONSTRUCTOR (t) = 0;
- TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 0;
- TYPE_HAS_INIT_REF (t) = 0;
- TYPE_HAS_CONST_INIT_REF (t) = 0;
- TYPE_HAS_ASSIGN_REF (t) = 0;
- TYPE_HAS_ASSIGNMENT (t) = 0;
- TYPE_HAS_CONST_ASSIGN_REF (t) = 0;
-
- q = &TYPE_METHODS (t);
- while (*q)
- {
- if (DECL_ARTIFICIAL (*q))
- *q = TREE_CHAIN (*q);
- else
- q = &TREE_CHAIN (*q);
- }
- if (TYPE_METHODS (t))
- error ("an anonymous union cannot have function members");
+/* 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.
- p = &pending_inlines;
- for (; *p; *p = (*p)->next)
- if (DECL_CONTEXT ((*p)->fndecl) != t)
- break;
- }
- else if (TREE_CODE (t) == ENUMERAL_TYPE)
- x = grok_enum_decls (NULL_TREE);
- else
- x = NULL_TREE;
- return x;
- break;
+ 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. */
- default:
- if (t != void_type_node)
- error ("empty component declaration");
- return NULL_TREE;
- }
- }
+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
- /* There may or may not be any enum decls to grok, but
- grok_enum_decls will just return components, if there aren't
- any. We used to try to figure out whether or not there were
- any enum decls based on the type of components, but that's too
- hard; it might be something like `enum { a } *p;'. */
- return grok_enum_decls (components);
+ 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.
@@ -969,8 +965,8 @@ grok_x_components (specs, components)
QUALS are the qualifiers for the this pointer. */
void
-grokclassfn (ctype, cname, function, flags, quals)
- tree ctype, cname, function;
+grokclassfn (ctype, function, flags, quals)
+ tree ctype, function;
enum overload_flags flags;
tree quals;
{
@@ -978,8 +974,6 @@ grokclassfn (ctype, cname, function, flags, quals)
tree arg_types;
tree parm;
tree qualtype;
- tree fntype = TREE_TYPE (function);
- tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
if (fn_name == NULL_TREE)
{
@@ -1006,24 +1000,6 @@ grokclassfn (ctype, cname, function, flags, quals)
&& (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function)))
constp = 0;
- if (DECL_CONSTRUCTOR_P (function))
- {
- if (TYPE_USES_VIRTUAL_BASECLASSES (ctype))
- {
- DECL_CONSTRUCTOR_FOR_VBASE_P (function) = 1;
- /* In this case we need "in-charge" flag saying whether
- this constructor is responsible for initialization
- of virtual baseclasses or not. */
- 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;
- TREE_CHAIN (parm) = last_function_parms;
- last_function_parms = parm;
- }
- }
-
parm = build_decl (PARM_DECL, this_identifier, type);
/* Mark the artificial `this' parameter as "artificial". */
SET_DECL_ARTIFICIAL (parm);
@@ -1037,81 +1013,24 @@ grokclassfn (ctype, cname, function, flags, quals)
last_function_parms = parm;
}
- if (flags == DTOR_FLAG)
+ 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))
{
- char *buf, *dbuf;
- int len = sizeof (DESTRUCTOR_DECL_PREFIX)-1;
-
- arg_types = hash_tree_chain (integer_type_node, void_list_node);
- TREE_SIDE_EFFECTS (arg_types) = 1;
- /* Build the overload name. It will look like `7Example'. */
- if (IDENTIFIER_TYPE_VALUE (cname))
- dbuf = build_overload_name (IDENTIFIER_TYPE_VALUE (cname), 1, 1);
- else if (IDENTIFIER_LOCAL_VALUE (cname))
- dbuf = build_overload_name (TREE_TYPE (IDENTIFIER_LOCAL_VALUE (cname)),
- 1, 1);
- else
- /* Using ctype fixes the `X::Y::~Y()' crash. The cname has no type when
- it's defined out of the class definition, since poplevel_class wipes
- it out. This used to be internal error 346. */
- dbuf = build_overload_name (ctype, 1, 1);
- buf = (char *) alloca (strlen (dbuf) + sizeof (DESTRUCTOR_DECL_PREFIX));
- bcopy (DESTRUCTOR_DECL_PREFIX, buf, len);
- buf[len] = '\0';
- strcat (buf, dbuf);
- DECL_ASSEMBLER_NAME (function) = get_identifier (buf);
- parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node);
- /* Mark the artificial `__in_chrg' parameter as "artificial". */
- SET_DECL_ARTIFICIAL (parm);
- TREE_READONLY (parm) = 1;
- DECL_ARG_TYPE (parm) = integer_type_node;
- /* This is the same chain as DECL_ARGUMENTS (...). */
- TREE_CHAIN (last_function_parms) = parm;
+ maybe_retrofit_in_chrg (function);
+ arg_types = TYPE_ARG_TYPES (TREE_TYPE (function));
+ }
- fntype = build_cplus_method_type (qualtype, void_type_node,
- arg_types);
- if (raises)
- {
- fntype = build_exception_variant (fntype, raises);
- }
- TREE_TYPE (function) = fntype;
+ if (flags == DTOR_FLAG)
+ {
+ DECL_ASSEMBLER_NAME (function) = build_destructor_name (ctype);
TYPE_HAS_DESTRUCTOR (ctype) = 1;
}
else
- {
- tree these_arg_types;
-
- if (DECL_CONSTRUCTOR_FOR_VBASE_P (function))
- {
- arg_types = hash_tree_chain (integer_type_node,
- TREE_CHAIN (arg_types));
- fntype = build_cplus_method_type (qualtype,
- TREE_TYPE (TREE_TYPE (function)),
- arg_types);
- if (raises)
- {
- fntype = build_exception_variant (fntype, raises);
- }
- TREE_TYPE (function) = fntype;
- arg_types = TYPE_ARG_TYPES (TREE_TYPE (function));
- }
-
- these_arg_types = arg_types;
-
- if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE)
- /* Only true for static member functions. */
- these_arg_types = hash_tree_chain (build_pointer_type (qualtype),
- arg_types);
-
- DECL_ASSEMBLER_NAME (function)
- = build_decl_overload (fn_name, these_arg_types,
- 1 + DECL_CONSTRUCTOR_P (function));
- }
-
- DECL_ARGUMENTS (function) = last_function_parms;
- /* First approximations. */
- DECL_CONTEXT (function) = ctype;
- DECL_CLASS_CONTEXT (function) = ctype;
+ set_mangled_name_for_decl (function);
}
/* Work on the expr used by alignof (this is only called by the parser). */
@@ -1193,7 +1112,9 @@ grok_array_decl (array_expr, 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. */
+ /* 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;
@@ -1241,9 +1162,7 @@ delete_sanity (exp, size, doing_vec, use_global_delete)
tree exp, size;
int doing_vec, use_global_delete;
{
- tree t;
- tree type;
- enum tree_code code;
+ 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;
@@ -1259,65 +1178,45 @@ delete_sanity (exp, size, doing_vec, use_global_delete)
return t;
}
- t = exp;
- if (TREE_CODE (t) == OFFSET_REF)
- t = resolve_offset_ref (t);
- t = stabilize_reference (convert_from_reference (t));
- type = TREE_TYPE (t);
- code = TREE_CODE (type);
+ 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);
- switch (doing_vec)
+ if (t == NULL_TREE || t == error_mark_node)
{
- case 2:
- maxindex = build_binary_op (MINUS_EXPR, size, integer_one_node, 1);
- pedwarn ("anachronistic use of array size in vector delete");
- /* Fall through. */
- case 1:
- break;
- default:
- if (code != POINTER_TYPE)
- {
- cp_error ("type `%#T' argument given to `delete', expected pointer",
- type);
- return error_mark_node;
- }
-
- /* 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);
+ cp_error ("type `%#T' argument given to `delete', expected pointer",
+ TREE_TYPE (exp));
+ return error_mark_node;
}
- if (code == POINTER_TYPE)
+ if (doing_vec == 2)
{
-#if 0
- /* As of Valley Forge, you can delete a pointer to const. */
- if (TREE_READONLY (TREE_TYPE (type)))
- {
- error ("`const *' cannot be deleted");
- return error_mark_node;
- }
-#endif
- /* You can't delete functions. */
- if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
- {
- error ("cannot delete a function");
- return error_mark_node;
- }
+ maxindex = build_binary_op (MINUS_EXPR, size, integer_one_node, 1);
+ pedwarn ("anachronistic use of array size in vector delete");
}
-#if 0
- /* If the type has no destructor, then we should build a regular
- delete, instead of a vector delete. Otherwise, we would end
- up passing a bogus offset into __builtin_delete, which is
- not expecting it. */
- if (doing_vec
- && TREE_CODE (type) == POINTER_TYPE
- && !TYPE_HAS_DESTRUCTOR (TREE_TYPE (type)))
+ 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)
{
- doing_vec = 0;
- use_global_delete = 1;
+ error ("cannot delete a function");
+ return error_mark_node;
}
-#endif
+
+ /* 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,
@@ -1329,8 +1228,8 @@ delete_sanity (exp, size, doing_vec, use_global_delete)
{
/* 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);
+ 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;
}
@@ -1382,6 +1281,70 @@ check_member_template (tmpl)
cp_error ("template declaration of `%#D'", decl);
}
+/* Return true iff TYPE is a valid Java parameter or return type. */
+
+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. */
@@ -1391,7 +1354,7 @@ check_classfn (ctype, function)
tree ctype, function;
{
tree fn_name = DECL_NAME (function);
- tree fndecl;
+ tree fndecl, fndecls;
tree method_vec = CLASSTYPE_METHOD_VEC (complete_type (ctype));
tree *methods = 0;
tree *end = 0;
@@ -1403,27 +1366,31 @@ check_classfn (ctype, function)
end = TREE_VEC_END (method_vec);
/* First suss out ctors and dtors. */
- if (*methods && fn_name == DECL_NAME (*methods)
+ if (*methods && fn_name == DECL_NAME (OVL_CURRENT (*methods))
&& DECL_CONSTRUCTOR_P (function))
goto got_it;
- if (*++methods && fn_name == DECL_NAME (*methods)
+ if (*++methods && fn_name == DECL_NAME (OVL_CURRENT (*methods))
&& DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function)))
goto got_it;
- while (++methods != end)
+ while (++methods != end && *methods)
{
fndecl = *methods;
- if (fn_name == DECL_NAME (*methods))
+ if (fn_name == DECL_NAME (OVL_CURRENT (*methods)))
{
got_it:
- for (fndecl = *methods; fndecl != NULL_TREE;
- fndecl = DECL_CHAIN (fndecl))
+ for (fndecls = *methods; fndecls != NULL_TREE;
+ fndecls = OVL_NEXT (fndecls))
{
+ fndecl = OVL_CURRENT (fndecls);
/* The DECL_ASSEMBLER_NAME for a TEMPLATE_DECL is
not mangled, so the check below does not work
- correctly in that case. */
+ 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. */
if (TREE_CODE (function) != TEMPLATE_DECL
&& TREE_CODE (fndecl) != TEMPLATE_DECL
+ && !DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function))
&& (DECL_ASSEMBLER_NAME (function)
== DECL_ASSEMBLER_NAME (fndecl)))
return fndecl;
@@ -1477,22 +1444,20 @@ check_classfn (ctype, function)
if (templates)
/* This function might be an instantiation or a specialization.
- We should verify that this is possible. If it is, we must
- somehow add the new declaration to the method vector for the
- class. Perhaps we should use add_method? For now, we simply
- return NULL_TREE, which lets the caller know that this
- function is new, but we don't print an error message. */
+ We should verify that this is possible. For now, we simply
+ return NULL_TREE, which lets the caller know that this function
+ is new, but we don't print an error message. */
return NULL_TREE;
- if (methods != end)
+ 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", DECL_CHAIN (fndecl) ? "s are" : " is",
- fndecl);
- while (fndecl = DECL_CHAIN (fndecl), fndecl)
- cp_error_at (" %#D", fndecl);
+ 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
{
@@ -1567,8 +1532,9 @@ grokfield (declarator, declspecs, init, asmspec_tree, attrlist)
init = NULL_TREE;
value = grokdeclarator (declarator, declspecs, FIELD, init != 0, NULL_TREE);
- if (! value)
- return value; /* friend or constructor went bad. */
+ if (! value || value == error_mark_node)
+ /* friend or constructor went bad. */
+ return value;
/* Pass friendly classes back. */
if (TREE_CODE (value) == VOID_TYPE)
@@ -1586,13 +1552,13 @@ grokfield (declarator, declspecs, init, asmspec_tree, attrlist)
DECL_NONLOCAL (value) = 1;
DECL_CONTEXT (value) = current_class_type;
DECL_CLASS_CONTEXT (value) = current_class_type;
- CLASSTYPE_LOCAL_TYPEDECLS (current_class_type) = 1;
/* Now that we've updated the context, we need to remangle the
name for this TYPE_DECL. */
DECL_ASSEMBLER_NAME (value) = DECL_NAME (value);
- DECL_ASSEMBLER_NAME (value) =
- get_identifier (build_overload_name (TREE_TYPE (value), 1, 1));
+ if (!uses_template_parms (value))
+ DECL_ASSEMBLER_NAME (value) =
+ get_identifier (build_overload_name (TREE_TYPE (value), 1, 1));
pushdecl_class_level (value);
return value;
@@ -1680,6 +1646,19 @@ grokfield (declarator, declspecs, init, asmspec_tree, attrlist)
&& (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == FUNCTION_DECL))
value = push_template_decl (value);
+ /* Check to see if a field redeclares a template parameter. */
+ if (current_template_parms
+ && TREE_CODE (declarator) == IDENTIFIER_NODE
+ && IDENTIFIER_LOCAL_VALUE (declarator))
+ {
+ tree olddecl = IDENTIFIER_LOCAL_VALUE (declarator);
+ if (decl_template_parm_p (olddecl))
+ {
+ cp_error ("redeclaration of template parameter `%T'", declarator);
+ cp_error_at (" previously declared here `%#D'", olddecl);
+ }
+ }
+
if (attrlist)
cplus_decl_attributes (value, TREE_PURPOSE (attrlist),
TREE_VALUE (attrlist));
@@ -1744,15 +1723,6 @@ grokfield (declarator, declspecs, init, asmspec_tree, attrlist)
}
if (TREE_CODE (value) == FUNCTION_DECL)
{
- check_default_args (value);
- if (DECL_CHAIN (value) != NULL_TREE)
- {
- /* Need a fresh node here so that we don't get circularity
- when we link these together. */
- value = copy_node (value);
- /* When does this happen? */
- my_friendly_assert (init == NULL_TREE, 193);
- }
if (asmspec)
{
/* This must override the asm specifier which was placed
@@ -1802,6 +1772,17 @@ grokbitfield (declarator, declspecs, width)
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");
@@ -1881,7 +1862,7 @@ grokoptypename (declspecs, declarator)
int
copy_assignment_arg_p (parmtype, virtualp)
tree parmtype;
- int virtualp;
+ int virtualp ATTRIBUTE_UNUSED;
{
if (current_class_type == NULL_TREE)
return 0;
@@ -1978,7 +1959,7 @@ constructor_name_full (thing)
else if (IS_AGGR_TYPE_CODE (TREE_CODE (thing)))
{
if (TYPE_WAS_ANONYMOUS (thing) && TYPE_HAS_CONSTRUCTOR (thing))
- thing = DECL_NAME (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (thing), 0));
+ thing = DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (thing), 0)));
else
thing = TYPE_NAME (thing);
}
@@ -2140,6 +2121,82 @@ get_temp_regvar (type, init)
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. */
+
+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 (TREE_CODE (field) != FIELD_DECL)
+ 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
@@ -2152,13 +2209,13 @@ finish_anon_union (anon_union_decl)
tree anon_union_decl;
{
tree type = TREE_TYPE (anon_union_decl);
- tree field, main_decl = NULL_TREE;
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 ((field = TYPE_FIELDS (type)) == NULL_TREE)
+ if (TYPE_FIELDS (type) == NULL_TREE)
return;
if (public_p)
@@ -2167,58 +2224,19 @@ finish_anon_union (anon_union_decl)
return;
}
- for (; field; field = TREE_CHAIN (field))
- {
- tree decl;
- if (TREE_CODE (field) != FIELD_DECL)
- 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);
-
- 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) = public_p;
- TREE_STATIC (decl) = static_p;
- DECL_EXTERNAL (decl) = external_p;
- decl = pushdecl (decl);
-
- /* Only write out one anon union element--choose the one that
- can hold them all. */
- if (main_decl == NULL_TREE
- && 1 == simple_cst_equal (DECL_SIZE (decl),
- DECL_SIZE (anon_union_decl)))
- {
- main_decl = decl;
- }
- else
- {
- /* ??? This causes there to be no debug info written out
- about this decl. */
- TREE_ASM_WRITTEN (decl) = 1;
- }
+ main_decl = build_anon_union_vars (anon_union_decl, &elems,
+ static_p, external_p);
- DECL_INITIAL (decl) = NULL_TREE;
- /* 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;
+ if (main_decl == NULL_TREE)
+ {
+ warning ("anonymous union with no members");
+ return;
}
+
if (static_p)
{
- if (main_decl)
- {
- make_decl_rtl (main_decl, 0, toplevel_bindings_p ());
- DECL_RTL (anon_union_decl) = DECL_RTL (main_decl);
- }
- else
- {
- warning ("anonymous union with no members");
- return;
- }
+ 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
@@ -2413,6 +2431,30 @@ comdat_linkage (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 can't use make_decl_one_only for variables, because their
+ DECL_INITIAL may not have been set properly yet. */
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ make_decl_one_only (decl);
+ else
+ comdat_linkage (decl);
+}
+
/* Set TREE_PUBLIC and/or DECL_EXTERN on the vtable DECL,
based on TYPE and other static flags.
@@ -2427,12 +2469,10 @@ import_export_vtable (decl, type, final)
if (DECL_INTERFACE_KNOWN (decl))
return;
- /* +e0 or +e1 */
- if (write_virtuals < 2 && write_virtuals != 0)
+ if (TYPE_FOR_JAVA (type))
{
TREE_PUBLIC (decl) = 1;
- if (write_virtuals < 0)
- DECL_EXTERNAL (decl) = 1;
+ DECL_EXTERNAL (decl) = 1;
DECL_INTERFACE_KNOWN (decl) = 1;
}
else if (CLASSTYPE_INTERFACE_KNOWN (type))
@@ -2441,11 +2481,9 @@ import_export_vtable (decl, type, final)
DECL_EXTERNAL (decl) = ! CLASSTYPE_VTABLE_NEEDS_WRITING (type);
DECL_INTERFACE_KNOWN (decl) = 1;
- /* For WIN32 we also want to put explicit instantiations in
- linkonce sections. */
- if (CLASSTYPE_EXPLICIT_INSTANTIATION (type)
- && supports_one_only () && ! SUPPORTS_WEAK)
- make_decl_one_only (decl);
+ /* Always make vtables weak. */
+ if (flag_weak)
+ comdat_linkage (decl);
}
else
{
@@ -2483,29 +2521,39 @@ import_export_vtable (decl, type, final)
}
}
-static void
-import_export_template (type)
- tree type;
-{
- if (CLASSTYPE_IMPLICIT_INSTANTIATION (type)
- && ! flag_implicit_templates
- && CLASSTYPE_INTERFACE_UNKNOWN (type))
- {
- SET_CLASSTYPE_INTERFACE_KNOWN (type);
- CLASSTYPE_INTERFACE_ONLY (type) = 1;
- CLASSTYPE_VTABLE_NEEDS_WRITING (type) = 0;
- }
-}
-
-int
-finish_prevtable_vardecl (prev, vars)
- tree prev, vars;
+/* Determine whether or not we want to specifically import or export CTYPE,
+ using various heuristics. */
+
+void
+import_export_class (ctype)
+ tree ctype;
{
- tree ctype = DECL_CONTEXT (vars);
- import_export_template (ctype);
+ /* -1 for imported, 1 for exported. */
+ int import_export = 0;
+
+ if (CLASSTYPE_INTERFACE_KNOWN (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;
#ifndef MULTIPLE_SYMBOL_SPACES
- if (CLASSTYPE_INTERFACE_UNKNOWN (ctype) && TYPE_VIRTUAL_P (ctype)
+ /* 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;
@@ -2516,28 +2564,64 @@ finish_prevtable_vardecl (prev, vars)
&& !DECL_THIS_INLINE (method)
&& !DECL_ABSTRACT_VIRTUAL_P (method))
{
- SET_CLASSTYPE_INTERFACE_KNOWN (ctype);
- CLASSTYPE_VTABLE_NEEDS_WRITING (ctype)
- = ! DECL_REALLY_EXTERN (method);
- CLASSTYPE_INTERFACE_ONLY (ctype) = DECL_REALLY_EXTERN (method);
+ import_export = (DECL_REALLY_EXTERN (method) ? -1 : 1);
break;
}
}
}
#endif
+ if (import_export)
+ {
+ SET_CLASSTYPE_INTERFACE_KNOWN (ctype);
+ CLASSTYPE_VTABLE_NEEDS_WRITING (ctype) = (import_export > 0);
+ CLASSTYPE_INTERFACE_ONLY (ctype) = (import_export < 0);
+ }
+}
+
+int
+finish_prevtable_vardecl (prev, vars)
+ tree prev ATTRIBUTE_UNUSED, vars;
+{
+ tree ctype = DECL_CONTEXT (vars);
+ import_export_class (ctype);
import_export_vtable (vars, ctype, 1);
return 1;
}
-
+
+/* 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 (prev, vars)
tree prev, vars;
{
- if (write_virtuals >= 0
- && ! DECL_EXTERNAL (vars)
- && ((TREE_PUBLIC (vars) && ! DECL_WEAK (vars) && ! DECL_ONE_ONLY (vars))
- || CLASSTYPE_EXPLICIT_INSTANTIATION (DECL_CONTEXT (vars))
+ 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))
@@ -2574,6 +2658,10 @@ finish_vtable_vardecl (prev, 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)))
@@ -2680,11 +2768,14 @@ import_export_decl (decl)
if (DECL_INTERFACE_KNOWN (decl))
return;
- if (DECL_TEMPLATE_INSTANTIATION (decl))
+ if (DECL_TEMPLATE_INSTANTIATION (decl)
+ || DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl))
{
DECL_NOT_REALLY_EXTERN (decl) = 1;
- if (DECL_IMPLICIT_INSTANTIATION (decl)
- && (flag_implicit_templates || DECL_THIS_INLINE (decl)))
+ 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
@@ -2707,6 +2798,10 @@ import_export_decl (decl)
DECL_NOT_REALLY_EXTERN (decl)
= ! (CLASSTYPE_INTERFACE_ONLY (ctype)
|| (DECL_THIS_INLINE (decl) && ! flag_implement_inlines));
+
+ /* Always make artificials weak. */
+ if (DECL_ARTIFICIAL (decl) && flag_weak)
+ comdat_linkage (decl);
}
else
comdat_linkage (decl);
@@ -2716,24 +2811,21 @@ import_export_decl (decl)
{
tree ctype = TREE_TYPE (DECL_NAME (decl));
if (IS_AGGR_TYPE (ctype) && CLASSTYPE_INTERFACE_KNOWN (ctype)
- && TYPE_VIRTUAL_P (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)
- = TYPE_READONLY (ctype)
- || TYPE_VOLATILE (ctype)
- || ! (CLASSTYPE_INTERFACE_ONLY (ctype)
- || (DECL_THIS_INLINE (decl) && ! flag_implement_inlines));
+ = ! (CLASSTYPE_INTERFACE_ONLY (ctype)
+ || (DECL_THIS_INLINE (decl) && ! flag_implement_inlines));
- /* For WIN32 we also want to put explicit instantiations in
- linkonce sections. */
- if (CLASSTYPE_EXPLICIT_INSTANTIATION (ctype)
- && supports_one_only () && ! SUPPORTS_WEAK)
- make_decl_one_only (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;
@@ -2770,20 +2862,19 @@ extern int parse_time, varconst_time;
extern tree pending_templates;
extern tree maybe_templates;
-extern struct obstack permanent_obstack;
-
static tree
get_sentry (base)
tree base;
{
tree sname = get_id_2 ("__sn", base);
- /* for struct X foo __attribute__((weak)), there is a counter
+ /* 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 (&permanent_obstack, &permanent_obstack);
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
sentry = build_decl (VAR_DECL, sname, integer_type_node);
TREE_PUBLIC (sentry) = 1;
DECL_ARTIFICIAL (sentry) = 1;
@@ -2797,6 +2888,368 @@ get_sentry (base)
return sentry;
}
+/* A list of objects which have constructors or destructors
+ which reside in the global scope. The decl is stored in
+ the TREE_VALUE slot and the initializer is stored
+ in the TREE_PURPOSE slot. */
+extern tree static_aggregates_initp;
+
+/* Set up the static_aggregates* lists for processing. Subroutine of
+ finish_file. Note that this function changes the format of
+ static_aggregates_initp, from (priority . decl) to
+ (priority . ((initializer . decl) ...)). */
+
+static void
+setup_initp ()
+{
+ tree t, *p, next_t;
+
+ if (! flag_init_priority)
+ {
+ for (t = static_aggregates_initp; t; t = TREE_CHAIN (t))
+ cp_warning ("init_priority for `%#D' ignored without -finit-priority",
+ TREE_VALUE (t));
+ return;
+ }
+
+ /* First, remove any entries from static_aggregates that are also in
+ static_aggregates_initp, and update the entries in _initp to
+ include the initializer. */
+ p = &static_aggregates;
+ for (; *p; )
+ {
+ t = value_member (TREE_VALUE (*p), static_aggregates_initp);
+
+ if (t)
+ {
+ TREE_VALUE (t) = *p;
+ *p = TREE_CHAIN (*p);
+ TREE_CHAIN (TREE_VALUE (t)) = NULL_TREE;
+ }
+ else
+ p = &TREE_CHAIN (*p);
+ }
+
+ /* Then, group static_aggregates_initp. After this step, there will only
+ be one entry for each priority, with a chain coming off it. */
+ t = static_aggregates_initp;
+ static_aggregates_initp = NULL_TREE;
+
+ for (; t; t = next_t)
+ {
+ next_t = TREE_CHAIN (t);
+
+ for (p = &static_aggregates_initp; ; p = &TREE_CHAIN (*p))
+ {
+ if (*p == NULL_TREE
+ || tree_int_cst_lt (TREE_PURPOSE (*p), TREE_PURPOSE (t)))
+ {
+ TREE_CHAIN (t) = *p;
+ *p = t;
+ break;
+ }
+ else if (tree_int_cst_equal (TREE_PURPOSE (*p), TREE_PURPOSE (t)))
+ {
+ TREE_CHAIN (TREE_VALUE (t)) = TREE_VALUE (*p);
+ TREE_VALUE (*p) = TREE_VALUE (t);
+ break;
+ }
+ }
+ }
+
+ /* Reverse each list to preserve the order (currently reverse declaration
+ order, for destructors). */
+ for (t = static_aggregates_initp; t; t = TREE_CHAIN (t))
+ TREE_VALUE (t) = nreverse (TREE_VALUE (t));
+}
+
+/* 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 (flag_init_priority)
+ {
+ if (initp == 0)
+ initp = DEFAULT_INIT_PRIORITY;
+
+ 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);
+
+ store_parm_decls ();
+ pushlevel (0);
+ clear_last_expr ();
+ push_momentary ();
+ expand_start_bindings (0);
+}
+
+/* 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;
+
+ if (! initp)
+ {
+ tree list = (method_type == 'I' ? static_ctors : static_dtors);
+
+ if (! current_function_decl && list)
+ start_objects (method_type, initp);
+
+ for (; list; list = TREE_CHAIN (list))
+ expand_expr_stmt (build_function_call (TREE_VALUE (list), NULL_TREE));
+ }
+
+ if (! current_function_decl)
+ return;
+
+ 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 (! flag_init_priority)
+ {
+ if (method_type == 'I')
+ assemble_constructor (fnname);
+ else
+ assemble_destructor (fnname);
+ }
+
+#ifdef ASM_OUTPUT_SECTION_NAME
+ /* 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. */
+ if (flag_init_priority)
+ {
+ char buf[15];
+ if (initp == 0)
+ initp = DEFAULT_INIT_PRIORITY;
+ 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
+}
+
+/* Generate a function to run a set of global destructors. START is either
+ NULL_TREE or a node indicating a set of destructors with the same
+ init priority. Subroutine of finish_file. */
+
+static void
+do_dtors (start)
+ tree start;
+{
+ tree vars;
+ int initp;
+
+ if (start)
+ {
+ initp = TREE_INT_CST_LOW (TREE_PURPOSE (start));
+ vars = TREE_VALUE (start);
+ }
+ else
+ {
+ initp = 0;
+ vars = static_aggregates;
+ }
+
+ for (; vars; vars = TREE_CHAIN (vars))
+ {
+ tree decl = TREE_VALUE (vars);
+ tree type = TREE_TYPE (decl);
+ tree temp;
+
+ if (TYPE_NEEDS_DESTRUCTOR (type) && ! TREE_STATIC (vars)
+ && ! DECL_EXTERNAL (decl))
+ {
+ int protect = (TREE_PUBLIC (decl) && (DECL_COMMON (decl)
+ || DECL_ONE_ONLY (decl)
+ || DECL_WEAK (decl)));
+
+ if (! current_function_decl)
+ start_objects ('D', initp);
+
+ /* 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 must convince enforce_access to let us access the
+ DECL. */
+ if (member_p (decl))
+ {
+ DECL_CLASS_CONTEXT (current_function_decl)
+ = DECL_CONTEXT (decl);
+ DECL_STATIC_FUNCTION_P (current_function_decl) = 1;
+ }
+
+ temp = build_cleanup (decl);
+
+ if (protect)
+ {
+ tree sentry = get_sentry (DECL_ASSEMBLER_NAME (decl));
+ sentry = build_unary_op (PREDECREMENT_EXPR, sentry, 0);
+ sentry = build_binary_op (EQ_EXPR, sentry, integer_zero_node, 1);
+ expand_start_cond (sentry, 0);
+ }
+
+ expand_expr_stmt (temp);
+
+ if (protect)
+ expand_end_cond ();
+
+ /* 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;
+ }
+ }
+
+ finish_objects ('D', initp);
+}
+
+/* Generate a function to run a set of global constructors. START is
+ either NULL_TREE or a node indicating a set of constructors with the
+ same init priority. Subroutine of finish_file. */
+
+static void
+do_ctors (start)
+ tree start;
+{
+ tree vars;
+ int initp;
+
+ if (start)
+ {
+ initp = TREE_INT_CST_LOW (TREE_PURPOSE (start));
+ vars = TREE_VALUE (start);
+ }
+ else
+ {
+ initp = 0;
+ vars = static_aggregates;
+ }
+
+ /* Reverse the list so it's in the right order for ctors. */
+ vars = nreverse (vars);
+
+ for (; vars; vars = TREE_CHAIN (vars))
+ {
+ tree decl = TREE_VALUE (vars);
+ tree init = TREE_PURPOSE (vars);
+
+ /* If this was a static attribute within some function's scope,
+ then don't initialize it here. Also, don't bother
+ with initializers that contain errors. */
+ if (TREE_STATIC (vars)
+ || DECL_EXTERNAL (decl)
+ || (init && TREE_CODE (init) == TREE_LIST
+ && value_member (error_mark_node, init)))
+ continue;
+
+ if (TREE_CODE (decl) == VAR_DECL)
+ {
+ int protect = (TREE_PUBLIC (decl) && (DECL_COMMON (decl)
+ || DECL_ONE_ONLY (decl)
+ || DECL_WEAK (decl)));
+
+ if (! current_function_decl)
+ start_objects ('I', initp);
+
+ /* Set these global variables so that GDB at least puts
+ us near the declaration which required the initialization. */
+ input_filename = DECL_SOURCE_FILE (decl);
+ lineno = DECL_SOURCE_LINE (decl);
+ emit_note (input_filename, lineno);
+
+ /* 9.5p5: The initializer of a static member of a class has
+ the same access rights as a member function. */
+ if (member_p (decl))
+ {
+ DECL_CLASS_CONTEXT (current_function_decl)
+ = DECL_CONTEXT (decl);
+ DECL_STATIC_FUNCTION_P (current_function_decl) = 1;
+ }
+
+ if (protect)
+ {
+ tree sentry = get_sentry (DECL_ASSEMBLER_NAME (decl));
+ sentry = build_unary_op (PREINCREMENT_EXPR, sentry, 0);
+ sentry = build_binary_op
+ (EQ_EXPR, sentry, integer_one_node, 1);
+ expand_start_cond (sentry, 0);
+ }
+
+ 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 ();
+
+ if (protect)
+ expand_end_cond ();
+
+ DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE;
+ DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
+ }
+ else if (decl == error_mark_node)
+ /* OK */;
+ else
+ my_friendly_abort (22);
+ }
+
+ finish_objects ('I', initp);
+}
+
/* 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
@@ -2818,6 +3271,8 @@ finish_file ()
if (! global_bindings_p () || current_class_type)
return;
+ check_decl_namespace ();
+
start_time = get_run_time ();
/* Otherwise, GDB can get confused, because in only knows
@@ -2829,7 +3284,12 @@ finish_file ()
for (fnname = pending_templates; fnname; fnname = TREE_CHAIN (fnname))
{
+ tree srcloc = TREE_PURPOSE (fnname);
tree decl = TREE_VALUE (fnname);
+
+ input_filename = SRCLOC_FILE (srcloc);
+ lineno = SRCLOC_LINE (srcloc);
+
if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't')
{
instantiate_class_template (decl);
@@ -2855,6 +3315,8 @@ finish_file ()
instantiate_decl (fn);
}
+ cat_namespace_levels();
+
/* Push into C language context, because that's all
we'll need here. */
push_lang_context (lang_name_c);
@@ -2896,194 +3358,31 @@ finish_file ()
if (static_ctors || vars)
needs_messing_up = 1;
- if (static_dtors)
+ if (static_dtors || vars)
needs_cleaning = 1;
- /* See if we really need the hassle. */
- while (vars && needs_cleaning == 0)
- {
- tree decl = TREE_VALUE (vars);
- tree type = TREE_TYPE (decl);
- if (TYPE_NEEDS_DESTRUCTOR (type) && ! TREE_STATIC (vars))
- {
- needs_cleaning = 1;
- break;
- }
-
- vars = TREE_CHAIN (vars);
- }
-
- if (needs_cleaning == 0)
- goto mess_up;
+ setup_initp ();
- fnname = get_file_function_name ('D');
- start_function (void_list_node,
- make_call_declarator (fnname, void_list_node, NULL_TREE,
- NULL_TREE),
- NULL_TREE, 0);
- fnname = DECL_ASSEMBLER_NAME (current_function_decl);
- store_parm_decls ();
-
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
-
- /* These must be done in backward order to destroy,
- in which they happen to be! */
- for (vars = static_aggregates; vars; vars = TREE_CHAIN (vars))
+ /* After setup_initp, the aggregates are listed in reverse declaration
+ order, for cleaning. */
+ if (needs_cleaning)
{
- tree decl = TREE_VALUE (vars);
- tree type = TREE_TYPE (decl);
- tree temp = TREE_PURPOSE (vars);
+ do_dtors (NULL_TREE);
- if (TYPE_NEEDS_DESTRUCTOR (type) && ! TREE_STATIC (vars)
- && ! DECL_EXTERNAL (decl))
- {
- int protect = (TREE_PUBLIC (decl) && (DECL_COMMON (decl)
- || DECL_ONE_ONLY (decl)
- || DECL_WEAK (decl)));
-
- temp = build_cleanup (decl);
-
- if (protect)
- {
- tree sentry = get_sentry (DECL_ASSEMBLER_NAME (decl));
- sentry = build_unary_op (PREDECREMENT_EXPR, sentry, 0);
- sentry = build_binary_op (EQ_EXPR, sentry, integer_zero_node, 1);
- expand_start_cond (sentry, 0);
- }
-
- expand_expr_stmt (temp);
-
- if (protect)
- expand_end_cond ();
- }
+ if (flag_init_priority)
+ for (vars = static_aggregates_initp; vars; vars = TREE_CHAIN (vars))
+ do_dtors (vars);
}
- for (; static_dtors; static_dtors = TREE_CHAIN (static_dtors))
- expand_expr_stmt (build_function_call (TREE_VALUE (static_dtors),
- NULL_TREE));
-
- expand_end_bindings (getdecls (), 1, 0);
- poplevel (1, 0, 0);
- pop_momentary ();
-
- finish_function (lineno, 0, 0);
-
- assemble_destructor (IDENTIFIER_POINTER (fnname));
-
- /* if it needed cleaning, then it will need messing up: drop through */
-
- mess_up:
- /* Must do this while we think we are at the top level. */
- vars = nreverse (static_aggregates);
+ /* do_ctors will reverse the lists for messing up. */
if (needs_messing_up)
{
- fnname = get_file_function_name ('I');
- start_function (void_list_node,
- make_call_declarator (fnname, void_list_node, NULL_TREE,
- NULL_TREE),
- NULL_TREE, 0);
- fnname = DECL_ASSEMBLER_NAME (current_function_decl);
- store_parm_decls ();
-
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
-
- while (vars)
- {
- tree decl = TREE_VALUE (vars);
- tree init = TREE_PURPOSE (vars);
-
- /* If this was a static attribute within some function's scope,
- then don't initialize it here. Also, don't bother
- with initializers that contain errors. */
- if (TREE_STATIC (vars)
- || DECL_EXTERNAL (decl)
- || (init && TREE_CODE (init) == TREE_LIST
- && value_member (error_mark_node, init)))
- goto next_mess;
-
- if (TREE_CODE (decl) == VAR_DECL)
- {
- int protect = (TREE_PUBLIC (decl) && (DECL_COMMON (decl)
- || DECL_ONE_ONLY (decl)
- || DECL_WEAK (decl)));
-
- /* Set these global variables so that GDB at least puts
- us near the declaration which required the initialization. */
- input_filename = DECL_SOURCE_FILE (decl);
- lineno = DECL_SOURCE_LINE (decl);
- emit_note (input_filename, lineno);
-
- /* 9.5p5: The initializer of a static member of a class has
- the same access rights as a member function. */
- if (member_p (decl))
- {
- DECL_CLASS_CONTEXT (current_function_decl)
- = DECL_CONTEXT (decl);
- DECL_STATIC_FUNCTION_P (current_function_decl) = 1;
- }
-
- if (protect)
- {
- tree sentry = get_sentry (DECL_ASSEMBLER_NAME (decl));
- sentry = build_unary_op (PREINCREMENT_EXPR, sentry, 0);
- sentry = build_binary_op
- (EQ_EXPR, sentry, integer_one_node, 1);
- expand_start_cond (sentry, 0);
- }
-
- expand_start_target_temps ();
+ do_ctors (NULL_TREE);
- if (IS_AGGR_TYPE (TREE_TYPE (decl))
- || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
- expand_aggr_init (decl, init, 0, 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 ();
-
- if (protect)
- expand_end_cond ();
-
- DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE;
- DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
- }
- else if (decl == error_mark_node)
- ;
- else my_friendly_abort (22);
-
- next_mess:
- vars = TREE_CHAIN (vars);
- }
-
- for (; static_ctors; static_ctors = TREE_CHAIN (static_ctors))
- expand_expr_stmt (build_function_call (TREE_VALUE (static_ctors),
- NULL_TREE));
-
- expand_end_bindings (getdecls (), 1, 0);
- poplevel (1, 0, 0);
- pop_momentary ();
-
- finish_function (lineno, 0, 0);
- assemble_constructor (IDENTIFIER_POINTER (fnname));
- }
+ if (flag_init_priority)
+ for (vars = static_aggregates_initp; vars; vars = TREE_CHAIN (vars))
+ do_ctors (vars);
+ }
permanent_allocation (1);
@@ -3129,6 +3428,8 @@ finish_file ()
import_export_decl (decl);
}
+ mark_all_runtime_matches ();
+
/* Now write out inline functions which had their addresses taken and
which were not declared virtual and which were not declared `extern
inline'. */
@@ -3224,19 +3525,6 @@ finish_file ()
walk_vtables ((void (*) PROTO((tree, tree))) 0,
prune_vtable_vardecl);
- if (write_virtuals == 2)
- {
- /* Now complain about an virtual function tables promised
- but not delivered. */
- while (pending_vtables)
- {
- if (TREE_PURPOSE (pending_vtables) == NULL_TREE)
- error ("virtual function table for `%s' not defined",
- IDENTIFIER_POINTER (TREE_VALUE (pending_vtables)));
- pending_vtables = TREE_CHAIN (pending_vtables);
- }
- }
-
finish_repo ();
this_time = get_run_time ();
@@ -3338,13 +3626,13 @@ build_expr_from_tree (t)
switch (TREE_CODE (t))
{
case IDENTIFIER_NODE:
- return do_identifier (t, 0);
+ 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);
+ return do_identifier (TREE_OPERAND (t, 0), 0, NULL_TREE);
case TEMPLATE_ID_EXPR:
return (lookup_template_function
@@ -3509,12 +3797,21 @@ build_expr_from_tree (t)
else
{
tree name = TREE_OPERAND (t, 0);
- if (TREE_CODE (name) == TEMPLATE_ID_EXPR
+ 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, build_expr_from_tree (TREE_OPERAND (t, 1)),
- current_class_ref);
+ return build_x_function_call (name, args, current_class_ref);
}
case COND_EXPR:
@@ -3666,7 +3963,8 @@ check_cp_case_value (value)
return value;
}
-/* return 1 if root encloses child */
+/* Return 1 if root encloses child. */
+
static int
is_namespace_ancestor (root, child)
tree root, child;
@@ -3677,19 +3975,20 @@ is_namespace_ancestor (root, child)
return 1;
if (child == global_namespace)
return 0;
- return is_namespace_ancestor (root, DECL_NAMESPACE (child));
+ return is_namespace_ancestor (root, CP_DECL_CONTEXT (child));
}
-/* return the namespace that is the common ancestor
- of two given namespaces */
-static tree
+/* 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 (DECL_NAMESPACE (ns1), ns2);
+ return namespace_ancestor (CP_DECL_CONTEXT (ns1), ns2);
}
/* Insert used into the using list of user. Set indirect_flag if this
@@ -3701,130 +4000,200 @@ add_using_namespace (user, used, indirect)
tree used;
int indirect;
{
- tree iter;
- /* using oneself is a no-op */
+ 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 */
- if (purpose_member (used, DECL_NAMESPACE_USING (user)) != NULL_TREE)
- return;
+ /* 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 */
+ /* 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 */
+ /* Add user to the used's users list. */
DECL_NAMESPACE_USERS (used)
= perm_tree_cons (user, 0, DECL_NAMESPACE_USERS (used));
-
- for (iter = DECL_NAMESPACE_USERS (user); iter; iter = TREE_CHAIN (iter))
+
+ /* Recursively add all namespaces used. */
+ for (t = DECL_NAMESPACE_USING (used); t; t = TREE_CHAIN (t))
/* indirect usage */
- add_using_namespace (TREE_PURPOSE (iter), used, 1);
+ 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, val1, val2)
- tree name, val1, val2;
+ambiguous_decl (name, old, new, flags)
+ tree name;
+ tree old;
+ tree new;
+ int flags;
{
- my_friendly_assert (val1 != val2, 376);
- if (is_overloaded_fn (val1) && is_overloaded_fn (val1))
+ 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)
+ && (!(flags & LOOKUP_TEMPLATES_EXPECTED)
+ || !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)
+ {
+ 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)
{
- /* now built a joint list of all overloaded declarations */
- /* XXX if I chain'em together, they will be always considered
- as overloaded */
- sorry ("overloaded functions used from different namespaces");
+ 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);
+ }
}
- cp_error ("ambiguous definition `%D' used", name);
- cp_error_at ("first definition here", val1);
- cp_error_at ("other definition here", val2);
- return error_mark_node;
+ return old;
}
-/* add the bindings of name in used namespaces to val
- the using list is defined by current, and the lookup goes to scope */
-tree
-lookup_using_namespace (name, val, current, scope)
- tree name, val, current, scope;
+/* 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 namespaces from current to scope */
- while (1)
- {
- /* iterate over all used namespaces in current, searching for
- using directives of scope */
- for (iter = DECL_NAMESPACE_USING (current);
- iter; iter = TREE_CHAIN (iter))
- if (TREE_VALUE (iter) == scope)
- {
- val1 = NAMESPACE_BINDING (name, TREE_PURPOSE (iter));
- /* name not found in this space */
- if (!val1)
- continue;
- /* first definition ever */
- if (!val)
- {
- val = val1;
- continue;
- }
- /* Hmmm. Ambiguity. As long as both are overloaded functions,
- this is fine */
- val = ambiguous_decl (name, val, val1);
- if (val == error_mark_node)
- break;
- }
- if (current == scope)
- break;
- current = DECL_NAMESPACE (current);
- }
- return val;
+ /* 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] */
-tree
-qualified_lookup_using_namespace (name, scope)
+/* [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;
{
- tree val = NULL_TREE;
- tree val1;
- /* maintain a list of namespaces visited */
+ /* Maintain a list of namespaces visited... */
tree seen = NULL_TREE;
- /* and a list of namespace yet to see */
+ /* ... and a list of namespace yet to see. */
tree todo = NULL_TREE;
tree usings;
- while (scope)
+ while (scope && (result != error_mark_node))
{
seen = temp_tree_cons (scope, NULL_TREE, seen);
- val1 = NAMESPACE_BINDING (name, scope);
- if (val1)
- {
- if (val)
- {
- val = ambiguous_decl (name, val, val1);
- break;
- }
- else
- val = val1;
- }
- else
- /* consider using directives */
+ 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 this was a real directive, and we have not seen it. */
if (!TREE_INDIRECT_USING (usings)
- && !purpose_member (seen, TREE_PURPOSE (usings)))
+ && !purpose_member (TREE_PURPOSE (usings), seen))
todo = temp_tree_cons (TREE_PURPOSE (usings), NULL_TREE, todo);
if (todo)
{
@@ -3832,103 +4201,593 @@ qualified_lookup_using_namespace (name, scope)
todo = TREE_CHAIN (todo);
}
else
- scope = NULL_TREE; /* if there never was a todo list */
+ scope = NULL_TREE; /* If there never was a todo list. */
}
- return val;
+ return result != error_mark_node;
}
-#if 0
-/* this is broken and should not be called anymore */
-/* Get the inner part of a namespace id. It doesn't have any prefix, nor
- postfix. Returns 0 if in global namespace. */
+/* [namespace.memdef]/2 */
+
+/* Set the context of a declaration to scope. Complain if we are not
+ outside scope. */
+
+void
+set_decl_namespace (decl, scope)
+ tree decl;
+ tree scope;
+{
+ tree old;
+ if (scope == std_node)
+ scope = global_namespace;
+ /* Get rid of namespace aliases. */
+ scope = ORIGINAL_NAMESPACE (scope);
+
+ if (!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. */
tree
-get_namespace_id ()
+decl_namespace (decl)
+ tree decl;
{
- tree x = current_namespace;
- if (x)
- x = TREE_PURPOSE (x);
- return x;
+ 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;
}
-/* Build up a DECL_ASSEMBLER_NAME for NAME in the current namespace. */
+/* Return the namespace where the current declaration is declared. */
tree
-current_namespace_id (name)
- tree name;
+current_decl_namespace ()
{
- tree old_id = get_namespace_id ();
- char *buf;
+ 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;
+}
- /* Global names retain old encoding. */
- if (! old_id)
- return name;
+/* Temporarily set the namespace for the current declaration. */
- buf = (char *) alloca (8 + IDENTIFIER_LENGTH (old_id)
- + IDENTIFIER_LENGTH (name));
- sprintf (buf, "__ns_%s_%s", IDENTIFIER_POINTER (old_id),
- IDENTIFIER_POINTER (name));
- return get_identifier (buf);
+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);
}
-#endif
+
+void
+pop_decl_namespace ()
+{
+ decl_namespace_list = TREE_CHAIN (decl_namespace_list);
+}
+
+static void
+check_decl_namespace ()
+{
+ my_friendly_assert (decl_namespace_list == NULL_TREE, 980711);
+}
+
+/* [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));
+
+/* 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:
+ 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);
+ while (TREE_CODE (n) == TREE_LIST)
+ n = TREE_VALUE (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 (k, 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;
{
- tree binding;
- tree ns;
- if (TREE_CODE (namespace) == IDENTIFIER_NODE)
- ns = lookup_name (namespace, 1);
- else
- ns = namespace;
- if (TREE_CODE (ns) != NAMESPACE_DECL)
+ if (TREE_CODE (namespace) != NAMESPACE_DECL)
{
- cp_error ("`%D' is not a namespace", namespace);
+ /* The parser did not find it, so it's not there. */
+ cp_error ("unknown namespace `%D'", namespace);
return;
}
- binding = binding_for_name (alias, current_namespace);
- if (BINDING_VALUE (binding) && BINDING_VALUE (binding) != namespace)
+
+ 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)
+ return NULL_TREE;
+ if (TREE_CODE (decl) == SCOPE_REF)
+ {
+ *scope = TREE_OPERAND (decl, 0);
+ *name = TREE_OPERAND (decl, 1);
+ }
+ else if (TREE_CODE (decl) == IDENTIFIER_NODE
+ || TREE_CODE (decl) == TYPE_DECL)
{
- cp_error ("invalid namespace alias `%D'", alias);
- cp_error_at ("`%D' previously declared here", alias);
+ *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)))
{
- /* XXX the alias is not exactly identical to the name space,
- it must not be used in a using directive or namespace alias */
- BINDING_VALUE (binding) = ns;
+ 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))
+ {
+ /* Compare each new function with each old one.
+ If the old function was also used, there is no conflict. */
+ for (tmp1 = oldval; tmp1; tmp1 = OVL_NEXT (tmp1))
+ if (OVL_CURRENT (tmp) == OVL_CURRENT (tmp1))
+ break;
+ else if (OVL_USED (tmp1))
+ continue;
+ else if (duplicate_decls (OVL_CURRENT (tmp), OVL_CURRENT (tmp1)))
+ return;
+
+ /* Duplicate use, ignore */
+ 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;
{
-#if 1
- if (TREE_CODE (decl) == SCOPE_REF
- && TREE_OPERAND (decl, 0) == std_node)
+ tree scope, name, binding;
+ tree oldval, oldtype, newval, newtype;
+
+ decl = validate_nonmember_using_decl (decl, &scope, &name);
+ if (decl == NULL_TREE)
return;
- sorry ("using-declaration");
-#else
- if (decl == NULL_TREE || decl == error_mark_node)
+
+ 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;
- if (TREE_CODE (decl) == SCOPE_REF)
- decl = resolve_scope_to_name (NULL_TREE, decl);
+ oldval = lookup_name_current_level (name);
+ oldtype = lookup_type_current_level (name);
- /* Is this the right way to do an id list? */
- if (TREE_CODE (decl) != TREE_LIST)
- {
- pushdecl (decl);
- }
- else
- while (decl)
- {
- pushdecl (TREE_VALUE (decl));
- decl = TREE_CHAIN (decl);
- }
-#endif
+ do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
+
+ if (newval)
+ set_identifier_local_value (name, newval);
+ if (newtype)
+ set_identifier_type_value (name, newtype);
}
tree
@@ -3937,7 +4796,8 @@ do_class_using_decl (decl)
{
tree name, value;
- if (TREE_CODE (decl) != SCOPE_REF)
+ 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;
@@ -3948,23 +4808,44 @@ do_class_using_decl (decl)
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 A::B::C; */
+ /* using namespace A::B::C; */
if (TREE_CODE (namespace) == SCOPE_REF)
namespace = TREE_OPERAND (namespace, 1);
- /* direct usage */
- add_using_namespace (current_namespace, namespace, 0);
+ 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
@@ -3979,8 +4860,8 @@ check_default_args (x)
saw_def = 1;
else if (saw_def)
{
- cp_error ("default argument missing for parameter %P of `%#D'",
- i, x);
+ cp_error_at ("default argument missing for parameter %P of `%+#D'",
+ i, x);
break;
}
}
@@ -3994,13 +4875,23 @@ mark_used (decl)
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 (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (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);
}
@@ -4019,6 +4910,6 @@ handle_class_head (aggr, scope, id)
cp_error ("no file-scope type named `%D'", id);
id = xref_tag
- (aggr, make_anon_name (), NULL_TREE, 1);
+ (aggr, make_anon_name (), 1);
return TYPE_MAIN_DECL (id);
}