#include "output.h"
#include "except.h"
#include "toplev.h"
+#include "../hash.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
static struct binding_level *make_binding_level PROTO((void));
static int namespace_bindings_p PROTO((void));
static void declare_namespace_level PROTO((void));
-static void signal_catch PROTO((int));
+static void signal_catch PROTO((int)) ATTRIBUTE_NORETURN;
static void storedecls PROTO((tree));
static void storetags PROTO((tree));
static void require_complete_types_for_parms PROTO((tree));
struct binding_level *, int));
static void set_identifier_type_value_with_scope
PROTO((tree, tree, struct binding_level *));
-static void set_identifier_local_value_with_scope
- PROTO((tree, tree, struct binding_level *));
static void record_builtin_type PROTO((enum rid, char *, tree));
static void record_unknown_type PROTO((tree, char *));
static int member_function_or_else PROTO((tree, tree, char *));
int));
static void lang_print_error_function PROTO((char *));
static tree maybe_process_template_type_declaration PROTO((tree, int, struct binding_level*));
+static void check_for_uninitialized_const_var PROTO((tree));
+static unsigned long typename_hash PROTO((hash_table_key));
+static boolean typename_compare PROTO((hash_table_key, hash_table_key));
+static void push_binding PROTO((tree, tree, struct binding_level*));
+static void pop_binding PROTO((tree));
#if defined (DEBUG_CP_BINDING_LEVELS)
static void indent PROTO((void));
tree intHI_type_node;
tree intSI_type_node;
tree intDI_type_node;
+#if HOST_BITS_PER_WIDE_INT >= 64
tree intTI_type_node;
+#endif
tree unsigned_intQI_type_node;
tree unsigned_intHI_type_node;
tree unsigned_intSI_type_node;
tree unsigned_intDI_type_node;
+#if HOST_BITS_PER_WIDE_INT >= 64
tree unsigned_intTI_type_node;
+#endif
tree java_byte_type_node;
tree java_short_type_node;
/* Array type `vtable_entry_type[]' */
tree vtbl_type_node;
+tree vtbl_ptr_type_node;
/* namespace std */
tree std_node;
tree abort_fndecl;
+/* A FUNCTION_DECL for the default `::operator delete'. */
+
+tree global_delete_fndecl;
+
extern rtx cleanup_label, return_label;
/* If original DECL_RESULT of current function was a register,
tree current_function_return_value;
-/* Set to nonzero by `grokdeclarator' for a function
- whose return type is defaulted, if warnings for this are desired. */
-
-static int warn_about_return_type;
-
/* Nonzero means give `double' the same size as `float'. */
extern int flag_short_double;
{
/* A chain of _DECL nodes for all variables, constants, functions,
and typedef types. These are in the reverse of the order
- supplied. */
+ supplied. There may be OVERLOADs on this list, too, but they
+ are wrapped in TREE_LISTs; the TREE_VALUE is the OVERLOAD. */
tree names;
/* A list of structure, union and enum definitions, for looking up
VALUE the common ancestor with this binding_level's namespace. */
tree using_directives;
- /* For each level, a list of shadowed outer-level local definitions
- to be restored when this level is popped.
- Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and
- whose TREE_VALUE is its old definition (a kind of ..._DECL node). */
- tree shadowed;
-
- /* Same, for IDENTIFIER_CLASS_VALUE. */
+ /* If this binding level is the binding level for a class, then
+ class_shadowed is a TREE_LIST. The TREE_PURPOSE of each node
+ is the name of an entity bound in the class; the TREE_VALUE is
+ the IDENTIFIER_CLASS_VALUE before we entered the class. Thus,
+ when leaving class scope, we can restore the
+ IDENTIFIER_CLASS_VALUE by walking this list. */
tree class_shadowed;
- /* Same, for IDENTIFIER_TYPE_VALUE. */
+ /* Similar to class_shadowed, but for IDENTIFIER_TYPE_VALUE, and
+ is used for all binding levels. */
tree type_shadowed;
/* For each level (except not the global one),
/* List of VAR_DECLS saved from a previous for statement.
These would be dead in ANSI-conforming code, but might
- be referenced in ARM-era code. */
+ be referenced in ARM-era code. These are stored in a
+ TREE_LIST; the TREE_VALUE is the actual declaration. */
tree dead_vars_from_for;
/* 1 for the level that holds the parameters of a function.
expand_start_bindings (0);
}
+/* For a binding between a name and an entity at a block scope,
+ this is the `struct binding_level' for the block. */
+#define BINDING_LEVEL(NODE) \
+ ((struct binding_level*) ((struct tree_binding*)NODE)->scope)
+
+/* These are currently unused, but permanent, CPLUS_BINDING nodes.
+ They are kept here because they are allocated from the permanent
+ obstack and cannot be easily freed. */
+static tree free_binding_nodes;
+
+/* Make DECL the innermost binding for ID. The LEVEL is the binding
+ level at which this declaration is being bound. */
+
+static void
+push_binding (id, decl, level)
+ tree id;
+ tree decl;
+ struct binding_level* level;
+{
+ tree binding;
+
+ if (!free_binding_nodes)
+ {
+ /* There are no free nodes, so we must build one here. */
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ binding = make_node (CPLUS_BINDING);
+ pop_obstacks ();
+ }
+ else
+ {
+ /* There are nodes on the free list. Grab the first one. */
+ binding = free_binding_nodes;
+
+ /* And update the free list. */
+ free_binding_nodes = TREE_CHAIN (free_binding_nodes);
+ }
+
+ /* Now, fill in the binding information. */
+ BINDING_VALUE (binding) = decl;
+ BINDING_LEVEL (binding) = level;
+ LOCAL_BINDING_P (binding) = (level != class_binding_level);
+
+ /* And put it on the front of the ilst of bindings for ID. */
+ TREE_CHAIN (binding) = IDENTIFIER_BINDING (id);
+ IDENTIFIER_BINDING (id) = binding;
+}
+
+/* Bind DECL to ID in the current_binding_level. */
+
+void
+push_local_binding (id, decl)
+ tree id;
+ tree decl;
+{
+ tree d = decl;;
+
+ if (TREE_CODE (decl) == OVERLOAD)
+ /* We must put the OVERLOAD into a TREE_LIST since the
+ TREE_CHAIN of an OVERLOAD is already used. */
+ decl = build_tree_list (NULL_TREE, decl);
+
+ /* Create a binding, hanging off of ID. */
+ push_binding (id, d, current_binding_level);
+
+ /* And put DECL on the list of things declared by the current
+ binding level. */
+ TREE_CHAIN (decl) = current_binding_level->names;
+ current_binding_level->names = decl;
+}
+
+/* Bind DECL to ID in the class_binding_level. */
+
+void
+push_class_binding (id, decl)
+ tree id;
+ tree decl;
+{
+ push_binding (id, decl, class_binding_level);
+}
+
+/* Remove the innermost binding for ID; it has gone out of scope. */
+
+static void
+pop_binding (id)
+ tree id;
+{
+ tree binding;
+
+ if (id == NULL_TREE)
+ /* It's easiest to write the loops that call this function without
+ checking whether or not the entities involved have names. We
+ get here for such an entity. */
+ return;
+
+ my_friendly_assert (IDENTIFIER_BINDING (id) != NULL_TREE, 0);
+
+ /* Unhook the innermost binding from the list of bindings. */
+ binding = IDENTIFIER_BINDING (id);
+ IDENTIFIER_BINDING (id) = TREE_CHAIN (binding);
+
+ /* And place this list node on the free list. */
+ TREE_CHAIN (binding) = free_binding_nodes;
+ free_binding_nodes = binding;
+}
+
/* Exit a binding level.
Pop the level off, and restore the state of the identifier-decl mappings
that were in effect when this level was entered.
and create a "block" (a BLOCK node) for the level
to record its declarations and subblocks for symbol table output.
- If KEEP == 2, this level's subblocks go to the front,
- not the back of the current binding level. This happens,
- for instance, when code for constructors and destructors
- need to generate code at the end of a function which must
- be moved up to the front of the function.
-
If FUNCTIONBODY is nonzero, this level is the body of a function,
so create a block as if KEEP were set and also clear out all
label names.
tree block = NULL_TREE;
tree decl;
int block_previously_created;
+ int leaving_for_scope;
+
+ if (current_binding_level->parm_flag == 2
+ || current_binding_level->class_shadowed)
+ /* We should not be using poplevel to pop a class binding level.
+ Use poplevel_class instead. */
+ my_friendly_abort (0);
+
+ /* We used to use KEEP == 2 to indicate that the new block should go
+ at the beginning of the list of blocks at this binding level,
+ rather than the end. This hack is no longer used. */
+ my_friendly_assert (keep == 0 || keep == 1, 0);
GNU_xref_end_scope ((HOST_WIDE_INT) current_binding_level,
(HOST_WIDE_INT) current_binding_level->level_chain,
if (decls || tags || subblocks)
{
if (BLOCK_VARS (block) || BLOCK_TYPE_TAGS (block))
- {
- warning ("internal compiler error: debugging info corrupted");
- }
+ warning ("internal compiler error: debugging info corrupted");
+
BLOCK_VARS (block) = decls;
BLOCK_TYPE_TAGS (block) = tags;
BLOCK_VARS (block) = decls;
BLOCK_TYPE_TAGS (block) = tags;
BLOCK_SUBBLOCKS (block) = subblocks;
- /* Otherwise, for a new block, install a new BLOCK_END_NOTE value. */
+ /* Otherwise, for a new block, install a new BLOCK_END_NOTE
+ value. */
remember_end_note (block);
}
}
for (link = subblocks; link; link = TREE_CHAIN (link))
BLOCK_SUPERCONTEXT (link) = block;
- /* Clear out the meanings of the local variables of this level. */
-
- if (current_binding_level->is_for_scope && flag_new_for_scope == 1)
- {
- struct binding_level *outer = current_binding_level->level_chain;
- for (link = decls; link; link = TREE_CHAIN (link))
- {
- if (TREE_CODE (link) == VAR_DECL)
- DECL_DEAD_FOR_LOCAL (link) = 1;
+ /* We still support the old for-scope rules, whereby the variables
+ in a for-init statement were in scope after the for-statement
+ ended. We only use the new rules in flag_new_for_scope is
+ nonzero. */
+ leaving_for_scope
+ = current_binding_level->is_for_scope && flag_new_for_scope == 1;
+
+ /* Remove declarations for all the DECLs in this level. */
+ for (link = decls; link; link = TREE_CHAIN (link))
+ {
+ if (leaving_for_scope && TREE_CODE (link) == VAR_DECL)
+ {
+ tree outer_binding
+ = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (link)));
+ tree ns_binding;
+
+ if (!outer_binding)
+ ns_binding = IDENTIFIER_NAMESPACE_VALUE (DECL_NAME (link));
+
+ if (outer_binding
+ && (BINDING_LEVEL (outer_binding)
+ == current_binding_level->level_chain))
+ /* We have something like:
+
+ int i;
+ for (int i; ;);
+
+ and we are leaving the `for' scope. There's no reason to
+ keep the binding of the inner `i' in this case. */
+ pop_binding (DECL_NAME (link));
+ else if ((outer_binding
+ && (TREE_CODE (BINDING_VALUE (outer_binding))
+ == TYPE_DECL))
+ || (ns_binding
+ && TREE_CODE (ns_binding) == TYPE_DECL))
+ /* Here, we have something like:
+
+ typedef int I;
+
+ void f () {
+ for (int I; ;);
+ }
+
+ We must pop the for-scope binding so we know what's a
+ type and what isn't. */
+ pop_binding (DECL_NAME (link));
else
- IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE;
- }
-
- /* Save declarations made in a 'for' statement so we can support pre-ANSI
- 'for' scoping semantics. */
-
- for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
- {
- tree id = TREE_PURPOSE (link);
- tree decl = IDENTIFIER_LOCAL_VALUE (id);
-
- if (decl && DECL_DEAD_FOR_LOCAL (decl))
{
- /* In this case keep the dead for-decl visible,
- but remember what (if anything) it shadowed. */
- DECL_SHADOWED_FOR_VAR (decl) = TREE_VALUE (link);
- TREE_CHAIN (decl) = outer->dead_vars_from_for;
- outer->dead_vars_from_for = decl;
+ /* Mark this VAR_DECL as dead so that we can tell we left it
+ there only for backward compatibility. */
+ DECL_DEAD_FOR_LOCAL (link) = 1;
+
+ /* Keep track of what should of have happenned when we
+ popped the binding. */
+ if (outer_binding && BINDING_VALUE (outer_binding))
+ DECL_SHADOWED_FOR_VAR (link)
+ = BINDING_VALUE (outer_binding);
+
+ /* Add it to the list of dead variables in the next
+ outermost binding to that we can remove these when we
+ leave that binding. */
+ current_binding_level->level_chain->dead_vars_from_for
+ = tree_cons (NULL_TREE, link,
+ current_binding_level->level_chain->
+ dead_vars_from_for);
+
+ /* Although we don't pop the CPLUS_BINDING, we do clear
+ its BINDING_LEVEL since the level is going away now. */
+ BINDING_LEVEL (IDENTIFIER_BINDING (DECL_NAME (link)))
+ = 0;
}
- else
- IDENTIFIER_LOCAL_VALUE (id) = TREE_VALUE (link);
}
- }
- else /* Not special for scope. */
- {
- for (link = decls; link; link = TREE_CHAIN (link))
+ else
{
- if (DECL_NAME (link) != NULL_TREE)
- {
- /* If the ident. was used or addressed via a local extern decl,
- don't forget that fact. */
- if (DECL_EXTERNAL (link))
- {
- if (TREE_USED (link))
- TREE_USED (DECL_ASSEMBLER_NAME (link)) = 1;
- if (TREE_ADDRESSABLE (link))
- TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1;
- }
- IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE;
- }
+ /* Remove the binding. */
+ if (TREE_CODE_CLASS (TREE_CODE (link)) == 'd')
+ pop_binding (DECL_NAME (link));
+ else if (TREE_CODE (link) == TREE_LIST)
+ pop_binding (DECL_NAME (OVL_FUNCTION (TREE_VALUE (link))));
+ else
+ my_friendly_abort (0);
}
+ }
- /* Restore all name-meanings of the outer levels
- that were shadowed by this level. */
-
- for (link = current_binding_level->shadowed;
- link; link = TREE_CHAIN (link))
- IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
-
- /* We first restore the regular decls and *then* the dead_vars_from_for
- to handle this case:
-
- int i; // i#1
- {
- for (int i; ; ) { ...} // i#2
- int i; // i#3
- } // we are here
-
- In this case, we want remove the binding for i#3, restoring
- that of i#2. Then we want to remove the binding for i#2,
- and restore that of i#1. */
+ /* Remove declarations for any `for' variables from inner scopes
+ that we kept around. */
+ for (link = current_binding_level->dead_vars_from_for;
+ link; link = TREE_CHAIN (link))
+ pop_binding (DECL_NAME (TREE_VALUE (link)));
- link = current_binding_level->dead_vars_from_for;
- for (; link != NULL_TREE; link = TREE_CHAIN (link))
- {
- tree id = DECL_NAME (link);
- if (IDENTIFIER_LOCAL_VALUE (id) == link)
- IDENTIFIER_LOCAL_VALUE (id) = DECL_SHADOWED_FOR_VAR (link);
- }
+ /* Restore the IDENTIFIER_TYPE_VALUEs. */
+ for (link = current_binding_level->type_shadowed;
+ link; link = TREE_CHAIN (link))
+ SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link));
+
+ /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs
+ list if a `using' declaration put them there. The debugging
+ back-ends won't understand OVERLOAD, so we remove them here.
+ Because the BLOCK_VARS are (temporarily) shared with
+ CURRENT_BINDING_LEVEL->NAMES we must do this fixup after we have
+ popped all the bindings. */
+ if (block)
+ {
+ tree* d;
- for (link = current_binding_level->class_shadowed;
- link; link = TREE_CHAIN (link))
- IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
- for (link = current_binding_level->type_shadowed;
- link; link = TREE_CHAIN (link))
- SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link));
+ for (d = &BLOCK_VARS (block);
+ *d;
+ d = *d ? &TREE_CHAIN (*d) : d)
+ if (TREE_CODE (*d) == TREE_LIST)
+ *d = TREE_CHAIN (*d);
}
/* If the level being exited is the top level of a function,
must be carried forward so they will later become subblocks
of something else. */
else if (subblocks)
- {
- if (keep == 2)
- current_binding_level->blocks
- = chainon (subblocks, current_binding_level->blocks);
- else
- current_binding_level->blocks
- = chainon (current_binding_level->blocks, subblocks);
- }
+ current_binding_level->blocks
+ = chainon (current_binding_level->blocks, subblocks);
/* Take care of compiler's internal binding structures. */
if (tmp == 2)
free_binding_level = free_binding_level->level_chain;
}
else
- {
- newlevel = make_binding_level ();
- }
+ newlevel = make_binding_level ();
#if defined(DEBUG_CP_BINDING_LEVELS)
is_class_level = 1;
my_friendly_assert (level != 0, 354);
decl_stack = pop_stack_level (decl_stack);
- for (shadowed = level->shadowed; shadowed; shadowed = TREE_CHAIN (shadowed))
- IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (shadowed)) = TREE_VALUE (shadowed);
/* If we're leaving a toplevel class, don't bother to do the setting
of IDENTIFIER_CLASS_VALUE to NULL_TREE, since first of all this slot
shouldn't even be used when current_class_type isn't set, and second,
shadowed = TREE_CHAIN (shadowed))
SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (shadowed), TREE_VALUE (shadowed));
+ /* Remove the bindings for all of the class-level declarations. */
+ for (shadowed = level->class_shadowed;
+ shadowed;
+ shadowed = TREE_CHAIN (shadowed))
+ pop_binding (TREE_PURPOSE (shadowed));
+
GNU_xref_end_scope ((HOST_WIDE_INT) class_binding_level,
(HOST_WIDE_INT) class_binding_level->level_chain,
class_binding_level->parm_flag,
if (i)
fprintf (stderr, "\n");
}
- if (lvl->shadowed)
- {
- fprintf (stderr, " shadowed:");
- for (t = lvl->shadowed; t; t = TREE_CHAIN (t))
- {
- fprintf (stderr, " %s ", IDENTIFIER_POINTER (TREE_PURPOSE (t)));
- }
- fprintf (stderr, "\n");
- }
if (lvl->class_shadowed)
{
fprintf (stderr, " class-shadowed:");
push_namespace (name)
tree name;
{
- tree d;
+ tree d = NULL_TREE;
int need_new = 1;
int implicit_use = 0;
int global = 0;
tree old_bindings;
tree old_namespace;
struct saved_scope *prev;
- tree class_name, class_type, function_decl;
+ tree class_name, class_type;
+ tree access_specifier;
+ tree function_decl;
struct binding_level *class_bindings;
tree *lang_base, *lang_stack, lang_name;
int lang_stacksize;
else
id = DECL_NAME (t);
- if (!id
- || (!IDENTIFIER_LOCAL_VALUE (id)
- && !IDENTIFIER_CLASS_VALUE (id)))
+ if (!id
+ /* Note that we may have an IDENTIFIER_CLASS_VALUE even when
+ we have no IDENTIFIER_BINDING if we have left the class
+ scope, but cached the class-level declarations. */
+ || !(IDENTIFIER_BINDING (id) || IDENTIFIER_CLASS_VALUE (id)))
continue;
for (t1 = old_bindings; t1; t1 = TREE_CHAIN (t1))
my_friendly_assert (TREE_CODE (id) == IDENTIFIER_NODE, 135);
TREE_VEC_ELT (binding, 0) = id;
TREE_VEC_ELT (binding, 1) = REAL_IDENTIFIER_TYPE_VALUE (id);
- TREE_VEC_ELT (binding, 2) = IDENTIFIER_LOCAL_VALUE (id);
+ TREE_VEC_ELT (binding, 2) = IDENTIFIER_BINDING (id);
TREE_VEC_ELT (binding, 3) = IDENTIFIER_CLASS_VALUE (id);
- IDENTIFIER_LOCAL_VALUE (id) = NULL_TREE;
+ IDENTIFIER_BINDING (id) = NULL_TREE;
IDENTIFIER_CLASS_VALUE (id) = NULL_TREE;
}
TREE_CHAIN (binding) = old_bindings;
s->old_namespace = current_namespace;
s->class_name = current_class_name;
s->class_type = current_class_type;
+ s->access_specifier = current_access_specifier;
s->function_decl = current_function_decl;
s->class_bindings = class_binding_level;
s->lang_stack = current_lang_stack;
if (id)
{
SET_IDENTIFIER_TYPE_VALUE (id, TREE_VEC_ELT (t, 1));
- IDENTIFIER_LOCAL_VALUE (id) = TREE_VEC_ELT (t, 2);
+ IDENTIFIER_BINDING (id) = TREE_VEC_ELT (t, 2);
IDENTIFIER_CLASS_VALUE (id) = TREE_VEC_ELT (t, 3);
}
t = TREE_CHAIN (t);
current_namespace = s->old_namespace;
current_class_name = s->class_name;
current_class_type = s->class_type;
+ current_access_specifier = s->access_specifier;
current_function_decl = s->function_decl;
class_binding_level = s->class_bindings;
free (current_lang_base);
set_identifier_type_value_with_scope (id, type, inner_binding_level);
}
-static void
-set_identifier_local_value_with_scope (id, val, b)
- tree id, val;
- struct binding_level *b;
-{
- tree oldlocal;
- my_friendly_assert (! b->namespace_p, 980716);
-
- oldlocal = IDENTIFIER_LOCAL_VALUE (id);
- b->shadowed = tree_cons (id, oldlocal, b->shadowed);
- IDENTIFIER_LOCAL_VALUE (id) = val;
-}
-
-void
-set_identifier_local_value (id, val)
- tree id, val;
-{
- set_identifier_local_value_with_scope (id, val, current_binding_level);
-}
-
/* Return the type associated with id. */
tree
{
pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
b->level_chain);
+ finish_member_declaration (CLASSTYPE_TI_TEMPLATE (type));
/* Put this tag on the list of tags for the class, since
that won't happen below because B is not the class
binding level, but is instead the pseudo-global level. */
globalize, b);
if (b->parm_flag == 2)
- d = pushdecl_class_level (d);
+ {
+ pushdecl_class_level (d);
+ if (newdecl && !PROCESSING_REAL_TEMPLATE_DECL_P ())
+ /* Put this TYPE_DECL on the TYPE_FIELDS list for the
+ class. But if it's a member template class, we
+ want the TEMPLATE_DECL, not the TYPE_DECL, so this
+ is done later. */
+ finish_member_declaration (d);
+ }
else
d = pushdecl_with_scope (d, b);
{
int types_match;
- if (TREE_CODE (newdecl) == FUNCTION_DECL
- && TREE_CODE (olddecl) == FUNCTION_DECL)
+ if (TREE_CODE (newdecl) != TREE_CODE (olddecl))
+ /* If the two DECLs are not even the same kind of thing, we're not
+ interested in their types. */
+ return 0;
+
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
tree f1 = TREE_TYPE (newdecl);
tree f2 = TREE_TYPE (olddecl);
return 0;
}
- if (comptypes (TREE_TYPE (f1), TREE_TYPE (f2), 1))
+ if (same_type_p (TREE_TYPE (f1), TREE_TYPE (f2)))
{
if (! strict_prototypes_lang_c && DECL_LANGUAGE (olddecl) == lang_c
&& p2 == NULL_TREE)
TREE_TYPE (newdecl) = TREE_TYPE (olddecl);
}
else
- types_match = compparms (p1, p2, 3);
+ types_match = compparms (p1, p2);
}
else
types_match = 0;
}
- else if (TREE_CODE (newdecl) == TEMPLATE_DECL
- && TREE_CODE (olddecl) == TEMPLATE_DECL)
+ else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
DECL_TEMPLATE_PARMS (olddecl)))
types_match = TREE_TYPE (newdecl) == NULL_TREE;
else if (TREE_TYPE (newdecl) == NULL_TREE)
types_match = 0;
- /* Qualifiers must match, and they may be present on either, the type
- or the decl. */
- else if ((TREE_READONLY (newdecl)
- || TYPE_READONLY (TREE_TYPE (newdecl)))
- == (TREE_READONLY (olddecl)
- || TYPE_READONLY (TREE_TYPE (olddecl)))
- && (TREE_THIS_VOLATILE (newdecl)
- || TYPE_VOLATILE (TREE_TYPE (newdecl)))
- == (TREE_THIS_VOLATILE (olddecl)
- || TYPE_VOLATILE (TREE_TYPE (olddecl))))
- types_match = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (newdecl)),
- TYPE_MAIN_VARIANT (TREE_TYPE (olddecl)), 1);
else
- types_match = 0;
+ types_match = comptypes (TREE_TYPE (newdecl),
+ TREE_TYPE (olddecl),
+ COMPARE_REDECLARATION);
}
return types_match;
else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL
&& TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL
&& compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))),
- TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))), 3)
+ TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))))
&& comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
DECL_TEMPLATE_PARMS (olddecl)))
{
cp_error_at ("previous declaration `%#D' here", olddecl);
}
else if (compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
- TYPE_ARG_TYPES (TREE_TYPE (olddecl)), 3))
+ TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
{
cp_error ("new declaration `%#D'", newdecl);
cp_error_at ("ambiguates old declaration `%#D'", olddecl);
olddecl);
}
}
- /* These bits are logically part of the type for non-functions. */
- else if (TREE_READONLY (newdecl) != TREE_READONLY (olddecl)
- || TREE_THIS_VOLATILE (newdecl) != TREE_THIS_VOLATILE (olddecl))
- {
- cp_pedwarn ("type qualifiers for `%#D'", newdecl);
- cp_pedwarn_at ("conflict with previous decl `%#D'", olddecl);
- }
}
/* If new decl is `static' and an `extern' was seen previously,
DECL_TEMPLATE_RESULT (olddecl)))
cp_error ("invalid redeclaration of %D", newdecl);
TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl));
- DECL_TEMPLATE_PARMS (olddecl) = DECL_TEMPLATE_PARMS (newdecl);
- if (DECL_TEMPLATE_INFO (newdecl))
- DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl);
DECL_TEMPLATE_SPECIALIZATIONS (olddecl)
= chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl),
DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
- if (DECL_TEMPLATE_INFO (newdecl) == NULL_TREE)
- {
- DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
- DECL_USE_TEMPLATE (newdecl) = DECL_USE_TEMPLATE (olddecl);
- }
+ DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
olddecl_friend = DECL_FRIEND_P (olddecl);
}
{
register tree t;
register tree name = DECL_ASSEMBLER_NAME (x);
- register struct binding_level *b = current_binding_level;
+ int need_new_binding = 1;
if (current_function_decl && x != current_function_decl
/* A local declaration for a function doesn't constitute nesting. */
&& (TREE_CODE (x) != FUNCTION_DECL || DECL_INITIAL (x))
/* Don't change DECL_CONTEXT of virtual methods. */
&& (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x))
- && ! DECL_CONTEXT (x))
+ && !DECL_CONTEXT (x))
DECL_CONTEXT (x) = current_function_decl;
if (!DECL_CONTEXT (x))
DECL_CONTEXT (x) = FROB_CONTEXT (current_namespace);
}
}
+ check_template_shadow (x);
+
if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x))
{
t = push_overloaded_decl (x, 1);
if (t != x || DECL_LANGUAGE (x) == lang_c)
return t;
+ if (!namespace_bindings_p ())
+ /* We do not need to create a binding for this name;
+ push_overloaded_decl will have already done so if
+ necessary. */
+ need_new_binding = 0;
}
else if (DECL_FUNCTION_TEMPLATE_P (x) && DECL_NAMESPACE_SCOPE_P (x))
return push_overloaded_decl (x, 0);
if (TYPE_NAME (type) == 0)
TYPE_NAME (type) = x;
}
- else if (type != error_mark_node && TYPE_NAME (type) != x)
+ else if (type != error_mark_node && TYPE_NAME (type) != x
+ /* We don't want to copy the type when all we're
+ doing is making a TYPE_DECL for the purposes of
+ inlining. */
+ && (!TYPE_NAME (type)
+ || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x)))
{
push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
if (type != error_mark_node
&& TYPE_NAME (type)
&& TYPE_IDENTIFIER (type))
- set_identifier_type_value_with_scope (DECL_NAME (x), type, b);
+ set_identifier_type_value_with_scope (DECL_NAME (x), type,
+ current_binding_level);
+
+ if (TREE_CODE (x) == TYPE_DECL
+ && DECL_ARTIFICIAL (x)
+ && t != NULL_TREE)
+ /* We don't want an artificial TYPE_DECL is we already
+ have another DECL with the same name. */
+ need_new_binding = 0;
}
/* Multiple external decls of the same identifier ought to match.
if (decl
/* If different sort of thing, we already gave an error. */
&& TREE_CODE (decl) == TREE_CODE (x)
- && ! comptypes (TREE_TYPE (x), TREE_TYPE (decl), 1))
+ && !same_type_p (TREE_TYPE (x), TREE_TYPE (decl)))
{
cp_pedwarn ("type mismatch with previous external decl", x);
cp_pedwarn_at ("previous external decl of `%#D'", decl);
if (IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE && TREE_PUBLIC (x))
TREE_PUBLIC (name) = 1;
- /* Don't install an artificial TYPE_DECL if we already have
- another _DECL with that name. */
- if (TREE_CODE (x) != TYPE_DECL
- || t == NULL_TREE
- || ! DECL_ARTIFICIAL (x))
+ if (need_new_binding)
{
if (TREE_CODE (x) == FUNCTION_DECL)
my_friendly_assert
else
{
/* Here to install a non-global value. */
- tree oldlocal = IDENTIFIER_LOCAL_VALUE (name);
+ tree oldlocal = IDENTIFIER_VALUE (name);
tree oldglobal = IDENTIFIER_NAMESPACE_VALUE (name);
- /* Don't install an artificial TYPE_DECL if we already have
- another _DECL with that name. */
- if (TREE_CODE (x) != TYPE_DECL
- || t == NULL_TREE
- || ! DECL_ARTIFICIAL (x))
- set_identifier_local_value_with_scope (name, x, b);
+ if (need_new_binding)
+ {
+ push_local_binding (name, x);
+ /* Because push_local_binding will hook X on to the
+ current_binding_level's name list, we don't want to
+ do that again below. */
+ need_new_binding = 0;
+ }
/* If this is a TYPE_DECL, push it into the type value slot. */
if (TREE_CODE (x) == TYPE_DECL)
- set_identifier_type_value_with_scope (name, TREE_TYPE (x), b);
+ set_identifier_type_value_with_scope (name, TREE_TYPE (x),
+ current_binding_level);
/* Clear out any TYPE_DECL shadowed by a namespace so that
we won't think this is a type. The C struct hack doesn't
go through namespaces. */
if (TREE_CODE (x) == NAMESPACE_DECL)
- set_identifier_type_value_with_scope (name, NULL_TREE, b);
+ set_identifier_type_value_with_scope (name, NULL_TREE,
+ current_binding_level);
/* If this is an extern function declaration, see if we
have a global definition or declaration for the function. */
&& oldglobal == NULL_TREE
&& DECL_EXTERNAL (x)
&& TREE_PUBLIC (x))
- {
- TREE_PUBLIC (name) = 1;
- }
+ TREE_PUBLIC (name) = 1;
if (DECL_FROM_INLINE (x))
/* Inline decls shadow nothing. */;
if (b->parm_flag == 1)
cp_error ("declaration of `%#D' shadows a parameter", name);
}
- else if (warn_shadow && oldlocal != NULL_TREE && b->is_for_scope
+ else if (warn_shadow && oldlocal != NULL_TREE
+ && current_binding_level->is_for_scope
&& !DECL_DEAD_FOR_LOCAL (oldlocal))
{
warning ("variable `%s' shadows local",
if (warnstring)
warning (warnstring, IDENTIFIER_POINTER (name));
}
- /* Check to see if decl redeclares a template parameter. */
- if (oldlocal && (current_class_type || current_function_decl)
- && current_template_parms)
- {
- if (decl_template_parm_p (oldlocal))
- {
- cp_error ("re-using name of template parameter `%T' in this scope", name);
- cp_error_at (" previously declared here `%#D'", oldlocal);
- }
- }
}
if (TREE_CODE (x) == FUNCTION_DECL)
/* RTTI TD entries are created while defining the type_info. */
|| (TYPE_LANG_SPECIFIC (TREE_TYPE (x))
&& TYPE_BEING_DEFINED (TREE_TYPE (x)))))
- b->incomplete = tree_cons (NULL_TREE, x, b->incomplete);
+ current_binding_level->incomplete
+ = tree_cons (NULL_TREE, x, current_binding_level->incomplete);
}
- /* Put decls on list in reverse order.
- We will reverse them later if necessary. */
- TREE_CHAIN (x) = b->names;
- b->names = x;
- if (! (b != global_binding_level || TREE_PERMANENT (x)))
- my_friendly_abort (124);
+ if (need_new_binding)
+ {
+ /* Put decls on list in reverse order.
+ We will reverse them later if necessary. */
+ TREE_CHAIN (x) = current_binding_level->names;
+ current_binding_level->names = x;
+ if (! (current_binding_level != global_binding_level
+ || TREE_PERMANENT (x)))
+ my_friendly_abort (124);
+ }
return x;
}
/* Make the declaration of X appear in CLASS scope. */
-tree
+void
pushdecl_class_level (x)
tree x;
{
Types, enums, and static vars are checked here; other
members are checked in finish_struct. */
tree icv = IDENTIFIER_CLASS_VALUE (name);
- tree ilv = IDENTIFIER_LOCAL_VALUE (name);
+ /* This should match check_member_decl_is_same_in_complete_scope. */
if (icv && icv != x
&& flag_optional_diags
/* Don't complain about inherited names. */
icv);
}
- /* Check to see if decl redeclares a template parameter. */
- if (ilv && ! decls_match (ilv, x)
- && (current_class_type || current_function_decl)
- && current_template_parms)
- {
- if (decl_template_parm_p (ilv))
- {
- cp_error ("re-using name of template parameter `%T' in this scope", name);
- cp_error_at (" previously declared here `%#D'", ilv);
- }
- }
+ check_template_shadow (x);
}
push_class_level_binding (name, x);
if (TREE_CODE (x) == TYPE_DECL)
- {
- set_identifier_type_value (name, TREE_TYPE (x));
- }
+ set_identifier_type_value (name, TREE_TYPE (x));
}
- return x;
}
#if 0
&& purpose_member (name, class_binding_level->class_shadowed))
return;
+ /* If this declaration shadows a declaration from an enclosing
+ class, then we will need to restore IDENTIFIER_CLASS_VALUE when
+ we leave this class. Record the shadowed declaration here. */
maybe_push_cache_obstack ();
class_binding_level->class_shadowed
= tree_cons (name, IDENTIFIER_CLASS_VALUE (name),
class_binding_level->class_shadowed);
pop_obstacks ();
+
+ /* Put the binding on the stack of bindings for the identifier, and
+ update IDENTIFIER_CLASS_VALUE. */
+ push_class_binding (name, x);
IDENTIFIER_CLASS_VALUE (name) = x;
+
obstack_ptr_grow (&decl_obstack, x);
}
return ud;
}
-/* DECL is a FUNCTION_DECL which may have other definitions already in
- place. We get around this by making the value of the identifier point
- to a list of all the things that want to be referenced by that name. It
- is then up to the users of that name to decide what to do with that
- list.
+/* DECL is a FUNCTION_DECL for a non-member function, which may have
+ other definitions already in place. We get around this by making
+ the value of the identifier point to a list of all the things that
+ want to be referenced by that name. It is then up to the users of
+ that name to decide what to do with that list.
DECL may also be a TEMPLATE_DECL, with a FUNCTION_DECL in its DECL_RESULT
slot. It is dealt with the same way.
tree decl;
int forgettable;
{
- tree orig_name = DECL_NAME (decl);
+ tree name = DECL_NAME (decl);
tree old;
+ tree new_binding;
int doing_global = (namespace_bindings_p () || ! forgettable);
if (doing_global)
{
- old = namespace_binding (orig_name, DECL_CONTEXT (decl));
+ old = namespace_binding (name, DECL_CONTEXT (decl));
if (old && TREE_CODE (old) == FUNCTION_DECL
&& DECL_ARTIFICIAL (old)
&& (DECL_BUILT_IN (old) || DECL_BUILT_IN_NONANSI (old)))
}
}
else
- {
- old = IDENTIFIER_LOCAL_VALUE (orig_name);
-
- if (! purpose_member (orig_name, current_binding_level->shadowed))
- {
- current_binding_level->shadowed
- = tree_cons (orig_name, old, current_binding_level->shadowed);
- old = NULL_TREE;
- }
- }
+ old = lookup_name_current_level (name);
if (old)
{
if (old || TREE_CODE (decl) == TEMPLATE_DECL)
{
if (old && TREE_CODE (old) != OVERLOAD)
- old = ovl_cons (old, NULL_TREE);
- old = ovl_cons (decl, old);
+ new_binding = ovl_cons (decl, ovl_cons (old, NULL_TREE));
+ else
+ new_binding = ovl_cons (decl, old);
}
else
- /* orig_name is not ambiguous. */
- old = decl;
+ /* NAME is not ambiguous. */
+ new_binding = decl;
if (doing_global)
- set_namespace_binding (orig_name, current_namespace, old);
+ set_namespace_binding (name, current_namespace, new_binding);
else
- IDENTIFIER_LOCAL_VALUE (orig_name) = old;
+ {
+ /* We only create an OVERLOAD if there was a previous binding at
+ this level. In that case, we need to remove the old binding
+ and replace it with the new binding. We must also run
+ through the NAMES on the current binding level to update the
+ chain. */
+ if (TREE_CODE (new_binding) == OVERLOAD)
+ {
+ tree *d;
+
+ for (d = &BINDING_LEVEL (IDENTIFIER_BINDING (name))->names;
+ *d;
+ d = &TREE_CHAIN (*d))
+ if (*d == old
+ || (TREE_CODE (*d) == TREE_LIST
+ && TREE_VALUE (*d) == old))
+ {
+ *d = TREE_CHAIN (*d);
+ break;
+ }
+
+ pop_binding (name);
+ }
+
+ /* Install the new binding. */
+ push_local_binding (name, new_binding);
+ }
return decl;
}
/* Because C++ can put things into name space for free,
constructs like "typedef struct foo { ... } foo"
would look like an erroneous redeclaration. */
- if (comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 0))
+ if (same_type_p (TREE_TYPE (newdecl), TREE_TYPE (olddecl)))
return 0;
else
return "redefinition of `%#D'";
and they should be cleaned up
by the time we get to the label. */
&& ! DECL_ARTIFICIAL (new_decls)
- && ((DECL_INITIAL (new_decls) != NULL_TREE
- && DECL_INITIAL (new_decls) != error_mark_node)
- || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls))))
+ && !(DECL_INITIAL (new_decls) == NULL_TREE
+ && pod_type_p (TREE_TYPE (new_decls))))
{
if (! identified)
{
" from here");
identified = 1;
}
- cp_error_at (" crosses initialization of `%#D'",
- new_decls);
+ if (DECL_INITIAL (new_decls)
+ || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls)))
+ cp_error_at (" crosses initialization of `%#D'",
+ new_decls);
+ else
+ cp_error_at (" enters scope of non-POD `%#D'",
+ new_decls);
}
new_decls = TREE_CHAIN (new_decls);
}
/* XXX Note decl is never actually used. (bpk) */
void
-define_case_label (decl)
- tree decl;
+define_case_label ()
{
tree cleanup = last_cleanup_this_contour ();
struct binding_level *b = current_binding_level;
tree val;
my_friendly_assert (TREE_CODE (namespace) == NAMESPACE_DECL, 370);
+
+ /* This happens for A::B<int> when B is a namespace. */
+ if (TREE_CODE (name) == NAMESPACE_DECL)
+ return name;
+
my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 373);
val = binding_init (&_b);
return error_mark_node;
}
+/* Hash a TYPENAME_TYPE. K is really of type `tree'. */
+
+static unsigned long
+typename_hash (k)
+ hash_table_key k;
+{
+ unsigned long hash;
+ tree t;
+
+ t = (tree) k;
+ hash = (((unsigned long) TYPE_CONTEXT (t))
+ ^ ((unsigned long) DECL_NAME (TYPE_NAME (t))));
+
+ return hash;
+}
+
+/* Compare two TYPENAME_TYPEs. K1 and K2 are really of type `tree'. */
+
+static boolean
+typename_compare (k1, k2)
+ hash_table_key k1;
+ hash_table_key k2;
+{
+ tree t1;
+ tree t2;
+ tree d1;
+ tree d2;
+
+ t1 = (tree) k1;
+ t2 = (tree) k2;
+ d1 = TYPE_NAME (t1);
+ d2 = TYPE_NAME (t2);
+
+ return (DECL_NAME (d1) == DECL_NAME (d2)
+ && same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2))
+ && ((TREE_TYPE (t1) != NULL_TREE)
+ == (TREE_TYPE (t2) != NULL_TREE))
+ && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+ && TYPENAME_TYPE_FULLNAME (t1) == TYPENAME_TYPE_FULLNAME (t2));
+}
+
+/* Build a TYPENAME_TYPE. If the type is `typename T::t', CONTEXT is
+ the type of `T', NAME is the IDENTIFIER_NODE for `t'. If BASE_TYPE
+ is non-NULL, this type is being created by the implicit typename
+ extension, and BASE_TYPE is a type named `t' in some base class of
+ `T' which depends on template parameters.
+
+ Returns the new TYPENAME_TYPE. */
+
+tree
+build_typename_type (context, name, fullname, base_type)
+ tree context;
+ tree name;
+ tree fullname;
+ tree base_type;
+{
+ tree t;
+ tree d;
+ struct hash_entry* e;
+
+ static struct hash_table ht;
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ if (!ht.table
+ && !hash_table_init (&ht, &hash_newfunc, &typename_hash,
+ &typename_compare))
+ fatal ("virtual memory exhausted");
+
+ /* Build the TYPENAME_TYPE. */
+ t = make_lang_type (TYPENAME_TYPE);
+ TYPE_CONTEXT (t) = FROB_CONTEXT (context);
+ TYPENAME_TYPE_FULLNAME (t) = fullname;
+ TREE_TYPE (t) = base_type;
+
+ /* Build the corresponding TYPE_DECL. */
+ d = build_decl (TYPE_DECL, name, t);
+ TYPE_NAME (TREE_TYPE (d)) = d;
+ TYPE_STUB_DECL (TREE_TYPE (d)) = d;
+ DECL_CONTEXT (d) = FROB_CONTEXT (context);
+ DECL_ARTIFICIAL (d) = 1;
+
+ /* See if we already have this type. */
+ e = hash_lookup (&ht, t, /*create=*/false, /*copy=*/0);
+ if (e)
+ {
+ /* This will free not only TREE_TYPE, but the lang-specific data
+ and the TYPE_DECL as well. */
+ obstack_free (&permanent_obstack, t);
+ t = (tree) e->key;
+ }
+ else
+ /* Insert the type into the table. */
+ hash_lookup (&ht, t, /*create=*/true, /*copy=*/0);
+
+ pop_obstacks ();
+
+ return t;
+}
+
tree
make_typename_type (context, name)
tree context, name;
{
- tree t, d;
+ tree t;
tree fullname;
if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
if (TREE_CODE (name) != IDENTIFIER_NODE)
my_friendly_abort (2000);
+ if (TREE_CODE (context) == NAMESPACE_DECL)
+ {
+ /* We can get here from typename_sub0 in the explicit_template_type
+ expansion. Just fail. */
+ cp_error ("no class template named `%#T' in `%#T'",
+ name, context);
+ return error_mark_node;
+ }
+
if (! uses_template_parms (context)
|| currently_open_class (context))
{
return TREE_TYPE (t);
}
}
-
- if (processing_template_decl)
- push_obstacks (&permanent_obstack, &permanent_obstack);
- t = make_lang_type (TYPENAME_TYPE);
- TYPENAME_TYPE_FULLNAME (t) = fullname;
- d = build_decl (TYPE_DECL, name, t);
- if (processing_template_decl)
- pop_obstacks ();
-
- TYPE_CONTEXT (t) = FROB_CONTEXT (context);
- TYPE_NAME (TREE_TYPE (d)) = d;
- TYPE_STUB_DECL (TREE_TYPE (d)) = d;
- DECL_CONTEXT (d) = FROB_CONTEXT (context);
- CLASSTYPE_GOT_SEMICOLON (t) = 1;
-
- return t;
+
+ return build_typename_type (context, name, fullname, NULL_TREE);
}
/* Select the right _DECL from multiple choices. */
register tree val;
int yylex = 0;
tree from_obj = NULL_TREE;
- tree locval, classval;
int flags;
/* Hack: copy flag set by parser, if set. */
else
flags = lookup_flags (prefer_type, namespaces_only);
- locval = classval = NULL_TREE;
-
- if (! namespace_bindings_p ())
- locval = qualify_lookup (IDENTIFIER_LOCAL_VALUE (name), flags);
-
- /* In C++ class fields are between local and global scope,
- just before the global scope. */
- if (current_class_type && ! nonclass)
- {
- classval = IDENTIFIER_CLASS_VALUE (name);
- if (classval == NULL_TREE && TYPE_BEING_DEFINED (current_class_type))
- /* Try to find values from base classes if we are presently
- defining a type. We are presently only interested in
- TYPE_DECLs. */
- classval = lookup_field (current_class_type, name, 0, 1);
-
- /* Add implicit 'typename' to types from template bases. lookup_field
- will do this for us. If classval is actually from an enclosing
- scope, lookup_nested_field will get it for us. */
- else if (processing_template_decl
- && classval && TREE_CODE (classval) == TYPE_DECL
- && ! currently_open_class (DECL_CONTEXT (classval))
- && uses_template_parms (current_class_type))
- classval = lookup_field (current_class_type, name, 0, 1);
+ /* First, look in a non-global scope, carefully avoiding any
+ class-scope bindings if required. */
+ val = IDENTIFIER_BINDING (name);
+ while (val && nonclass && !LOCAL_BINDING_P (val))
+ val = TREE_CHAIN (val);
- /* yylex() calls this with -2, since we should never start digging for
- the nested name at the point where we haven't even, for example,
- created the COMPONENT_REF or anything like that. */
- if (classval == NULL_TREE)
- classval = lookup_nested_field (name, ! yylex);
-
- classval = qualify_lookup (classval, flags);
+ /* Get the DECL actually bound. */
+ if (val)
+ val = BINDING_VALUE (val);
+
+ /* If VAL is a type from a dependent base, we're not really supposed
+ to be able to see it; the fact that we can is the "implicit
+ typename" extension. We call lookup_field here to turn VAL into
+ a TYPE_DECL for a TYPENAME_TYPE. */
+ if (processing_template_decl && val
+ && val == IDENTIFIER_CLASS_VALUE (name)
+ && TREE_CODE (val) == TYPE_DECL
+ && !currently_open_class (DECL_CONTEXT (val))
+ && uses_template_parms (current_class_type))
+ val = lookup_field (current_class_type, name, 0, 1);
+
+ /* Make sure that this binding is the sort of thing we're looking
+ for. */
+ val = qualify_lookup (val, flags);
+
+ /* We don't put names from baseclasses onto the IDENTIFIER_BINDING
+ list when we're defining a type. It would probably be simpler to
+ do this, but we don't. So, we must lookup names from base
+ classes explicitly. */
+ if (!val && !nonclass
+ && current_class_type && TYPE_BEING_DEFINED (current_class_type))
+ {
+ val = qualify_lookup (lookup_field (current_class_type, name, 0, 0),
+ flags);
+ if (!val)
+ val = qualify_lookup (lookup_nested_field (name, !yylex),
+ flags);
}
+
+ /* If we found a type from a dependent base class (using the
+ implicit typename extension), turn it into the TYPE_DECL for a
+ TYPENAME_TYPE here. */
+ if (val && TREE_CODE (val) == TYPE_DECL
+ && IMPLICIT_TYPENAME_P (TREE_TYPE (val)))
+ {
+ tree global_val;
+
+ /* Any other name takes precedence over an implicit typename. Warn the
+ user about this potentially confusing lookup. */
+ global_val = unqualified_namespace_lookup (name, flags);
+
+ if (global_val)
+ {
+ tree subtype;
+
+ /* Only warn when not lexing; we don't want to warn if they
+ use this name as a declarator. */
+ subtype = TREE_TYPE (TREE_TYPE (val));
+ if (! yylex
+ && ! (TREE_CODE (global_val) == TEMPLATE_DECL
+ && CLASSTYPE_TEMPLATE_INFO (subtype)
+ && CLASSTYPE_TI_TEMPLATE (subtype) == global_val)
+ && ! (TREE_CODE (global_val) == TYPE_DECL
+ && same_type_p (TREE_TYPE (global_val), subtype)))
+ {
+ cp_warning ("lookup of `%D' finds `%#D'", name, global_val);
+ cp_warning (" instead of `%D' from dependent base class",
+ val);
+ cp_warning (" (use `typename %T::%D' if that's what you meant)",
+ constructor_name (current_class_type), name);
+ }
- if (locval && classval)
- {
- if (current_scope () == current_function_decl
- && ! hack_decl_function_context (current_function_decl))
- /* Not in a nested function. */
- val = locval;
- else
- {
- /* This is incredibly horrible. The whole concept of
- IDENTIFIER_LOCAL_VALUE / IDENTIFIER_CLASS_VALUE /
- IDENTIFIER_GLOBAL_VALUE needs to be scrapped for local
- classes. */
- tree lctx = hack_decl_function_context (locval);
- tree cctx = hack_decl_function_context (classval);
-
- if (lctx == current_scope ())
- val = locval;
- else if (lctx == cctx)
- val = classval;
- else
- /* I don't know which is right; let's just guess for now. */
- val = locval;
+ /* Use the global value instead of the implicit typename. */
+ val = global_val;
}
}
- else if (locval)
- val = locval;
- else if (classval)
- val = classval;
- else
+ else if (!val)
+ /* No local, or class-scoped binding. Look for a namespace-scope
+ declaration. */
val = unqualified_namespace_lookup (name, flags);
- if (classval && TREE_CODE (val) == TYPE_DECL
- && TREE_CODE (TREE_TYPE (val)) == TYPENAME_TYPE
- && TREE_TYPE (TREE_TYPE (val)))
+ done:
+ if (val)
{
- tree nsval = unqualified_namespace_lookup (name, flags);
-
- if (val && nsval && TREE_CODE (nsval) == TYPE_DECL)
- {
- static int explained;
- cp_warning ("namespace-scope type `%#D'", nsval);
- cp_warning
- (" is used instead of `%D' from dependent base class", val);
- if (! explained)
- {
- explained = 1;
- cp_warning (" (use `typename %D' if that's what you meant)",
- val);
- }
- val = nsval;
- }
- }
-
- done:
- if (val)
- {
- /* This should only warn about types used in qualified-ids. */
- if (from_obj && from_obj != val)
+ /* This should only warn about types used in qualified-ids. */
+ if (from_obj && from_obj != val)
{
if (looking_for_typename && TREE_CODE (from_obj) == TYPE_DECL
&& TREE_CODE (val) == TYPE_DECL
val = from_obj;
}
- if ((TREE_CODE (val) == TEMPLATE_DECL && looking_for_template)
- || TREE_CODE (val) == TYPE_DECL || prefer_type <= 0)
- ;
- /* Caller wants a class-or-namespace-name. */
- else if (prefer_type == 1 && TREE_CODE (val) == NAMESPACE_DECL)
- ;
- else if (IDENTIFIER_HAS_TYPE_VALUE (name))
- val = TYPE_MAIN_DECL (IDENTIFIER_TYPE_VALUE (name));
- else if (TREE_TYPE (val) == error_mark_node)
- val = error_mark_node;
-
/* If we have a single function from a using decl, pull it out. */
if (TREE_CODE (val) == OVERLOAD && ! really_overloaded_fn (val))
val = OVL_FUNCTION (val);
if (t != NULL_TREE && TREE_CODE (t) == TREE_LIST)
t = TREE_VALUE (t);
}
- else if (IDENTIFIER_LOCAL_VALUE (name) != NULL_TREE)
+ else if (IDENTIFIER_BINDING (name)
+ && LOCAL_BINDING_P (IDENTIFIER_BINDING (name)))
{
struct binding_level *b = current_binding_level;
+
while (1)
{
- if (purpose_member (name, b->shadowed))
- return IDENTIFIER_LOCAL_VALUE (name);
+ if (BINDING_LEVEL (IDENTIFIER_BINDING (name)) == b)
+ return IDENTIFIER_VALUE (name);
+
if (b->keep == 2)
b = b->level_chain;
else
tree string_ftype_ptr_ptr, int_ftype_string_string;
tree sizetype_endlink;
tree ptr_ftype, ptr_ftype_unsigned, ptr_ftype_sizetype;
- tree void_ftype, void_ftype_int, void_ftype_ptr, ptr_ftype_void;
+ tree void_ftype, void_ftype_int, void_ftype_ptr;
/* Have to make these distinct before we try using them. */
lang_name_cplusplus = get_identifier ("C++");
if (flag_strict_prototype == 2)
flag_strict_prototype = pedantic;
+ if (! flag_permissive && ! pedantic)
+ flag_pedantic_errors = 1;
strict_prototypes_lang_c = flag_strict_prototype;
current_binding_level = NULL_BINDING_LEVEL;
free_binding_level = NULL_BINDING_LEVEL;
-#ifndef __CYGWIN32__
/* Because most segmentation signals can be traced back into user
code, catch them and at least give the user a chance of working
around compiler bugs. */
#ifdef SIGBUS
signal (SIGBUS, signal_catch);
#endif
-#else /* ndef __CYGWIN32__ */
- /* Cygwin32 cannot handle catching signals other than
- SIGABRT yet. We hope this will cease to be the case soon. */
-#ifdef SIGABRT
- signal (SIGABRT, signal_catch);
-#endif
-#endif /* ndef __CYGWIN32__ */
gcc_obstack_init (&decl_obstack);
pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node));
intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
+#if HOST_BITS_PER_WIDE_INT >= 64
intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
- pushdecl (build_decl (TYPE_DECL, NULL_TREE, intTI_type_node));
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("__int128_t"), intTI_type_node));
+#endif
unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node));
unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node));
unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node));
+#if HOST_BITS_PER_WIDE_INT >= 64
unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
- pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intTI_type_node));
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("__uint128_t"), unsigned_intTI_type_node));
+#endif
float_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
string_type_node = build_pointer_type (char_type_node);
const_string_type_node
- = build_pointer_type (build_type_variant (char_type_node, 1, 0));
+ = build_pointer_type (build_qualified_type (char_type_node,
+ TYPE_QUAL_CONST));
#if 0
record_builtin_type (RID_MAX, NULL_PTR, string_type_node);
#endif
ptr_type_node = build_pointer_type (void_type_node);
const_ptr_type_node
- = build_pointer_type (build_type_variant (void_type_node, 1, 0));
+ = build_pointer_type (build_qualified_type (void_type_node,
+ TYPE_QUAL_CONST));
#if 0
record_builtin_type (RID_MAX, NULL_PTR, ptr_type_node);
#endif
builtin_function ("__builtin_frame_address", ptr_ftype_unsigned,
BUILT_IN_FRAME_ADDRESS, NULL_PTR);
- ptr_ftype_void = build_function_type (ptr_type_node, endlink);
- builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
- builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
-
builtin_function ("__builtin_alloca", ptr_ftype_sizetype,
BUILT_IN_ALLOCA, "alloca");
builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
DECL_SIZE (fields[3]) = TYPE_SIZE (delta_type_node);
TREE_UNSIGNED (fields[3]) = 0;
TREE_CHAIN (fields[2]) = fields[3];
- vtable_entry_type = build_type_variant (vtable_entry_type, 1, 0);
+ vtable_entry_type = build_qualified_type (vtable_entry_type,
+ TYPE_QUAL_CONST);
}
record_builtin_type (RID_MAX, VTBL_PTR_TYPE, vtable_entry_type);
vtbl_type_node
- = build_array_type (vtable_entry_type, NULL_TREE);
+ = build_cplus_array_type (vtable_entry_type, NULL_TREE);
layout_type (vtbl_type_node);
- vtbl_type_node = cp_build_type_variant (vtbl_type_node, 1, 0);
+ vtbl_type_node = build_qualified_type (vtbl_type_node, TYPE_QUAL_CONST);
record_builtin_type (RID_MAX, NULL_PTR, vtbl_type_node);
+ vtbl_ptr_type_node = build_pointer_type (vtable_entry_type);
+ layout_type (vtbl_ptr_type_node);
+ record_builtin_type (RID_MAX, NULL_PTR, vtbl_ptr_type_node);
/* Simplify life by making a "sigtable_entry_type". Give its
fields names so that the debugger can use them. */
TREE_UNSIGNED (fields[5]) = 0;
TREE_CHAIN (fields[4]) = fields[5];
- sigtable_entry_type = build_type_variant (sigtable_entry_type, 1, 0);
+ sigtable_entry_type = build_qualified_type (sigtable_entry_type,
+ TYPE_QUAL_CONST);
record_builtin_type (RID_MAX, SIGTABLE_PTR_TYPE, sigtable_entry_type);
}
(void_ftype_ptr, build_tree_list (NULL_TREE, NULL_TREE));
auto_function (ansi_opname[(int) NEW_EXPR], newtype, NOT_BUILT_IN);
auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype, NOT_BUILT_IN);
- auto_function (ansi_opname[(int) DELETE_EXPR], deltype, NOT_BUILT_IN);
+ global_delete_fndecl
+ = auto_function (ansi_opname[(int) DELETE_EXPR], deltype, NOT_BUILT_IN);
auto_function (ansi_opname[(int) VEC_DELETE_EXPR], deltype, NOT_BUILT_IN);
}
return decl;
}
\f
-/* Called when a declaration is seen that contains no names to declare.
- If its type is a reference to a structure, union or enum inherited
- from a containing scope, shadow that tag name for the current scope
- with a forward reference.
- If its type defines a new named structure or union
- or defines an enum, it is valid but we need not do anything here.
- Otherwise, it is an error.
+/* When we call finish_struct for an anonymous union, we create
+ default copy constructors and such. But, an anonymous union
+ shouldn't have such things; this function undoes the damage to the
+ anonymous union type T.
- C++: may have to grok the declspecs to learn about static,
- complain for anonymous unions. */
+ (The reason that we create the synthesized methods is that we don't
+ distinguish `union { int i; }' from `typedef union { int i; } U'.
+ The first is an anonymous union; the second is just an ordinary
+ union type.) */
void
-shadow_tag (declspecs)
+fixup_anonymous_union (t)
+ tree t;
+{
+ tree *q;
+
+ /* 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;
+
+ /* Splice the implicitly generated functions out of the TYPE_METHODS
+ list. */
+ q = &TYPE_METHODS (t);
+ while (*q)
+ {
+ if (DECL_ARTIFICIAL (*q))
+ *q = TREE_CHAIN (*q);
+ else
+ q = &TREE_CHAIN (*q);
+ }
+
+ /* ANSI C++ June 5 1992 WP 9.5.3. Anonymous unions may not have
+ function members. */
+ if (TYPE_METHODS (t))
+ error ("an anonymous union cannot have function members");
+}
+
+/* Make sure that a declaration with no declarator is well-formed, i.e.
+ just defines a tagged type or anonymous union.
+
+ Returns the type defined, if any. */
+
+tree
+check_tag_decl (declspecs)
tree declspecs;
{
- int found_tag = 0;
+ int found_type = 0;
tree ob_modifier = NULL_TREE;
register tree link;
- register enum tree_code code, ok_code = ERROR_MARK;
register tree t = NULL_TREE;
for (link = declspecs; link; link = TREE_CHAIN (link))
{
register tree value = TREE_VALUE (link);
- code = TREE_CODE (value);
- if (IS_AGGR_TYPE_CODE (code) || code == ENUMERAL_TYPE)
+ if (TYPE_P (value))
{
- my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261);
-
- maybe_process_partial_specialization (value);
+ ++found_type;
- t = value;
- ok_code = code;
- found_tag++;
+ if (IS_AGGR_TYPE (value) || TREE_CODE (value) == ENUMERAL_TYPE)
+ {
+ my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261);
+ t = value;
+ }
+ }
+ else if (value == ridpointers[(int) RID_FRIEND])
+ {
+ if (current_class_type == NULL_TREE
+ || current_scope () != current_class_type)
+ ob_modifier = value;
}
else if (value == ridpointers[(int) RID_STATIC]
|| value == ridpointers[(int) RID_EXTERN]
|| value == ridpointers[(int) RID_REGISTER]
|| value == ridpointers[(int) RID_INLINE]
|| value == ridpointers[(int) RID_VIRTUAL]
+ || value == ridpointers[(int) RID_CONST]
+ || value == ridpointers[(int) RID_VOLATILE]
|| value == ridpointers[(int) RID_EXPLICIT])
ob_modifier = value;
}
+ if (found_type > 1)
+ error ("multiple types in one declaration");
+
+ /* Inside a class, we might be in a friend or access declaration.
+ Until we have a good way of detecting the latter, don't warn. */
+ if (t == NULL_TREE && ! current_class_type)
+ pedwarn ("declaration does not declare anything");
+ else if (t && ANON_UNION_TYPE_P (t))
+ /* Anonymous unions are objects, so they can have specifiers. */;
+ else if (ob_modifier)
+ {
+ if (ob_modifier == ridpointers[(int) RID_INLINE]
+ || ob_modifier == ridpointers[(int) RID_VIRTUAL])
+ cp_error ("`%D' can only be specified for functions", ob_modifier);
+ else if (ob_modifier == ridpointers[(int) RID_FRIEND])
+ cp_error ("`%D' can only be specified inside a class", ob_modifier);
+ else if (ob_modifier == ridpointers[(int) RID_EXPLICIT])
+ cp_error ("`%D' can only be specified for constructors",
+ ob_modifier);
+ else
+ cp_error ("`%D' can only be specified for objects and functions",
+ ob_modifier);
+ }
+
+ return t;
+}
+
+/* Called when a declaration is seen that contains no names to declare.
+ If its type is a reference to a structure, union or enum inherited
+ from a containing scope, shadow that tag name for the current scope
+ with a forward reference.
+ If its type defines a new named structure or union
+ or defines an enum, it is valid but we need not do anything here.
+ Otherwise, it is an error.
+
+ C++: may have to grok the declspecs to learn about static,
+ complain for anonymous unions. */
+
+void
+shadow_tag (declspecs)
+ tree declspecs;
+{
+ tree t = check_tag_decl (declspecs);
+
+ if (t)
+ maybe_process_partial_specialization (t);
+
/* This is where the variables in an anonymous union are
declared. An anonymous union declaration looks like:
union { ... } ;
because there is no declarator after the union, the parser
sends that declaration here. */
- if (ok_code == UNION_TYPE
- && t != NULL_TREE
- && ((TREE_CODE (TYPE_NAME (t)) == IDENTIFIER_NODE
- && ANON_AGGRNAME_P (TYPE_NAME (t)))
- || (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))))
- {
- /* See also grok_x_components. */
- tree *q;
-
- /* 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);
- }
-
- /* ANSI C++ June 5 1992 WP 9.5.3. Anonymous unions may not have
- function members. */
- if (TYPE_METHODS (t))
- error ("an anonymous union cannot have function members");
+ if (t && ANON_UNION_TYPE_P (t))
+ {
+ fixup_anonymous_union (t);
if (TYPE_FIELDS (t))
{
finish_anon_union (decl);
}
}
- else
- {
- /* Anonymous unions are objects, that's why we only check for
- inappropriate specifiers in this branch. */
-
- if (ob_modifier)
- {
- if (ob_modifier == ridpointers[(int) RID_INLINE]
- || ob_modifier == ridpointers[(int) RID_VIRTUAL])
- cp_error ("`%D' can only be specified for functions", ob_modifier);
- else if (ob_modifier == ridpointers[(int) RID_EXPLICIT])
- cp_error ("`%D' can only be specified for constructors",
- ob_modifier);
- else
- cp_error ("`%D' can only be specified for objects and functions",
- ob_modifier);
- }
-
- if (found_tag == 0)
- cp_error ("abstract declarator used as declaration");
- else if (found_tag > 1)
- pedwarn ("multiple types in one declaration");
- }
}
\f
/* Decode a "typename", such as "int **", returning a ..._TYPE node. */
if (context && TYPE_SIZE (complete_type (context)) != NULL_TREE)
{
+ pushclass (context, 2);
+
if (TREE_CODE (decl) == VAR_DECL)
{
tree field = lookup_field (context, DECL_NAME (decl), 0, 0);
DECL_IN_AGGR_P (decl) = 0;
if ((DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl))
|| CLASSTYPE_USE_TEMPLATE (context))
- SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+ {
+ SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+ /* [temp.expl.spec] An explicit specialization of a static data
+ member of a template is a definition if the declaration
+ includes an initializer; otherwise, it is a declaration.
+
+ We check for processing_specialization so this only applies
+ to the new specialization syntax. */
+ if (DECL_INITIAL (decl) == NULL_TREE && processing_specialization)
+ DECL_EXTERNAL (decl) = 1;
+ }
if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl))
cp_pedwarn ("declaration of `%#D' outside of class is not definition",
decl);
-
- pushclass (context, 2);
}
+#ifdef SET_DEFAULT_DECL_ATTRIBUTES
+ SET_DEFAULT_DECL_ATTRIBUTES (decl, attributes);
+#endif
+
/* Set attributes here so if duplicate decl, will have proper attributes. */
cplus_decl_attributes (decl, attributes, prefix_attributes);
data segment. */
DECL_COMMON (tem) = flag_conserve_space || ! TREE_PUBLIC (tem);
#endif
-
+
if (! processing_template_decl)
start_decl_1 (tem);
return;
}
- if (TREE_TYPE (init) && TREE_CODE (TREE_TYPE (init)) == UNKNOWN_TYPE)
- /* decay_conversion is probably wrong for references to functions. */
- init = decay_conversion (instantiate_type (TREE_TYPE (type), init, 1));
-
if (TREE_CODE (init) == TREE_LIST)
init = build_compound_expr (init);
return init;
}
+/* Issue an error message if DECL is an uninitialized const variable. */
+
+static void
+check_for_uninitialized_const_var (decl)
+ tree decl;
+{
+ tree type = TREE_TYPE (decl);
+
+ /* ``Unless explicitly declared extern, a const object does not have
+ external linkage and must be initialized. ($8.4; $12.1)'' ARM
+ 7.1.6 */
+ if (TREE_CODE (decl) == VAR_DECL
+ && TREE_CODE (type) != REFERENCE_TYPE
+ && CP_TYPE_CONST_P (type)
+ && !TYPE_NEEDS_CONSTRUCTING (type)
+ && !DECL_INITIAL (decl))
+ cp_error ("uninitialized const `%D'", decl);
+}
+
/* Finish processing of a declaration;
install its line number and initial value.
If the length of an array type is not known before,
init = NULL_TREE;
}
+ if (current_class_type
+ && DECL_REAL_CONTEXT (decl) == current_class_type
+ && TYPE_BEING_DEFINED (current_class_type)
+ && (DECL_INITIAL (decl) || init))
+ DECL_DEFINED_IN_CLASS_P (decl) = 1;
+
if (TREE_CODE (decl) == VAR_DECL
&& DECL_CONTEXT (decl)
&& TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL
{
if (TREE_CODE (type) == ARRAY_TYPE)
init = digest_init (type, init, (tree *) 0);
- else if (TREE_CODE (init) == CONSTRUCTOR)
+ else if (TREE_CODE (init) == CONSTRUCTOR
+ && TREE_HAS_CONSTRUCTOR (init))
{
if (TYPE_NON_AGGREGATE_CLASS (type))
{
decl);
}
- if (TREE_CODE (decl) == VAR_DECL
- && !DECL_INITIAL (decl)
- && !TYPE_NEEDS_CONSTRUCTING (type)
- && (TYPE_READONLY (type) || TREE_READONLY (decl)))
- cp_error ("uninitialized const `%D'", decl);
+ check_for_uninitialized_const_var (decl);
if (TYPE_SIZE (type) != NULL_TREE
&& TYPE_NEEDS_CONSTRUCTING (type))
init = obscure_complex_init (decl, NULL_TREE);
- }
- else if (TREE_CODE (decl) == VAR_DECL
- && TREE_CODE (type) != REFERENCE_TYPE
- && (TYPE_READONLY (type) || TREE_READONLY (decl)))
- {
- /* ``Unless explicitly declared extern, a const object does not have
- external linkage and must be initialized. ($8.4; $12.1)'' ARM 7.1.6
- However, if it's `const int foo = 1; const int foo;', don't complain
- about the second decl, since it does have an initializer before.
- We deliberately don't complain about arrays, because they're
- supposed to be initialized by a constructor. */
- if (! DECL_INITIAL (decl)
- && TREE_CODE (type) != ARRAY_TYPE
- && (!pedantic || !current_class_type))
- cp_error ("uninitialized const `%#D'", decl);
- }
+ }
+ else
+ check_for_uninitialized_const_var (decl);
+
/* For top-level declaration, the initial value was read in
the temporary obstack. MAXINDEX, rtl, etc. to be made below
must go in the permanent obstack; but don't discard the
if (was_temp)
end_temporary_allocation ();
- /* Extern inline function static data has external linkage.
- Instead of trying to deal with that, we disable inlining of
- such functions. The ASM_WRITTEN check is to avoid hitting this
- for __FUNCTION__. */
+ /* Static data in a function with comdat linkage also has comdat
+ linkage. */
if (TREE_CODE (decl) == VAR_DECL
&& TREE_STATIC (decl)
+ /* Don't mess with __FUNCTION__. */
&& ! TREE_ASM_WRITTEN (decl)
&& current_function_decl
&& DECL_CONTEXT (decl) == current_function_decl
- && DECL_THIS_INLINE (current_function_decl)
+ && (DECL_THIS_INLINE (current_function_decl)
+ || DECL_TEMPLATE_INSTANTIATION (current_function_decl))
&& TREE_PUBLIC (current_function_decl))
{
+ /* Rather than try to get this right with inlining, we suppress
+ inlining of such functions. */
current_function_cannot_inline
= "function with static variable cannot be inline";
+
+ /* If flag_weak, we don't need to mess with this, as we can just
+ make the function weak, and let it refer to its unique local
+ copy. This works because we don't allow the function to be
+ inlined. */
+ if (! flag_weak)
+ {
+ if (DECL_INTERFACE_KNOWN (current_function_decl))
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_EXTERNAL (decl) = DECL_EXTERNAL (current_function_decl);
+ }
+ else if (DECL_INITIAL (decl) == NULL_TREE
+ || DECL_INITIAL (decl) == error_mark_node)
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_COMMON (decl) = 1;
+ }
+ /* else we lose. We can only do this if we can use common,
+ which we can't if it has been initialized. */
+
+ if (TREE_PUBLIC (decl))
+ DECL_ASSEMBLER_NAME (decl)
+ = build_static_name (current_function_decl, DECL_NAME (decl));
+ else if (! DECL_ARTIFICIAL (decl))
+ {
+ cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl);
+ cp_warning_at (" you can work around this by removing the initializer"), decl;
+ }
+ }
}
else if (TREE_CODE (decl) == VAR_DECL
if (current_binding_level->is_for_scope)
{
- struct binding_level *outer = current_binding_level->level_chain;
+ struct binding_level *outer
+ = current_binding_level->level_chain;
/* Check to see if the same name is already bound at
the outer level, either because it was directly declared,
Otherwise, we need to preserve the temp slot for decl
to last into the outer binding level. */
- int handling_dead_for_vars = 0;
- tree link = outer->names;
- for (; ; link = TREE_CHAIN (link))
+ tree outer_binding
+ = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (decl)));
+
+ if (outer_binding && BINDING_LEVEL (outer_binding) == outer
+ && (TREE_CODE (BINDING_VALUE (outer_binding))
+ == VAR_DECL)
+ && DECL_DEAD_FOR_LOCAL (BINDING_VALUE (outer_binding)))
{
- if (link == NULL && handling_dead_for_vars == 0)
- {
- link = outer->dead_vars_from_for;
- handling_dead_for_vars = 1;
- }
- if (link == NULL)
- {
- if (DECL_IN_MEMORY_P (decl))
- preserve_temp_slots (DECL_RTL (decl));
- break;
- }
- if (DECL_NAME (link) == DECL_NAME (decl))
- {
- if (handling_dead_for_vars)
- {
- tree shadowing
- = purpose_member (DECL_NAME (decl),
- current_binding_level->shadowed);
- if (shadowing && TREE_VALUE (shadowing) == link)
- TREE_VALUE (shadowing)
- = DECL_SHADOWED_FOR_VAR (link);
- }
- current_binding_level->is_for_scope = 0;
- break;
- }
+ BINDING_VALUE (outer_binding)
+ = DECL_SHADOWED_FOR_VAR (BINDING_VALUE (outer_binding));
+ current_binding_level->is_for_scope = 0;
}
+ else if (DECL_IN_MEMORY_P (decl))
+ preserve_temp_slots (DECL_RTL (decl));
}
expand_start_target_temps ();
{
emit_line_note (DECL_SOURCE_FILE (decl),
DECL_SOURCE_LINE (decl));
- expand_aggr_init (decl, init, 0, flags);
+ expand_aggr_init (decl, init, flags);
}
/* Set this to 0 so we can tell whether an aggregate which
/* Remember this information until end of file. */
push_obstacks (&permanent_obstack, &permanent_obstack);
- /* Emit code to perform this initialization but once. */
+ /* Emit code to perform this initialization but once. This code
+ looks like:
+
+ static int temp = 0;
+ if (!temp) {
+ // Do initialization.
+ temp = 1;
+ // Register variable for destruction at end of program.
+ }
+
+ Note that the `temp' variable is only set to 1 *after* the
+ initialization is complete. This ensures that an exception,
+ thrown during the construction, will cause the variable to
+ reinitialized when we pass through this code again, as per:
+
+ [stmt.dcl]
+
+ If the initialization exits by throwing an exception, the
+ initialization is not complete, so it will be tried again
+ the next time control enters the declaration.
+
+ In theory, this process should be thread-safe, too; multiple
+ threads should not be able to initialize the variable more
+ than once. We don't yet attempt to ensure thread-safety. */
temp = get_temp_name (integer_type_node, 1);
rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
+
+ /* Begin the conditional initialization. */
expand_start_cond (build_binary_op (EQ_EXPR, temp,
integer_zero_node, 1), 0);
expand_start_target_temps ();
- expand_assignment (temp, integer_one_node, 0, 0);
+ /* Do the initialization itself. */
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
|| (init && TREE_CODE (init) == TREE_LIST))
{
- expand_aggr_init (decl, init, 0, 0);
+ expand_aggr_init (decl, init, 0);
do_pending_stack_adjust ();
}
else if (init)
expand_assignment (decl, init, 0, 0);
- /* Cleanup any temporaries needed for the initial value. */
+ /* Set TEMP to 1. */
+ expand_assignment (temp, integer_one_node, 0, 0);
+
+ /* Cleanup any temporaries needed for the initial value. If
+ destroying one of the temporaries causes an exception to be
+ thrown, then the object itself has still been fully
+ constructed. */
expand_end_target_temps ();
+ /* Use atexit to register a function for destroying this static
+ variable. */
if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
{
tree cleanup, fcall;
pop_obstacks ();
}
+ /* Call build_cleanup before we enter the anonymous function
+ so that any access checks will be done relative to the
+ current scope, rather than the scope of the anonymous
+ function. */
+ fcall = build_cleanup (decl);
cleanup = start_anon_func ();
- expand_expr_stmt (build_cleanup (decl));
+ expand_expr_stmt (fcall);
end_anon_func ();
mark_addressable (cleanup);
cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
or `volatile'.
RAISES is a list of exceptions that this function can raise.
CHECK is 1 if we must find this method in CTYPE, 0 if we should
- not look, and -1 if we should not call `grokclassfn' at all. */
+ not look, and -1 if we should not call `grokclassfn' at all.
+
+ Returns `error_mark_node' if something goes wrong, after issuing
+ applicable error messages. */
static tree
grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
if (TYPE_VOLATILE (type))
TREE_THIS_VOLATILE (decl) = 1;
- /* This decl is not from the current namespace. */
+ /* If this decl has namespace scope, set that up. */
if (in_namespace)
set_decl_namespace (decl, in_namespace);
+ else if (publicp && ! ctype)
+ DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
+
+ /* `main' and builtins have implicit 'C' linkage. */
+ if ((MAIN_NAME_P (declarator)
+ || (IDENTIFIER_LENGTH (declarator) > 10
+ && IDENTIFIER_POINTER (declarator)[0] == '_'
+ && IDENTIFIER_POINTER (declarator)[1] == '_'
+ && strncmp (IDENTIFIER_POINTER (declarator)+2, "builtin_", 8) == 0))
+ && current_lang_name == lang_name_cplusplus
+ && ctype == NULL_TREE
+ /* NULL_TREE means global namespace. */
+ && DECL_CONTEXT (decl) == NULL_TREE)
+ DECL_LANGUAGE (decl) = lang_c;
/* Should probably propagate const out from type to decl I bet (mrs). */
if (staticp)
if (ctype)
DECL_CLASS_CONTEXT (decl) = ctype;
- if (ctype == NULL_TREE && MAIN_NAME_P (declarator))
+ if (ctype == NULL_TREE && DECL_MAIN_P (decl))
{
+ if (processing_template_decl)
+ error ("cannot declare `main' to be a template");
if (inlinep)
error ("cannot declare `main' to be inline");
else if (! publicp)
publicp = 1;
}
- /* Members of anonymous types have no linkage; make them internal. */
- if (ctype && ANON_AGGRNAME_P (TYPE_IDENTIFIER (ctype)))
+ /* Members of anonymous types and local classes have no linkage; make
+ them internal. */
+ if (ctype && (ANON_AGGRNAME_P (TYPE_IDENTIFIER (ctype))
+ || hack_decl_function_context (TYPE_MAIN_DECL (ctype))))
publicp = 0;
if (publicp)
if (t)
{
if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
- cp_pedwarn ("non-local function `%#D' uses anonymous type", decl);
+ {
+ if (DECL_LANGUAGE (decl) == lang_c)
+ /* Allow this; it's pretty common in C. */;
+ else
+ cp_pedwarn ("non-local function `%#D' uses anonymous type",
+ decl);
+ }
else
cp_pedwarn ("non-local function `%#D' uses local type `%T'",
decl, t);
}
}
+ /* Plain overloading: will not be grok'd by grokclassfn. */
+ if (! ctype && ! processing_template_decl
+ && DECL_LANGUAGE (decl) != lang_c
+ && (! DECL_USE_TEMPLATE (decl) || name_mangling_version < 1))
+ set_mangled_name_for_decl (decl);
+
+ if (funcdef_flag)
+ /* Make the init_value nonzero so pushdecl knows this is not
+ tentative. error_mark_node is replaced later with the BLOCK. */
+ DECL_INITIAL (decl) = error_mark_node;
+
/* Caller will do the rest of this. */
if (check < 0)
return decl;
the following calls is supposed to do. */
DECL_CONSTRUCTOR_P (decl) = 1;
- grokclassfn (ctype, declarator, decl, flags, quals);
+ grokclassfn (ctype, decl, flags, quals);
decl = check_explicit_specialization (orig_declarator, decl,
template_count,
if (decl == error_mark_node)
return error_mark_node;
- if ((! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl))
+ if ((! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
&& check)
{
tmp = check_classfn (ctype, decl);
return tmp;
}
if (! grok_ctor_properties (ctype, decl))
- return NULL_TREE;
-
- if (check == 0 && ! current_function_decl)
- {
- /* Assembler names live in the global namespace. */
- tmp = IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl));
- if (tmp == NULL_TREE)
- SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl), decl);
- else if (TREE_CODE (tmp) != TREE_CODE (decl))
- cp_error ("inconsistent declarations for `%D'", decl);
- else
- {
- duplicate_decls (decl, tmp);
- decl = tmp;
- }
- make_decl_rtl (decl, NULL_PTR, 1);
- }
+ return error_mark_node;
}
else
{
This call may change the type of the function (because
of default parameters)! */
if (ctype != NULL_TREE)
- grokclassfn (ctype, cname, decl, flags, quals);
+ grokclassfn (ctype, decl, flags, quals);
decl = check_explicit_specialization (orig_declarator, decl,
template_count,
return error_mark_node;
if (ctype != NULL_TREE
- && (! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl))
+ && (! TYPE_FOR_JAVA (ctype) || check_java_method (decl))
&& check)
{
tmp = check_classfn (ctype, decl);
if (ctype == NULL_TREE || check)
return decl;
- /* Now install the declaration of this function so that others may
- find it (esp. its DECL_FRIENDLIST). Don't do this for local class
- methods, though. */
- if (! current_function_decl)
- {
- if (!DECL_TEMPLATE_SPECIALIZATION (decl))
- {
- /* We don't do this for specializations since the
- equivalent checks will be done later. Also, at this
- point the DECL_ASSEMBLER_NAME is not yet fully
- accurate. */
-
- /* FIXME: this should only need to look at
- IDENTIFIER_GLOBAL_VALUE. */
- tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
- if (tmp == NULL_TREE)
- SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl), decl);
- else if (TREE_CODE (tmp) != TREE_CODE (decl))
- cp_error ("inconsistent declarations for `%D'", decl);
- else
- {
- duplicate_decls (decl, tmp);
- decl = tmp;
- }
- }
+ if (attrlist)
+ cplus_decl_attributes (decl, TREE_PURPOSE (attrlist),
+ TREE_VALUE (attrlist));
+ make_decl_rtl (decl, NULL_PTR, 1);
- if (attrlist)
- cplus_decl_attributes (decl, TREE_PURPOSE (attrlist),
- TREE_VALUE (attrlist));
- make_decl_rtl (decl, NULL_PTR, 1);
- }
if (virtualp)
{
DECL_VIRTUAL_P (decl) = 1;
}
else
{
- tree context = in_namespace ? in_namespace : current_namespace;
+ tree context;
+
+ if (in_namespace)
+ context = in_namespace;
+ else if (namespace_bindings_p () || RIDBIT_SETP (RID_EXTERN, specbits))
+ context = current_namespace;
+ else
+ context = NULL_TREE;
+
decl = build_decl (VAR_DECL, declarator, complete_type (type));
- if (context != global_namespace && namespace_bindings_p ()
- && current_lang_name != lang_name_c)
- DECL_ASSEMBLER_NAME (decl) = build_static_name (context,
- declarator);
+
+ if (context)
+ set_decl_namespace (decl, context);
+
+ context = DECL_CONTEXT (decl);
+ if (declarator && context && current_lang_name != lang_name_c)
+ DECL_ASSEMBLER_NAME (decl) = build_static_name (context, declarator);
}
if (in_namespace)
push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
u = make_lang_type (UNION_TYPE);
- IS_AGGR_TYPE (u) = 0;
+ SET_IS_AGGR_TYPE (u, 0);
fields[0] = build_lang_field_decl (FIELD_DECL, pfn_identifier, type);
fields[1] = build_lang_field_decl (FIELD_DECL, delta2_identifier,
delta_type_node);
/* Let the front-end know this is a pointer to member function... */
TYPE_PTRMEMFUNC_FLAG (t) = 1;
/* ... and not really an aggregate. */
- IS_AGGR_TYPE (t) = 0;
+ SET_IS_AGGR_TYPE (t, 0);
fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier,
delta_type_node);
enum return_types { return_normal, return_ctor, return_dtor, return_conversion };
+/* DECL is a VAR_DECL defined in-class, whose TYPE is also given.
+ Check to see that the definition is valid. Issue appropriate error
+ messages. Return 1 if the definition is particularly bad, or 0
+ otherwise. */
+
+int
+check_static_variable_definition (decl, type)
+ tree decl;
+ tree type;
+{
+ /* Motion 10 at San Diego: If a static const integral data member is
+ initialized with an integral constant expression, the initializer
+ may appear either in the declaration (within the class), or in
+ the definition, but not both. If it appears in the class, the
+ member is a member constant. The file-scope definition is always
+ required. */
+ if (CLASS_TYPE_P (type) || TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ cp_error ("in-class initialization of static data member of non-integral type `%T'",
+ type);
+ /* If we just return the declaration, crashes will sometimes
+ occur. We therefore return void_type_node, as if this was a
+ friend declaration, to cause callers to completely ignore
+ this declaration. */
+ return 1;
+ }
+ else if (!CP_TYPE_CONST_P (type))
+ cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
+ decl);
+ else if (pedantic && !INTEGRAL_TYPE_P (type))
+ cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", decl, type);
+
+ return 0;
+}
+
tree
grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
tree declspecs;
tree type = NULL_TREE;
int longlong = 0;
int constp;
+ int restrictp;
int volatilep;
+ int type_quals;
int virtualp, explicitp, friendp, inlinep, staticp;
int explicit_int = 0;
int explicit_char = 0;
tree raises = NULL_TREE;
int template_count = 0;
tree in_namespace = NULL_TREE;
+ tree inner_attrs;
+ int ignore_attrs;
RIDBIT_RESET_ALL (specbits);
if (decl_context == FUNCDEF)
decl = *next;
switch (TREE_CODE (decl))
{
+ case TREE_LIST:
+ /* For attributes. */
+ next = &TREE_VALUE (decl);
+ break;
+
case COND_EXPR:
ctype = NULL_TREE;
next = &TREE_OPERAND (decl, 0);
init = TREE_OPERAND (decl, 1);
decl = start_decl (declarator, declspecs, 1, NULL_TREE, NULL_TREE);
- /* Look for __unused__ attribute */
- if (TREE_USED (TREE_TYPE (decl)))
- TREE_USED (decl) = 1;
- finish_decl (decl, init, NULL_TREE);
+ if (decl)
+ {
+ /* Look for __unused__ attribute */
+ if (TREE_USED (TREE_TYPE (decl)))
+ TREE_USED (decl) = 1;
+ finish_decl (decl, init, NULL_TREE);
+ }
+ else
+ cp_error ("invalid declarator");
return 0;
}
innermost_code = TREE_CODE (decl);
}
else
{
- if (funcdef_flag)
- {
- if (warn_return_type
- && return_type == return_normal)
- /* Save warning until we know what is really going on. */
- warn_about_return_type = 1;
- }
- else if (RIDBIT_SETP (RID_TYPEDEF, specbits))
- pedwarn ("ANSI C++ forbids typedef which does not specify a type");
- else if (innermost_code != CALL_EXPR || pedantic
- || (warn_return_type && return_type == return_normal))
- {
- if (innermost_code == CALL_EXPR)
- cp_pedwarn ("return-type of `%D' defaults to `int'", dname);
- else
- cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type",
- dname);
- }
+ if (! pedantic && ! warn_return_type
+ && funcdef_flag
+ && MAIN_NAME_P (dname)
+ && ctype == NULL_TREE
+ && in_namespace == NULL_TREE
+ && current_namespace == global_namespace)
+ /* Let `main () { }' slide, since it's so common. */;
+ else
+ cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type",
+ dname);
type = integer_type_node;
}
}
}
else if (return_type == return_conversion)
{
- if (comptypes (type, ctor_return_type, 1) == 0)
+ if (!same_type_p (type, ctor_return_type))
cp_error ("operator `%T' declared to return `%T'",
ctor_return_type, type);
else
&& TYPE_MAIN_VARIANT (type) == double_type_node)
{
RIDBIT_RESET (RID_LONG, specbits);
- type = build_type_variant (long_double_type_node, TYPE_READONLY (type),
- TYPE_VOLATILE (type));
+ type = build_qualified_type (long_double_type_node,
+ CP_TYPE_QUALS (type));
}
/* Check all other uses of type modifiers. */
if (return_type == return_conversion
&& (RIDBIT_SETP (RID_CONST, specbits)
- || RIDBIT_SETP (RID_VOLATILE, specbits)))
- cp_error ("`operator %T' cannot be cv-qualified",
+ || RIDBIT_SETP (RID_VOLATILE, specbits)
+ || RIDBIT_SETP (RID_RESTRICT, specbits)))
+ cp_error ("qualifiers are not allowed on declaration of `operator %T'",
ctor_return_type);
/* Set CONSTP if this declaration is `const', whether by
explicit specification or via a typedef.
Likewise for VOLATILEP. */
- constp = !! RIDBIT_SETP (RID_CONST, specbits) + TYPE_READONLY (type);
- volatilep = !! RIDBIT_SETP (RID_VOLATILE, specbits) + TYPE_VOLATILE (type);
- type = build_type_variant (type, 0, 0);
+ constp = !! RIDBIT_SETP (RID_CONST, specbits) + CP_TYPE_CONST_P (type);
+ restrictp =
+ !! RIDBIT_SETP (RID_RESTRICT, specbits) + CP_TYPE_RESTRICT_P (type);
+ volatilep =
+ !! RIDBIT_SETP (RID_VOLATILE, specbits) + CP_TYPE_VOLATILE_P (type);
+ type_quals = ((constp ? TYPE_QUAL_CONST : 0)
+ | (restrictp ? TYPE_QUAL_RESTRICT : 0)
+ | (volatilep ? TYPE_QUAL_VOLATILE : 0));
+ type = cp_build_qualified_type (type, type_quals);
staticp = 0;
inlinep = !! RIDBIT_SETP (RID_INLINE, specbits);
virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits);
friendp = RIDBIT_SETP (RID_FRIEND, specbits);
RIDBIT_RESET (RID_FRIEND, specbits);
+ /* $7.1.2, Function specifiers */
+ if (friendp && explicitp)
+ error ("only declarations of constructors can be `explicit'");
+
if (RIDBIT_SETP (RID_MUTABLE, specbits))
{
if (decl_context == PARM)
&& IS_SIGNATURE (current_class_type)
&& RIDBIT_NOTSETP (RID_TYPEDEF, specbits))
{
- if (constp)
- {
- error ("`const' specified for signature member function `%s'", name);
- constp = 0;
- }
- if (volatilep)
+ if (type_quals != TYPE_UNQUALIFIED)
{
- error ("`volatile' specified for signature member function `%s'",
- name);
- volatilep = 0;
+ error ("type qualifiers specified for signature member function `%s'", name);
+ type_quals = TYPE_UNQUALIFIED;
}
if (inlinep)
{
{
/* It's common practice (and completely valid) to have a const
be initialized and declared extern. */
- if (! constp)
+ if (!(type_quals & TYPE_QUAL_CONST))
warning ("`%s' initialized and declared `extern'", name);
}
else
Descend through it, creating more complex types, until we reach
the declared identifier (or NULL_TREE, in an absolute declarator). */
+ inner_attrs = NULL_TREE;
+ ignore_attrs = 0;
+
while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE
&& TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
{
quals = NULL_TREE;
}
}
+
+ /* See the comment for the TREE_LIST case, below. */
+ if (ignore_attrs)
+ ignore_attrs = 0;
+ else if (inner_attrs)
+ {
+ decl_attributes (type, inner_attrs, NULL_TREE);
+ inner_attrs = NULL_TREE;
+ }
+
switch (TREE_CODE (declarator))
{
+ case TREE_LIST:
+ {
+ /* We encode a declarator with embedded attributes using
+ a TREE_LIST. The attributes apply to the declarator
+ directly inside them, so we have to skip an iteration
+ before applying them to the type. If the declarator just
+ inside is the declarator-id, we apply the attrs to the
+ decl itself. */
+ inner_attrs = TREE_PURPOSE (declarator);
+ ignore_attrs = 1;
+ declarator = TREE_VALUE (declarator);
+ }
+ break;
+
case ARRAY_REF:
{
register tree itype = NULL_TREE;
if (size == error_mark_node)
type = error_mark_node;
+ else if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type))
+ {
+ /* [dcl.array]
+
+ the constant expressions that specify the bounds of
+ the arrays can be omitted only for the first member
+ of the sequence. */
+ cp_error ("declaration of `%D' as multidimensional array",
+ dname);
+ cp_error ("must have bounds for all dimensions except the first");
+ type = error_mark_node;
+ }
if (type == error_mark_node)
continue;
constant, but we don't know what the value is yet. */
if (processing_template_decl)
{
+ /* Resolve a qualified reference to an enumerator or
+ static const data member of ours. */
+ if (TREE_CODE (size) == SCOPE_REF
+ && TREE_OPERAND (size, 0) == current_class_type)
+ {
+ tree t = lookup_field (current_class_type,
+ TREE_OPERAND (size, 1), 0, 0);
+ if (t)
+ size = t;
+ }
+
itype = make_node (INTEGER_TYPE);
TYPE_MIN_VALUE (itype) = size_zero_node;
TYPE_MAX_VALUE (itype) = build_min
}
if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE
- && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE)
+ && TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE
+ && TREE_CODE (TREE_TYPE (size)) != BOOLEAN_TYPE)
{
cp_error ("size of array `%D' has non-integer type",
dname);
resume_momentary (yes);
}
- /* Build the array type itself, then merge any constancy or
- volatility into the target type. We must do it in this order
- to ensure that the TYPE_MAIN_VARIANT field of the array type
- is set correctly. */
-
type = build_cplus_array_type (type, itype);
- if (constp || volatilep)
- type = cp_build_type_variant (type, constp, volatilep);
-
ctype = NULL_TREE;
}
break;
/* Declaring a function type.
Make sure we have a valid type for the function to return. */
-#if 0
- /* Is this an error? Should they be merged into TYPE here? */
- if (pedantic && (constp || volatilep))
- pedwarn ("function declared to return const or volatile result");
-#else
- /* Merge any constancy or volatility into the function return
- type. */
- if (constp || volatilep)
- {
- type = cp_build_type_variant (type, constp, volatilep);
- if (IS_AGGR_TYPE (type))
- build_pointer_type (type);
- constp = 0;
- volatilep = 0;
- }
-#endif
+ /* We now know that the TYPE_QUALS don't apply to the
+ decl, but to its return type. */
+ type_quals = TYPE_UNQUALIFIED;
/* Warn about some types functions can't return. */
error ("destructor cannot be static member function");
if (quals)
{
- error ("destructors cannot be declared `const' or `volatile'");
- return void_type_node;
+ cp_error ("destructors may not be `%s'",
+ IDENTIFIER_POINTER (TREE_VALUE (quals)));
+ quals = NULL_TREE;
}
if (decl_context == FIELD)
{
}
if (quals)
{
- error ("constructors cannot be declared `const' or `volatile'");
- return void_type_node;
+ cp_error ("constructors may not be `%s'",
+ IDENTIFIER_POINTER (TREE_VALUE (quals)));
+ quals = NULL_TREE;
}
{
RID_BIT_TYPE tmp_bits;
arg_types = grokparms (inner_parms, funcdecl_p ? funcdef_flag : 0);
- if (declarator)
+ if (declarator && flags == DTOR_FLAG)
{
- /* Get past destructors, etc.
- We know we have one because FLAGS will be non-zero.
-
- Complain about improper parameter lists here. */
+ /* A destructor declared in the body of a class will
+ be represented as a BIT_NOT_EXPR. But, we just
+ want the underlying IDENTIFIER. */
if (TREE_CODE (declarator) == BIT_NOT_EXPR)
+ declarator = TREE_OPERAND (declarator, 0);
+
+ if (strict_prototype == 0 && arg_types == NULL_TREE)
+ arg_types = void_list_node;
+ else if (arg_types == NULL_TREE
+ || arg_types != void_list_node)
{
- declarator = TREE_OPERAND (declarator, 0);
-
- if (strict_prototype == 0 && arg_types == NULL_TREE)
- arg_types = void_list_node;
- else if (arg_types == NULL_TREE
- || arg_types != void_list_node)
- {
- error ("destructors cannot be specified with parameters");
- arg_types = void_list_node;
- }
+ cp_error ("destructors may not have parameters");
+ arg_types = void_list_node;
+ last_function_parms = NULL_TREE;
}
}
/* Merge any constancy or volatility into the target type
for the pointer. */
- if (constp || volatilep)
- {
- /* A const or volatile signature pointer/reference is
- pointing to a const or volatile object, i.e., the
- `optr' is const or volatile, respectively, not the
- signature pointer/reference itself. */
- if (! IS_SIGNATURE (type))
- {
- type = cp_build_type_variant (type, constp, volatilep);
- if (IS_AGGR_TYPE (type))
- build_pointer_type (type);
- constp = 0;
- volatilep = 0;
- }
- }
+ /* We now know that the TYPE_QUALS don't apply to the decl,
+ but to the target of the pointer. */
+ type_quals = TYPE_UNQUALIFIED;
if (IS_SIGNATURE (type))
{
cp_warning ("empty signature `%T' used in signature reference declaration",
type);
#if 0
- type = build_signature_reference_type (type,
- constp, volatilep);
+ type = build_signature_reference_type (type);
#else
sorry ("signature reference");
return NULL_TREE;
&& TYPE_SIZE (type))
cp_warning ("empty signature `%T' used in signature pointer declaration",
type);
- type = build_signature_pointer_type (type,
- constp, volatilep);
+ type = build_signature_pointer_type (type);
}
- constp = 0;
- volatilep = 0;
}
else if (TREE_CODE (declarator) == ADDR_EXPR)
{
- if (TREE_CODE (type) == FUNCTION_TYPE)
- {
- error ("cannot declare references to functions; use pointer to function instead");
- type = build_pointer_type (type);
- }
+ if (TREE_CODE (type) == VOID_TYPE)
+ error ("invalid type: `void &'");
else
- {
- if (TREE_CODE (type) == VOID_TYPE)
- error ("invalid type: `void &'");
- else
- type = build_reference_type (type);
- }
+ type = build_reference_type (type);
}
else if (TREE_CODE (type) == METHOD_TYPE)
{
{
register tree typemodlist;
int erred = 0;
+
+ constp = 0;
+ volatilep = 0;
+ restrictp = 0;
for (typemodlist = TREE_TYPE (declarator); typemodlist;
typemodlist = TREE_CHAIN (typemodlist))
{
- if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_CONST])
+ tree qualifier = TREE_VALUE (typemodlist);
+
+ if (qualifier == ridpointers[(int) RID_CONST])
constp++;
- else if (TREE_VALUE (typemodlist) == ridpointers[(int) RID_VOLATILE])
+ else if (qualifier == ridpointers[(int) RID_VOLATILE])
volatilep++;
+ else if (qualifier == ridpointers[(int) RID_RESTRICT])
+ restrictp++;
else if (!erred)
{
erred = 1;
- error ("invalid type modifier within %s declarator",
- TREE_CODE (declarator) == ADDR_EXPR
- ? "reference" : "pointer");
+ error ("invalid type modifier within pointer declarator");
}
}
if (constp > 1)
pedwarn ("duplicate `const'");
if (volatilep > 1)
pedwarn ("duplicate `volatile'");
+ if (restrictp > 1)
+ pedwarn ("duplicate `restrict'");
+
+ type_quals = ((constp ? TYPE_QUAL_CONST : 0)
+ | (restrictp ? TYPE_QUAL_RESTRICT : 0)
+ | (volatilep ? TYPE_QUAL_VOLATILE : 0));
if (TREE_CODE (declarator) == ADDR_EXPR
&& (constp || volatilep))
{
pedwarn ("discarding `const' applied to a reference");
if (volatilep)
pedwarn ("discarding `volatile' applied to a reference");
- constp = volatilep = 0;
+ type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
}
+ type = cp_build_qualified_type (type, type_quals);
}
declarator = TREE_OPERAND (declarator, 0);
ctype = NULL_TREE;
ctype = TREE_OPERAND (declarator, 0);
t = ctype;
- while (t != NULL_TREE)
+ while (t != NULL_TREE && CLASS_TYPE_P (t))
{
if (CLASSTYPE_TEMPLATE_INFO (t) &&
!CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
{
if (current_class_type == NULL_TREE
|| friendp)
- type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep),
- TREE_TYPE (type), TYPE_ARG_TYPES (type));
+ type = build_cplus_method_type (ctype, TREE_TYPE (type),
+ TYPE_ARG_TYPES (type));
else
{
cp_error ("cannot declare member function `%T::%s' within `%T'",
{
if (TREE_CODE (type) == FUNCTION_TYPE)
type
- = build_cplus_method_type (build_type_variant (ctype,
- constp,
- volatilep),
- TREE_TYPE (type),
+ = build_cplus_method_type (ctype, TREE_TYPE (type),
TYPE_ARG_TYPES (type));
}
else
else
{
if (TREE_CODE (type) == FUNCTION_TYPE)
- type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep), TREE_TYPE (type), TYPE_ARG_TYPES (type));
+ type = build_cplus_method_type (ctype, TREE_TYPE (type),
+ TYPE_ARG_TYPES (type));
else
type = build_offset_type (ctype, type);
}
}
}
+ /* See the comment for the TREE_LIST case, above. */
+ if (inner_attrs)
+ {
+ if (! ignore_attrs)
+ decl_attributes (type, inner_attrs, NULL_TREE);
+ else if (attrlist)
+ TREE_VALUE (attrlist) = chainon (inner_attrs, TREE_VALUE (attrlist));
+ else
+ attrlist = build_decl_list (NULL_TREE, inner_attrs);
+ }
+
if (explicitp == 1)
{
error ("only constructors can be declared `explicit'");
if (RIDBIT_SETP (RID_MUTABLE, specbits))
{
- if (constp)
+ if (type_quals & TYPE_QUAL_CONST)
{
error ("const `%s' cannot be declared `mutable'", name);
RIDBIT_RESET (RID_MUTABLE, specbits);
/* Note that the grammar rejects storage classes
in typenames, fields or parameters. */
- if (constp || volatilep)
- type = cp_build_type_variant (type, constp, volatilep);
if (current_lang_name == lang_name_java)
TYPE_FOR_JAVA (type) = 1;
if (decl_context == FIELD)
{
- if (declarator == current_class_name)
+ if (declarator == constructor_name (current_class_type))
cp_pedwarn ("ANSI C++ forbids nested type `%D' with same name as enclosing class",
declarator);
decl = build_lang_decl (TYPE_DECL, declarator, type);
&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& ANON_AGGRNAME_P (TYPE_IDENTIFIER (type)))
{
+ /* FIXME: This is bogus; we should not be doing this for
+ cv-qualified types. */
+
/* For anonymous structs that are cv-qualified, need to use
TYPE_MAIN_VARIANT so that name will mangle correctly. As
type not referenced after this block, don't bother
if (TYPE_LANG_SPECIFIC (type))
TYPE_WAS_ANONYMOUS (type) = 1;
+ /* If this is a typedef within a template class, the nested
+ type is a (non-primary) template. The name for the
+ template needs updating as well. */
+ if (TYPE_LANG_SPECIFIC (type) && CLASSTYPE_TEMPLATE_INFO (type))
+ DECL_NAME (CLASSTYPE_TI_TEMPLATE (type))
+ = TYPE_IDENTIFIER (type);
+
/* XXX Temporarily set the scope.
When returning, start_decl expects it as NULL_TREE,
and will then then set it using pushdecl. */
C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
if (RIDBIT_SETP (RID_MUTABLE, specbits))
- {
- error ("non-object member `%s' cannot be declared mutable", name);
- }
+ error ("non-object member `%s' cannot be declared mutable", name);
bad_specifiers (decl, "type", virtualp, quals != NULL_TREE,
inlinep, friendp, raises != NULL_TREE);
{
/* Note that the grammar rejects storage classes
in typenames, fields or parameters. */
- if (constp || volatilep)
+ if (type_quals != TYPE_UNQUALIFIED)
{
if (IS_SIGNATURE (type))
- error ("`const' or `volatile' specified with signature type");
- else
- type = cp_build_type_variant (type, constp, volatilep);
+ error ("type qualifiers specified for signature type");
+ type_quals = TYPE_UNQUALIFIED;
}
/* Special case: "friend class foo" looks like a TYPENAME context. */
if (friendp)
{
- if (volatilep)
+ if (type_quals != TYPE_UNQUALIFIED)
{
- cp_error ("`volatile' specified for friend class declaration");
- volatilep = 0;
+ cp_error ("type qualifiers specified for friend class declaration");
+ type_quals = TYPE_UNQUALIFIED;
}
if (inlinep)
{
/* Now create the decl, which may be a VAR_DECL, a PARM_DECL
or a FUNCTION_DECL, depending on DECL_CONTEXT and TYPE. */
+ if (decl_context == PARM || decl_context == CATCHPARM)
+ {
+ if (ctype || in_namespace)
+ error ("cannot use `::' in parameter declaration");
+
+ /* A parameter declared as an array of T is really a pointer to T.
+ One declared as a function is really a pointer to a function.
+ One declared as a member is really a pointer to member. */
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ /* Transfer const-ness of array into that of type pointed to. */
+ type = build_pointer_type (TREE_TYPE (type));
+ type_quals = TYPE_UNQUALIFIED;
+ }
+ else if (TREE_CODE (type) == FUNCTION_TYPE)
+ type = build_pointer_type (type);
+ else if (TREE_CODE (type) == OFFSET_TYPE)
+ type = build_pointer_type (type);
+ else if (TREE_CODE (type) == VOID_TYPE && declarator)
+ {
+ error ("declaration of `%s' as void", name);
+ return NULL_TREE;
+ }
+ }
+
{
register tree decl;
if (decl_context == PARM)
{
- if (ctype || in_namespace)
- error ("cannot use `::' in parameter declaration");
-
- /* A parameter declared as an array of T is really a pointer to T.
- One declared as a function is really a pointer to a function.
- One declared as a member is really a pointer to member. */
-
- if (TREE_CODE (type) == ARRAY_TYPE)
- {
- /* Transfer const-ness of array into that of type pointed to. */
- type = build_pointer_type
- (cp_build_type_variant (TREE_TYPE (type), constp, volatilep));
- volatilep = constp = 0;
- }
- else if (TREE_CODE (type) == FUNCTION_TYPE)
- type = build_pointer_type (type);
- else if (TREE_CODE (type) == OFFSET_TYPE)
- type = build_pointer_type (type);
- else if (TREE_CODE (type) == VOID_TYPE && declarator)
- {
- error ("declaration of `%s' as void", name);
- return NULL_TREE;
- }
-
- decl = build_decl (PARM_DECL, declarator, complete_type (type));
+ decl = build_decl (PARM_DECL, declarator, type);
bad_specifiers (decl, "parameter", virtualp, quals != NULL_TREE,
inlinep, friendp, raises != NULL_TREE);
are error_mark_node, for example. */
decl = NULL_TREE;
}
- else if (in_namespace)
+ else if (in_namespace && !friendp)
{
/* Something like struct S { int N::j; }; */
cp_error ("invalid use of `::'");
}
}
else if (staticp < 2)
- type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep),
- TREE_TYPE (type), TYPE_ARG_TYPES (type));
+ type = build_cplus_method_type (ctype, TREE_TYPE (type),
+ TYPE_ARG_TYPES (type));
}
/* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */
virtualp, flags, quals, raises, attrlist,
friendp ? -1 : 0, friendp, publicp, inlinep,
funcdef_flag, template_count, in_namespace);
- if (decl == NULL_TREE)
- return NULL_TREE;
+ if (decl == NULL_TREE || decl == error_mark_node)
+ return decl;
#if 0
/* This clobbers the attrs stored in `decl' from `attrlist'. */
/* The decl and setting of decl_machine_attr is also turned off. */
decl = build_decl_attribute_variant (decl, decl_machine_attr);
#endif
+ /* [class.conv.ctor]
+
+ A constructor declared without the function-specifier
+ explicit that can be called with a single parameter
+ specifies a conversion from the type of its first
+ parameter to the type of its class. Such a constructor
+ is called a converting constructor. */
if (explicitp == 2)
DECL_NONCONVERTING_P (decl) = 1;
+ else if (DECL_CONSTRUCTOR_P (decl))
+ {
+ /* The constructor can be called with exactly one
+ parameter if there is at least one parameter, and
+ any subsequent parameters have default arguments.
+ We don't look at the first parameter, which is
+ really just the `this' parameter for the new
+ object. */
+ tree arg_types =
+ TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl)));
+
+ /* Skip the `in_chrg' argument too, if present. */
+ if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (decl)))
+ arg_types = TREE_CHAIN (arg_types);
+
+ if (arg_types == void_list_node
+ || (arg_types
+ && TREE_CHAIN (arg_types)
+ && TREE_CHAIN (arg_types) != void_list_node
+ && !TREE_PURPOSE (TREE_CHAIN (arg_types))))
+ DECL_NONCONVERTING_P (decl) = 1;
+ }
}
else if (TREE_CODE (type) == METHOD_TYPE)
{
the rest of the compiler does not correctly
handle the initialization unless the member is
static so we make it static below. */
- cp_pedwarn ("ANSI C++ forbids initialization of %s `%D'",
- constp ? "const member" : "member",
+ cp_pedwarn ("ANSI C++ forbids initialization of member `%D'",
declarator);
cp_pedwarn ("making `%D' static", declarator);
staticp = 1;
}
- /* Motion 10 at San Diego: If a static const integral data
- member is initialized with an integral constant
- expression, the initializer may appear either in the
- declaration (within the class), or in the definition,
- but not both. If it appears in the class, the member is
- a member constant. The file-scope definition is always
- required. */
- if (CLASS_TYPE_P (type)
- || TREE_CODE (type) == REFERENCE_TYPE)
- {
- cp_error ("in-class initialization of static data member of non-integral type `%T'",
- type);
- /* If we just return the declaration, crashes will
- sometimes occur. We therefore return
- void_type_node, as if this was a friend
- declaration, to cause callers to completely
- ignore this declaration. */
- return void_type_node;
- }
- else if (!constp)
- cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
- declarator);
- else if (pedantic && ! INTEGRAL_TYPE_P (type)
- && !uses_template_parms (type))
- cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", declarator, type);
+ if (uses_template_parms (type))
+ /* We'll check at instantiation time. */
+ ;
+ else if (check_static_variable_definition (declarator,
+ type))
+ /* If we just return the declaration, crashes
+ will sometimes occur. We therefore return
+ void_type_node, as if this was a friend
+ declaration, to cause callers to completely
+ ignore this declaration. */
+ return void_type_node;
}
+ /* 9.2p13 [class.mem] */
+ if (declarator == constructor_name (current_class_type)
+ /* Divergence from the standard: In extern "C", we
+ allow non-static data members here, because C does
+ and /usr/include/netinet/in.h uses that. */
+ && (staticp || current_lang_name != lang_c))
+ cp_pedwarn ("ANSI C++ forbids data member `%D' with same name as enclosing class",
+ declarator);
+
if (staticp)
{
- /* ANSI C++ Apr '95 wp 9.2 */
- if (declarator == current_class_name)
- cp_pedwarn ("ANSI C++ forbids static member `%D' with same name as enclosing class",
- declarator);
-
/* C++ allows static class members.
All other work for this is done by grokfield.
This VAR_DCL is built by build_lang_field_decl.
error ("virtual non-class function `%s'", name);
virtualp = 0;
}
-
- if (current_lang_name == lang_name_cplusplus
- && ! processing_template_decl
- && ! MAIN_NAME_P (original_name)
- && ! (IDENTIFIER_LENGTH (original_name) > 10
- && IDENTIFIER_POINTER (original_name)[0] == '_'
- && IDENTIFIER_POINTER (original_name)[1] == '_'
- && strncmp (IDENTIFIER_POINTER (original_name)+2, "builtin_", 8) == 0))
- /* Plain overloading: will not be grok'd by grokclassfn. */
- if (name_mangling_version < 1
- || TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
- declarator = build_decl_overload (dname, TYPE_ARG_TYPES (type), 0);
}
else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2)
- type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep),
- TREE_TYPE (type), TYPE_ARG_TYPES (type));
+ type = build_cplus_method_type (ctype, TREE_TYPE (type),
+ TYPE_ARG_TYPES (type));
/* Record presence of `static'. */
publicp = (ctype != NULL_TREE
if (decl == error_mark_node)
return error_mark_node;
- if (ctype == NULL_TREE && DECL_LANGUAGE (decl) != lang_c
- && (! DECL_USE_TEMPLATE (decl) ||
- name_mangling_version < 1))
- DECL_ASSEMBLER_NAME (decl) = declarator;
-
if (staticp == 1)
{
int illegal_static = 0;
{
/* It's a variable. */
- if (decl_context == CATCHPARM)
- {
- if (ctype)
- {
- ctype = NULL_TREE;
- error ("cannot use `::' in parameter declaration");
- }
-
- /* A parameter declared as an array of T is really a pointer to T.
- One declared as a function is really a pointer to a function.
- One declared as a member is really a pointer to member. */
-
- if (TREE_CODE (type) == ARRAY_TYPE)
- {
- /* Transfer const-ness of array into that of type
- pointed to. */
- type = build_pointer_type
- (cp_build_type_variant (TREE_TYPE (type), constp, volatilep));
- volatilep = constp = 0;
- }
- else if (TREE_CODE (type) == FUNCTION_TYPE)
- type = build_pointer_type (type);
- else if (TREE_CODE (type) == OFFSET_TYPE)
- type = build_pointer_type (type);
- }
-
/* An uninitialized decl with `extern' is a reference. */
decl = grokvardecl (type, declarator, &specbits,
- initialized, constp, in_namespace);
+ initialized,
+ (type_quals & TYPE_QUAL_CONST) != 0,
+ in_namespace);
bad_specifiers (decl, "variable", virtualp, quals != NULL_TREE,
inlinep, friendp, raises != NULL_TREE);
DECL_THIS_STATIC (decl) = 1;
/* Record constancy and volatility. */
-
- if (constp)
- TREE_READONLY (decl) = TREE_CODE (type) != REFERENCE_TYPE;
- if (volatilep)
- {
- TREE_SIDE_EFFECTS (decl) = 1;
- TREE_THIS_VOLATILE (decl) = 1;
- }
+ /* FIXME: Disallow `restrict' pointer-to-member declarations. */
+ c_apply_type_quals_to_decl (type_quals, decl);
return decl;
}
return 1;
}
-/* Subroutine of `grokparms'. In a fcn definition, arg types must
- be complete.
-
- C++: also subroutine of `start_function'. */
+/* Subroutine of start_function. Ensure that each of the parameter
+ types (as listed in PARMS) is complete, as is required for a
+ function definition. */
static void
require_complete_types_for_parms (parms)
tree parms;
{
- if (processing_template_decl)
- return;
-
while (parms)
{
tree type = TREE_TYPE (parms);
error ("parameter has incomplete type");
TREE_TYPE (parms) = error_mark_node;
}
-#if 0
- /* If the arg types are incomplete in a declaration,
- they must include undefined tags.
- These tags can never be defined in the scope of the declaration,
- so the types can never be completed,
- and no call can be compiled successfully. */
- /* This is not the right behavior for C++, but not having
- it is also probably wrong. */
else
- {
- /* Now warn if is a pointer to an incomplete type. */
- while (TREE_CODE (type) == POINTER_TYPE
- || TREE_CODE (type) == REFERENCE_TYPE)
- type = TREE_TYPE (type);
- type = TYPE_MAIN_VARIANT (type);
- if (TYPE_SIZE (type) == NULL_TREE)
- {
- if (DECL_NAME (parm) != NULL_TREE)
- warning ("parameter `%s' points to incomplete type",
- IDENTIFIER_POINTER (DECL_NAME (parm)));
- else
- warning ("parameter points to incomplete type");
- }
- }
-#endif
+ layout_decl (parms, 0);
+
parms = TREE_CHAIN (parms);
}
}
TREE_PURPOSE (decl),
PARM, init != NULL_TREE,
NULL_TREE);
- if (! decl)
+ if (! decl || TREE_TYPE (decl) == error_mark_node)
continue;
- type = TREE_TYPE (decl);
+
+ /* Top-level qualifiers on the parameters are
+ ignored for function types. */
+ type = TYPE_MAIN_VARIANT (TREE_TYPE (decl));
+
if (TREE_CODE (type) == VOID_TYPE)
decl = void_type_node;
else if (TREE_CODE (type) == METHOD_TYPE)
/* Unparsed default arg from in-class decl. */
else if (TREE_CODE (init) == DEFAULT_ARG)
;
- else if (TREE_CODE (init) == VAR_DECL
- || TREE_CODE (init) == PARM_DECL)
+ else if (TREE_CODE (init) == PARM_DECL
+ || TREE_CODE (init) == VAR_DECL)
{
- if (IDENTIFIER_LOCAL_VALUE (DECL_NAME (init)))
+ if (TREE_CODE (init) == VAR_DECL
+ && (IDENTIFIER_VALUE (DECL_NAME (init))
+ == init)
+ && LOCAL_BINDING_P
+ (IDENTIFIER_BINDING (DECL_NAME
+ (init))))
{
- /* ``Local variables may not be used in default
- argument expressions.'' dpANSI C++ 8.2.6 */
- /* If extern int i; within a function is not
- considered a local variable, then this code is
- wrong. */
+ /* ``Local variables may not be used in
+ default argument expressions.''
+ dpANSI C++ 8.2.6 */
+
cp_error ("local variable `%D' may not be used as a default argument", init);
any_error = 1;
}
else if (TREE_READONLY_DECL_P (init))
init = decl_constant_value (init);
}
- else
- init = require_instantiated_type (type, init, integer_zero_node);
+ else if (TREE_TYPE (init) == NULL_TREE)
+ {
+ error ("argument list may not have an initializer list");
+ init = error_mark_node;
+ }
+
if (! processing_template_decl
&& init != error_mark_node
&& TREE_CODE (init) != DEFAULT_ARG
last_function_parms = decls;
- /* In a fcn definition, arg types must be complete. */
- if (funcdef_flag > 0)
- require_complete_types_for_parms (last_function_parms);
-
return result;
}
parmtype = TREE_VALUE (parmtypes);
}
+ /* [class.copy]
+
+ A non-template constructor for class X is a copy constructor if
+ its first parameter is of type X&, const X&, volatile X& or const
+ volatile X&, and either there are no other parameters or else all
+ other parameters have default arguments. */
if (TREE_CODE (parmtype) == REFERENCE_TYPE
&& TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == ctype
&& (TREE_CHAIN (parmtypes) == NULL_TREE
|| TREE_CHAIN (parmtypes) == void_list_node
- || TREE_PURPOSE (TREE_CHAIN (parmtypes))))
+ || TREE_PURPOSE (TREE_CHAIN (parmtypes)))
+ && !(DECL_TEMPLATE_INSTANTIATION (decl)
+ && is_member_template (DECL_TI_TEMPLATE (decl))))
{
TYPE_HAS_INIT_REF (ctype) = 1;
- if (TYPE_READONLY (TREE_TYPE (parmtype)))
+ if (CP_TYPE_CONST_P (TREE_TYPE (parmtype)))
TYPE_HAS_CONST_INIT_REF (ctype) = 1;
}
+ /* [class.copy]
+
+ A declaration of a constructor for a class X is ill-formed if its
+ first parameter is of type (optionally cv-qualified) X and either
+ there are no other parameters or else all other parameters have
+ default arguments.
+
+ We *don't* complain about member template instantiations that
+ have this form, though; they can occur as we try to decide what
+ constructor to use during overload resolution. Since overload
+ resolution will never prefer such a constructor to the
+ non-template copy constructor (which is either explicitly or
+ implicitly defined), there's no need to worry about their
+ existence. Theoretically, they should never even be
+ instantiated, but that's hard to forestall. */
else if (TYPE_MAIN_VARIANT (parmtype) == ctype
- && TREE_CHAIN (parmtypes) != NULL_TREE
- && TREE_CHAIN (parmtypes) == void_list_node)
+ && (TREE_CHAIN (parmtypes) == NULL_TREE
+ || TREE_CHAIN (parmtypes) == void_list_node
+ || TREE_PURPOSE (TREE_CHAIN (parmtypes)))
+ && !(DECL_TEMPLATE_INSTANTIATION (decl)
+ && is_member_template (DECL_TI_TEMPLATE (decl))))
{
cp_error ("invalid constructor; you probably meant `%T (const %T&)'",
ctype, ctype);
if (! friendp)
{
- if (name == ansi_opname[(int) MODIFY_EXPR])
+ /* [class.copy]
+
+ A user-declared copy assignment operator X::operator= is a
+ non-static non-template member function of class X with
+ exactly one parameter of type X, X&, const X&, volatile X& or
+ const volatile X&. */
+ if (name == ansi_opname[(int) MODIFY_EXPR]
+ && !(DECL_TEMPLATE_INSTANTIATION (decl)
+ && is_member_template (DECL_TI_TEMPLATE (decl))))
TYPE_HAS_ASSIGNMENT (current_class_type) = 1;
else if (name == ansi_opname[(int) CALL_EXPR])
TYPE_OVERLOADS_CALL_EXPR (current_class_type) = 1;
{
TYPE_HAS_ASSIGN_REF (current_class_type) = 1;
if (TREE_CODE (parmtype) != REFERENCE_TYPE
- || TYPE_READONLY (TREE_TYPE (parmtype)))
+ || CP_TYPE_CONST_P (TREE_TYPE (parmtype)))
TYPE_HAS_CONST_ASSIGN_REF (current_class_type) = 1;
}
}
if (list_length (argtypes) == 2)
{
if (TREE_CODE (ret) != REFERENCE_TYPE
- || !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ret)),
- arg, 1))
+ || !same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (ret)),
+ arg))
cp_warning ("prefix `%D' should return `%T'", decl,
build_reference_type (arg));
}
else
{
- if (!comptypes (TYPE_MAIN_VARIANT (ret), arg, 1))
+ if (!same_type_p (TYPE_MAIN_VARIANT (ret), arg))
cp_warning ("postfix `%D' should return `%T'", decl, arg);
}
}
}
}
\f
+static char *
+tag_name (code)
+ enum tag_types code;
+{
+ switch (code)
+ {
+ case record_type:
+ return "struct";
+ case class_type:
+ return "class";
+ case union_type:
+ return "union ";
+ case enum_type:
+ return "enum";
+ case signature_type:
+ return "signature";
+ default:
+ my_friendly_abort (981122);
+ }
+}
+
/* Get the struct, enum or union (CODE says which) with tag NAME.
Define the tag as a forward-reference if it is not defined.
}
else
t = IDENTIFIER_TYPE_VALUE (name);
+
if (t && TREE_CODE (t) != code && TREE_CODE (t) != TEMPLATE_TYPE_PARM
&& TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM)
t = NULL_TREE;
if (! globalize)
{
- if (t && (TREE_CODE (t) == TEMPLATE_TYPE_PARM
- || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM))
- {
- cp_error ("redeclaration of template type-parameter `%T'", name);
- cp_error_at (" previously declared here `%#D'",
- TEMPLATE_TYPE_DECL (t));
- }
- if (t && TYPE_CONTEXT (t) && got_type)
- ref = t;
- else
- /* If we know we are defining this tag, only look it up in
- this scope and don't try to find it as a type. */
- ref = lookup_tag (code, name, b, 1);
+ /* If we know we are defining this tag, only look it up in
+ this scope and don't try to find it as a type. */
+ ref = lookup_tag (code, name, b, 1);
}
else
{
else
{
if (t)
- ref = t;
+ {
+ if (t != TYPE_MAIN_VARIANT (t))
+ cp_pedwarn ("using typedef-name `%D' after `%s'",
+ TYPE_NAME (t), tag_name (tag_code));
+ ref = t;
+ }
else
ref = lookup_tag (code, name, b, 0);
TREE_TYPE (ref) = attributes;
+ if (ref && TYPE_P (ref))
+ {
+ /* [dcl.type.elab]
+
+ If the identifier resolves to a typedef-name or a template
+ type-parameter, the elaborated-type-specifier is
+ ill-formed. */
+ if (TYPE_LANG_SPECIFIC (ref) && TYPE_WAS_ANONYMOUS (ref))
+ cp_error ("`%T' is a typedef name", ref);
+ else if (TREE_CODE (ref) == TEMPLATE_TYPE_PARM)
+ cp_error ("`%T' is a template type paramter", ref);
+ }
+
return ref;
}
individual inheritance contains flags which say what
the `accessibility' of that particular inheritance is.) */
- base_binfo = make_binfo (integer_zero_node, basetype,
- TYPE_BINFO_VTABLE (basetype),
- TYPE_BINFO_VIRTUALS (basetype));
+ base_binfo
+ = make_binfo (integer_zero_node, basetype,
+ CLASS_TYPE_P (basetype)
+ ? TYPE_BINFO_VTABLE (basetype) : NULL_TREE,
+ CLASS_TYPE_P (basetype)
+ ? TYPE_BINFO_VIRTUALS (basetype) : NULL_TREE);
TREE_VEC_ELT (binfos, i) = base_binfo;
TREE_VIA_PUBLIC (base_binfo) = via_public;
TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
}
- TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype);
- TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype);
- CLASSTYPE_LOCAL_TYPEDECLS (ref) |= CLASSTYPE_LOCAL_TYPEDECLS (basetype);
+ if (CLASS_TYPE_P (basetype))
+ {
+ TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype);
+ TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype);
+ }
+
i += 1;
}
}
if (i > 1)
TYPE_USES_MULTIPLE_INHERITANCE (ref) = 1;
else if (i == 1)
- TYPE_USES_MULTIPLE_INHERITANCE (ref)
- = TYPE_USES_MULTIPLE_INHERITANCE (BINFO_TYPE (TREE_VEC_ELT (binfos, 0)));
+ {
+ tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, 0));
+
+ if (CLASS_TYPE_P (basetype))
+ TYPE_USES_MULTIPLE_INHERITANCE (ref)
+ = TYPE_USES_MULTIPLE_INHERITANCE (basetype);
+ }
+
if (TYPE_USES_MULTIPLE_INHERITANCE (ref))
TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
}
\f
-tree current_local_enum = NULL_TREE;
-
/* Begin compiling the definition of an enumeration type.
NAME is its name (or null if anonymous).
Returns the type object, as yet incomplete.
/* We are wasting space here and putting these on the permanent_obstack so
that typeid(local enum) will work correctly. */
-#if 0
- if (processing_template_decl && current_function_decl)
-#endif
-
- end_temporary_allocation ();
+ push_obstacks (&permanent_obstack, &permanent_obstack);
/* If this is the real definition for a previous forward reference,
fill in the contents in the same object that used to be the
if (current_class_type)
TREE_ADDRESSABLE (b->tags) = 1;
- current_local_enum = NULL_TREE;
-
/* We don't copy this value because build_enumerator needs to do it. */
enum_next_value = integer_zero_node;
enum_overflow = 0;
{
tree scope = current_scope ();
if (scope && TREE_CODE (scope) == FUNCTION_DECL)
- {
- add_tree (build_min (TAG_DEFN, enumtype));
- resume_temporary_allocation ();
- }
- return enumtype;
+ add_tree (build_min (TAG_DEFN, enumtype));
}
+ else
+ {
+ int unsignedp = tree_int_cst_sgn (minnode) >= 0;
+ int lowprec = min_precision (minnode, unsignedp);
+ int highprec = min_precision (maxnode, unsignedp);
+ int precision = MAX (lowprec, highprec);
+ tree tem;
- {
- int unsignedp = tree_int_cst_sgn (minnode) >= 0;
- int lowprec = min_precision (minnode, unsignedp);
- int highprec = min_precision (maxnode, unsignedp);
- int precision = MAX (lowprec, highprec);
-
- TYPE_SIZE (enumtype) = NULL_TREE;
-
- /* Set TYPE_MIN_VALUE and TYPE_MAX_VALUE according to `precision'. */
+ TYPE_SIZE (enumtype) = NULL_TREE;
- TYPE_PRECISION (enumtype) = precision;
- if (unsignedp)
- fixup_unsigned_type (enumtype);
- else
- fixup_signed_type (enumtype);
+ /* Set TYPE_MIN_VALUE and TYPE_MAX_VALUE according to `precision'. */
- if (flag_short_enums || (precision > TYPE_PRECISION (integer_type_node)))
- /* Use the width of the narrowest normal C type which is wide enough. */
- TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size
- (precision, 1));
- else
- TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
+ TYPE_PRECISION (enumtype) = precision;
+ if (unsignedp)
+ fixup_unsigned_type (enumtype);
+ else
+ fixup_signed_type (enumtype);
- TYPE_SIZE (enumtype) = 0;
- layout_type (enumtype);
- }
+ if (flag_short_enums || (precision > TYPE_PRECISION (integer_type_node)))
+ /* Use the width of the narrowest normal C type which is wide
+ enough. */
+ TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size
+ (precision, 1));
+ else
+ TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
- {
- register tree tem;
+ TYPE_SIZE (enumtype) = 0;
+ layout_type (enumtype);
- /* Fix up all variant types of this enum type. */
- for (tem = TYPE_MAIN_VARIANT (enumtype); tem;
- tem = TYPE_NEXT_VARIANT (tem))
- {
- TYPE_VALUES (tem) = TYPE_VALUES (enumtype);
- TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
- TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
- TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
- TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype);
- TYPE_MODE (tem) = TYPE_MODE (enumtype);
- TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
- TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
- TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype);
- }
- }
+ /* Fix up all variant types of this enum type. */
+ for (tem = TYPE_MAIN_VARIANT (enumtype); tem;
+ tem = TYPE_NEXT_VARIANT (tem))
+ {
+ TYPE_VALUES (tem) = TYPE_VALUES (enumtype);
+ TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
+ TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
+ TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
+ TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype);
+ TYPE_MODE (tem) = TYPE_MODE (enumtype);
+ TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
+ TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
+ TREE_UNSIGNED (tem) = TREE_UNSIGNED (enumtype);
+ }
+
+ /* Finish debugging output for this type. */
+ rest_of_type_compilation (enumtype, namespace_bindings_p ());
+ }
- /* Finish debugging output for this type. */
- rest_of_type_compilation (enumtype, namespace_bindings_p ());
+ /* In start_enum we pushed obstacks. Here, we must pop them. */
+ pop_obstacks ();
return enumtype;
}
if (context && context == current_class_type)
{
pushdecl_class_level (decl);
- TREE_CHAIN (decl) = current_local_enum;
- current_local_enum = decl;
+ /* In something like `struct S { enum E { i = 7 }; };' we put `i'
+ on the TYPE_FIELDS list for `S'. (That's so that you can say
+ things like `S::i' later.) */
+ finish_member_declaration (decl);
}
else
{
return result;
}
-/* Called after we have finished the declaration of an enumeration
- type, and, perhaps, some objects whose type involves the
- enumeration type. DECL, if non-NULL, is the declaration of the
- first such object.
-
- If CURRENT_LOCAL_ENUM is NULL, the DECL is returned.
-
- If CURRENT_LOCAL_ENUM is non-NULL, it should be the CONST_DECL for
- the last enumeration constant of an enumeration type that is a
- member of a class. The enumeration constants are already chained
- together through their TREE_CHAIN fields. This function sets the
- TREE_CHAIN of the last enumeration constant to DECL. The
- CONST_DECL for the last enumeration constant is returned.
-
- CURRENT_LOCAL_ENUM will always be NULL when this function
- returns. */
-
-tree
-grok_enum_decls (decl)
- tree decl;
-{
- tree d = current_local_enum;
-
- if (d == NULL_TREE)
- return decl;
-
- while (1)
- {
- if (TREE_CHAIN (d) == NULL_TREE)
- {
- TREE_CHAIN (d) = decl;
- break;
- }
- d = TREE_CHAIN (d);
- }
-
- decl = current_local_enum;
- current_local_enum = NULL_TREE;
-
- return decl;
-}
\f
static int function_depth;
they describe the function's name and the type it returns,
but twisted together in a fashion that parallels the syntax of C.
+ If PRE_PARSED_P is non-zero then DECLARATOR is really the DECL for
+ the function we are about to process; DECLSPECS are ignored. For
+ example, we set PRE_PARSED_P when processing the definition of
+ inline function that was defined in-class; the definition is
+ actually processed when the class is complete. In this case,
+ PRE_PARSED_P is 2. We also set PRE_PARSED_P when instanting the
+ body of a template function, and when constructing thunk functions
+ and such; in these cases PRE_PARSED_P is 1.
+
This function creates a binding context for the function body
as well as setting up the FUNCTION_DECL in current_function_decl.
/* Assume, until we see it does. */
current_function_returns_value = 0;
current_function_returns_null = 0;
- warn_about_return_type = 0;
named_labels = 0;
shadowed_labels = 0;
current_function_assigns_this = 0;
doing_friend = 1;
}
- /* In a fcn definition, arg types must be complete. */
- require_complete_types_for_parms (DECL_ARGUMENTS (decl1));
-
- /* In case some arg types were completed since the declaration was
- parsed, fix up the decls. */
- {
- tree t = DECL_ARGUMENTS (decl1);
- for (; t; t = TREE_CHAIN (t))
- layout_decl (t, 0);
- }
-
last_function_parms = DECL_ARGUMENTS (decl1);
last_function_parm_tags = NULL_TREE;
}
fntype = TREE_TYPE (decl1);
restype = TREE_TYPE (fntype);
- if (IS_AGGR_TYPE (restype) && ! TYPE_PTRMEMFUNC_P (restype)
- && ! CLASSTYPE_GOT_SEMICOLON (restype))
+ if (CLASS_TYPE_P (restype) && !CLASSTYPE_GOT_SEMICOLON (restype))
{
cp_error ("semicolon missing after declaration of `%#T'", restype);
shadow_tag (build_expr_list (NULL_TREE, restype));
pedwarn ("return type for `main' changed to `int'");
TREE_TYPE (decl1) = fntype = default_function_type;
}
- warn_about_return_type = 0;
}
}
&& IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)) != NULL_TREE)
cp_warning_at ("`%D' implicitly declared before its definition", IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)));
+ announce_function (decl1);
+
+ /* Set up current_class_type, and enter the scope of the class, if
+ appropriate. */
+ if (ctype)
+ push_nested_class (ctype, 1);
+ else if (DECL_STATIC_FUNCTION_P (decl1))
+ push_nested_class (DECL_CONTEXT (decl1), 2);
+
+ /* Now that we have entered the scope of the class, we must restore
+ the bindings for any template parameters surrounding DECL1, if it
+ is an inline member template. (Order is important; consider the
+ case where a template parameter has the same name as a field of
+ the class.) It is not until after this point that
+ PROCESSING_TEMPLATE_DECL is guaranteed to be set up correctly. */
+ if (pre_parsed_p == 2)
+ maybe_begin_member_template_processing (decl1);
+
+ /* We are now in the scope of the function being defined. */
current_function_decl = decl1;
+
/* Save the parm names or decls from this function's declarator
where store_parm_decls will find them. */
current_function_parms = last_function_parms;
current_function_parm_tags = last_function_parm_tags;
- announce_function (decl1);
-
if (! processing_template_decl)
{
+ /* In a fcn definition, arg types must be complete. */
+ require_complete_types_for_parms (DECL_ARGUMENTS (decl1));
+
if (TYPE_SIZE (complete_type (TREE_TYPE (fntype))) == NULL_TREE)
{
cp_error ("return-type `%#T' is an incomplete type",
TYPE_ARG_TYPES (TREE_TYPE (decl1)));
DECL_RESULT (decl1)
= build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (fntype)));
- TREE_READONLY (DECL_RESULT (decl1)) = TYPE_READONLY (TREE_TYPE (fntype));
- TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = TYPE_VOLATILE (TREE_TYPE (fntype));
+ TREE_READONLY (DECL_RESULT (decl1))
+ = CP_TYPE_CONST_P (TREE_TYPE (fntype));
+ TREE_THIS_VOLATILE (DECL_RESULT (decl1))
+ = CP_TYPE_VOLATILE_P (TREE_TYPE (fntype));
}
if (TYPE_LANG_SPECIFIC (TREE_TYPE (fntype))
abstract_virtuals_error (decl1, TREE_TYPE (fntype));
}
- if (warn_about_return_type)
- pedwarn ("return-type defaults to `int'");
-
/* Effective C++ rule 15. See also c_expand_return. */
if (warn_ecpp
&& DECL_NAME (decl1) == ansi_opname[(int) MODIFY_EXPR]
error_mark_node is replaced below (in poplevel) with the BLOCK. */
DECL_INITIAL (decl1) = error_mark_node;
+#ifdef SET_DEFAULT_DECL_ATTRIBUTES
+ SET_DEFAULT_DECL_ATTRIBUTES (decl1, attrs);
+#endif
+
/* This function exists in static storage.
(This does not mean `static' in the C sense!) */
TREE_STATIC (decl1) = 1;
- /* Set up current_class_type, and enter the scope of the class, if
- appropriate. */
- if (ctype)
- push_nested_class (ctype, 1);
- else if (DECL_STATIC_FUNCTION_P (decl1))
- push_nested_class (DECL_CONTEXT (decl1), 2);
-
/* We must call push_template_decl after current_class_type is set
up. (If we are processing inline definitions after exiting a
class scope, current_class_type will be NULL_TREE until set above
if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
{
- int i = suspend_momentary ();
+ int i;
- /* Fool build_indirect_ref. */
+ if (! hack_decl_function_context (decl1))
+ temporary_allocation ();
+ i = suspend_momentary ();
+
+ /* Normally, build_indirect_ref returns
+ current_class_ref whenever current_class_ptr is
+ dereferenced. This time, however, we want it to
+ *create* current_class_ref, so we temporarily clear
+ current_class_ptr to fool it. */
current_class_ptr = NULL_TREE;
current_class_ref = build_indirect_ref (t, NULL_PTR);
current_class_ptr = t;
+
resume_momentary (i);
+ if (! hack_decl_function_context (decl1))
+ end_temporary_allocation ();
}
else
/* We're having a signature pointer here. */
}
}
else
- {
- current_class_ptr = current_class_ref = NULL_TREE;
- }
+ current_class_ptr = current_class_ref = NULL_TREE;
pushlevel (0);
current_binding_level->parm_flag = 1;
if (attrs)
cplus_decl_attributes (decl1, NULL_TREE, attrs);
+
make_function_rtl (decl1);
/* Promote the value to int before returning it. */
{
DECL_RESULT (decl1)
= build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (restype));
- TREE_READONLY (DECL_RESULT (decl1)) = TYPE_READONLY (restype);
- TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = TYPE_VOLATILE (restype);
+ TREE_READONLY (DECL_RESULT (decl1)) = CP_TYPE_CONST_P (restype);
+ TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = CP_TYPE_VOLATILE_P (restype);
}
/* Allocate further tree nodes temporarily during compilation
/* Initialize RTL machinery. */
init_function_start (fndecl, input_filename, lineno);
- /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */
- declare_function_name ();
-
/* Create a binding level for the parms. */
expand_start_bindings (0);
storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
+ /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function. */
+ declare_function_name ();
+
/* Initialize the RTL code for the function. */
DECL_SAVED_INSNS (fndecl) = NULL_RTX;
if (! processing_template_decl)
This is called after parsing the body of the function definition.
LINENO is the current line number.
- C++: CALL_POPLEVEL is non-zero if an extra call to poplevel
- (and expand_end_bindings) must be made to take care of the binding
- contour for the base initializers. This is only relevant for
- constructors.
+ FLAGS is a bitwise or of the following values:
+ 1 - CALL_POPLEVEL
+ An extra call to poplevel (and expand_end_bindings) must be
+ made to take care of the binding contour for the base
+ initializers. This is only relevant for constructors.
+ 2 - INCLASS_INLINE
+ We just finished processing the body of an in-class inline
+ function definition. (This processing will have taken place
+ after the class definition is complete.)
NESTED is nonzero if we were in the middle of compiling another function
when we started on this one. */
void
-finish_function (lineno, call_poplevel, nested)
+finish_function (lineno, flags, nested)
int lineno;
- int call_poplevel;
+ int flags;
int nested;
{
register tree fndecl = current_function_decl;
/* Label to use if this function is supposed to return a value. */
tree no_return_label = NULL_TREE;
tree decls = NULL_TREE;
+ int call_poplevel = (flags & 1) != 0;
+ int inclass_inline = (flags & 2) != 0;
+ int in_template;
/* When we get some parse errors, we can end up without a
current_function_decl, so cope. */
pointer to represent the type of our base class. */
/* This side-effect makes call to `build_delete' generate the
- code we have to have at the end of this destructor. */
+ code we have to have at the end of this destructor.
+ `build_delete' will set the flag again. */
TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
/* These are two cases where we cannot delegate deletion. */
expand_end_cond ();
}
- TYPE_HAS_DESTRUCTOR (current_class_type) = 1;
-
virtual_size = c_sizeof (current_class_type);
/* At the end, call delete if that's what's requested. */
/* End of destructor. */
expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0);
- poplevel (2, 0, 0); /* XXX change to 1 */
+ poplevel (getdecls () != NULL_TREE, 0, 0);
/* Back to the top of destructor. */
/* Don't execute destructor code if `this' is NULL. */
/* Generate rtl for function exit. */
expand_function_end (input_filename, lineno, 1);
}
+
+ /* Must mark the RESULT_DECL as being in this function. */
+ DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
+
+ /* Set the BLOCK_SUPERCONTEXT of the outermost function scope to point
+ to the FUNCTION_DECL node itself. */
+ BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
+
+ /* If we're processing a template, squirrel away the definition
+ until we do an instantiation. */
+ if (processing_template_decl)
+ {
+ --minimal_parse_mode;
+ DECL_SAVED_TREE (fndecl) = TREE_CHAIN (DECL_SAVED_TREE (fndecl));
+ /* We have to save this value here in case
+ maybe_end_member_template_processing decides to pop all the
+ template parameters. */
+ in_template = 1;
+ }
+ else
+ in_template = 0;
/* This must come after expand_function_end because cleanups might
have declarations (from inline functions) that need to go into
my_friendly_abort (122);
poplevel (1, 0, 1);
+ /* If this is a in-class inline definition, we may have to pop the
+ bindings for the template parameters that we added in
+ maybe_begin_member_template_processing when start_function was
+ called. */
+ if (inclass_inline)
+ maybe_end_member_template_processing ();
+
/* Reset scope for C++: if we were in the scope of a class,
then when we finish this function, we are not longer so.
This cannot be done until we know for sure that no more
pop_nested_class (1);
}
- /* Must mark the RESULT_DECL as being in this function. */
- DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
-
- /* Set the BLOCK_SUPERCONTEXT of the outermost function scope to point
- to the FUNCTION_DECL node itself. */
- BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
-
- if (! processing_template_decl)
+ if (!in_template)
{
int saved_flag_keep_inline_functions =
flag_keep_inline_functions;
/* Free all the tree nodes making up this function. */
/* Switch back to allocating nodes permanently
until we start another function. */
- if (processing_template_decl)
- {
- --minimal_parse_mode;
- DECL_SAVED_TREE (fndecl) = TREE_CHAIN (DECL_SAVED_TREE (fndecl));
- }
-
if (! nested)
permanent_allocation (1);
}
\f
/* Create the FUNCTION_DECL for a function definition.
- LINE1 is the line number that the definition absolutely begins on.
- LINE2 is the line number that the name of the function appears on.
DECLSPECS and DECLARATOR are the parts of the declaration;
they describe the return type and the name of the function,
but twisted together in a fashion that parallels the syntax of C.
CHANGES TO CODE IN `grokfield'. */
tree
-start_method (declspecs, declarator)
- tree declarator, declspecs;
+start_method (declspecs, declarator, attrlist)
+ tree declarator, declspecs, attrlist;
{
tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0,
- NULL_TREE);
+ attrlist);
/* Something too ugly to handle. */
if (fndecl == NULL_TREE)
return void_type_node;
}
+ check_template_shadow (fndecl);
+
DECL_THIS_INLINE (fndecl) = 1;
if (flag_default_inline)
for (link = current_binding_level->names; link; link = TREE_CHAIN (link))
{
if (DECL_NAME (link) != NULL_TREE)
- IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0;
+ pop_binding (DECL_NAME (link));
my_friendly_assert (TREE_CODE (link) != FUNCTION_DECL, 163);
DECL_CONTEXT (link) = NULL_TREE;
}
- /* Restore all name-meanings of the outer levels
- that were shadowed by this level. */
-
- for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
- IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
- for (link = current_binding_level->class_shadowed;
- link; link = TREE_CHAIN (link))
- IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
- for (link = current_binding_level->type_shadowed;
- link; link = TREE_CHAIN (link))
- SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link));
-
GNU_xref_end_scope ((HOST_WIDE_INT) current_binding_level,
(HOST_WIDE_INT) current_binding_level->level_chain,
current_binding_level->parm_flag,
if (TREE_TYPE (exp) == unknown_type_node)
{
- if (TREE_CODE (exp) == ADDR_EXPR || TREE_CODE (exp) == TREE_LIST)
+ if (TREE_CODE (exp) == COMPONENT_REF)
+ error ("invalid reference to a member function name, did you forget the ()?");
+ else
error ("address of overloaded function with no contextual type information");
- else if (TREE_CODE (exp) == COMPONENT_REF)
- warning ("useless reference to a member function name, did you forget the ()?");
}
else
{
tree function = fn ? *fn : TREE_TYPE (*decl);
tree args = argtypes ? *argtypes : TYPE_ARG_TYPES (function);
- if (TYPE_READONLY (TREE_TYPE (TREE_VALUE (args))))
- cp_error ("static member function `%#D' declared const", *decl);
- if (TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (args))))
- cp_error ("static member function `%#D' declared volatile", *decl);
+ if (CP_TYPE_QUALS (TREE_TYPE (TREE_VALUE (args)))
+ != TYPE_UNQUALIFIED)
+ cp_error ("static member function `%#D' declared with type qualifiers",
+ *decl);
args = TREE_CHAIN (args);
tmp = build_function_type (TREE_TYPE (function), args);
- tmp = build_type_variant (tmp, TYPE_READONLY (function),
- TYPE_VOLATILE (function));
+ tmp = build_qualified_type (tmp, CP_TYPE_QUALS (function));
tmp = build_exception_variant (tmp,
TYPE_RAISES_EXCEPTIONS (function));
TREE_TYPE (*decl) = tmp;
{
int returns_value;
int returns_null;
- int warn_about_return_type;
int assigns_this;
int just_assigned_this;
int parms_stored;
int temp_name_counter;
tree named_labels;
+ struct named_label_list *named_label_uses;
tree shadowed_labels;
tree ctor_label;
tree dtor_label;
cp_function_chain = p;
p->named_labels = named_labels;
+ p->named_label_uses = named_label_uses;
p->shadowed_labels = shadowed_labels;
p->returns_value = current_function_returns_value;
p->returns_null = current_function_returns_null;
- p->warn_about_return_type = warn_about_return_type;
p->binding_level = current_binding_level;
p->ctor_label = ctor_label;
p->dtor_label = dtor_label;
cp_function_chain = p->next;
named_labels = p->named_labels;
+ named_label_uses = p->named_label_uses;
shadowed_labels = p->shadowed_labels;
current_function_returns_value = p->returns_value;
current_function_returns_null = p->returns_null;
- warn_about_return_type = p->warn_about_return_type;
current_binding_level = p->binding_level;
ctor_label = p->ctor_label;
dtor_label = p->dtor_label;