#include "tree-inline.h"
#include "tree-mudflap.h"
#include "except.h"
-#include "lex.h"
#include "toplev.h"
#include "flags.h"
#include "rtl.h"
#include "diagnostic.h"
#include "cgraph.h"
#include "tree-iterator.h"
+#include "vec.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
In case of parsing error, we simply call `pop_deferring_access_checks'
without `perform_deferred_access_checks'. */
+typedef struct deferred_access GTY(())
+{
+ /* A TREE_LIST representing name-lookups for which we have deferred
+ checking access controls. We cannot check the accessibility of
+ names used in a decl-specifier-seq until we know what is being
+ declared because code like:
+
+ class A {
+ class B {};
+ B* f();
+ }
+
+ A::B* A::f() { return 0; }
+
+ is valid, even though `A::B' is not generally accessible.
+
+ The TREE_PURPOSE of each node is the scope used to qualify the
+ name being looked up; the TREE_VALUE is the DECL to which the
+ name was resolved. */
+ tree deferred_access_checks;
+
+ /* The current mode of access checks. */
+ enum deferring_kind deferring_access_checks_kind;
+
+} deferred_access;
+DEF_VEC_O (deferred_access);
+
/* Data for deferred access checking. */
-static GTY(()) deferred_access *deferred_access_stack;
-static GTY(()) deferred_access *deferred_access_free_list;
+static GTY(()) VEC (deferred_access) *deferred_access_stack;
+static GTY(()) unsigned deferred_access_no_check;
/* Save the current deferred access states and start deferred
access checking iff DEFER_P is true. */
void
push_deferring_access_checks (deferring_kind deferring)
{
- deferred_access *d;
-
/* For context like template instantiation, access checking
disabling applies to all nested context. */
- if (deferred_access_stack
- && deferred_access_stack->deferring_access_checks_kind == dk_no_check)
- deferring = dk_no_check;
-
- /* Recycle previously used free store if available. */
- if (deferred_access_free_list)
- {
- d = deferred_access_free_list;
- deferred_access_free_list = d->next;
- }
+ if (deferred_access_no_check || deferring == dk_no_check)
+ deferred_access_no_check++;
else
- d = ggc_alloc (sizeof (deferred_access));
+ {
+ deferred_access *ptr;
- d->next = deferred_access_stack;
- d->deferred_access_checks = NULL_TREE;
- d->deferring_access_checks_kind = deferring;
- deferred_access_stack = d;
+ ptr = VEC_safe_push (deferred_access, deferred_access_stack, NULL);
+ ptr->deferred_access_checks = NULL_TREE;
+ ptr->deferring_access_checks_kind = deferring;
+ }
}
/* Resume deferring access checks again after we stopped doing
void
resume_deferring_access_checks (void)
{
- if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
- deferred_access_stack->deferring_access_checks_kind = dk_deferred;
+ if (!deferred_access_no_check)
+ VEC_last (deferred_access, deferred_access_stack)
+ ->deferring_access_checks_kind = dk_deferred;
}
/* Stop deferring access checks. */
void
stop_deferring_access_checks (void)
{
- if (deferred_access_stack->deferring_access_checks_kind == dk_deferred)
- deferred_access_stack->deferring_access_checks_kind = dk_no_deferred;
+ if (!deferred_access_no_check)
+ VEC_last (deferred_access, deferred_access_stack)
+ ->deferring_access_checks_kind = dk_no_deferred;
}
/* Discard the current deferred access checks and restore the
void
pop_deferring_access_checks (void)
{
- deferred_access *d = deferred_access_stack;
- deferred_access_stack = d->next;
-
- /* Remove references to access checks TREE_LIST. */
- d->deferred_access_checks = NULL_TREE;
-
- /* Store in free list for later use. */
- d->next = deferred_access_free_list;
- deferred_access_free_list = d;
+ if (deferred_access_no_check)
+ deferred_access_no_check--;
+ else
+ VEC_pop (deferred_access, deferred_access_stack);
}
/* Returns a TREE_LIST representing the deferred checks.
tree
get_deferred_access_checks (void)
{
- return deferred_access_stack->deferred_access_checks;
+ if (deferred_access_no_check)
+ return NULL;
+ else
+ return (VEC_last (deferred_access, deferred_access_stack)
+ ->deferred_access_checks);
}
/* Take current deferred checks and combine with the
void
pop_to_parent_deferring_access_checks (void)
{
- tree deferred_check = get_deferred_access_checks ();
- deferred_access *d1 = deferred_access_stack;
- deferred_access *d2 = deferred_access_stack->next;
- deferred_access *d3 = deferred_access_stack->next->next;
-
- /* Temporary swap the order of the top two states, just to make
- sure the garbage collector will not reclaim the memory during
- processing below. */
- deferred_access_stack = d2;
- d2->next = d1;
- d1->next = d3;
+ if (deferred_access_no_check)
+ deferred_access_no_check--;
+ else
+ {
+ tree checks;
+ deferred_access *ptr;
- for ( ; deferred_check; deferred_check = TREE_CHAIN (deferred_check))
- /* Perform deferred check if required. */
- perform_or_defer_access_check (TREE_PURPOSE (deferred_check),
- TREE_VALUE (deferred_check));
+ checks = (VEC_last (deferred_access, deferred_access_stack)
+ ->deferred_access_checks);
- deferred_access_stack = d1;
- d1->next = d2;
- d2->next = d3;
- pop_deferring_access_checks ();
+ VEC_pop (deferred_access, deferred_access_stack);
+ ptr = VEC_last (deferred_access, deferred_access_stack);
+ if (ptr->deferring_access_checks_kind == dk_no_deferred)
+ {
+ /* Check access. */
+ for (; checks; checks = TREE_CHAIN (checks))
+ enforce_access (TREE_PURPOSE (checks),
+ TREE_VALUE (checks));
+ }
+ else
+ {
+ /* Merge with parent. */
+ tree next;
+ tree original = ptr->deferred_access_checks;
+
+ for (; checks; checks = next)
+ {
+ tree probe;
+
+ next = TREE_CHAIN (checks);
+
+ for (probe = original; probe; probe = TREE_CHAIN (probe))
+ if (TREE_VALUE (probe) == TREE_VALUE (checks)
+ && TREE_PURPOSE (probe) == TREE_PURPOSE (checks))
+ goto found;
+ /* Insert into parent's checks. */
+ TREE_CHAIN (checks) = ptr->deferred_access_checks;
+ ptr->deferred_access_checks = checks;
+ found:;
+ }
+ }
+ }
}
/* Perform the deferred access checks.
perform_deferred_access_checks (void)
{
tree deferred_check;
- for (deferred_check = deferred_access_stack->deferred_access_checks;
+
+ for (deferred_check = (VEC_last (deferred_access, deferred_access_stack)
+ ->deferred_access_checks);
deferred_check;
deferred_check = TREE_CHAIN (deferred_check))
/* Check access. */
perform_or_defer_access_check (tree binfo, tree decl)
{
tree check;
+ deferred_access *ptr;
- my_friendly_assert (TREE_CODE (binfo) == TREE_VEC, 20030623);
+ /* Exit if we are in a context that no access checking is performed.
+ */
+ if (deferred_access_no_check)
+ return;
+
+ my_friendly_assert (TREE_CODE (binfo) == TREE_BINFO, 20030623);
+
+ ptr = VEC_last (deferred_access, deferred_access_stack);
/* If we are not supposed to defer access checks, just check now. */
- if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
+ if (ptr->deferring_access_checks_kind == dk_no_deferred)
{
enforce_access (binfo, decl);
return;
}
- /* Exit if we are in a context that no access checking is performed. */
- else if (deferred_access_stack->deferring_access_checks_kind == dk_no_check)
- return;
-
+
/* See if we are already going to perform this check. */
- for (check = deferred_access_stack->deferred_access_checks;
+ for (check = ptr->deferred_access_checks;
check;
check = TREE_CHAIN (check))
if (TREE_VALUE (check) == decl && TREE_PURPOSE (check) == binfo)
return;
/* If not, record the check. */
- deferred_access_stack->deferred_access_checks
- = tree_cons (binfo, decl,
- deferred_access_stack->deferred_access_checks);
+ ptr->deferred_access_checks
+ = tree_cons (binfo, decl, ptr->deferred_access_checks);
}
/* Returns nonzero if the current statement is a full expression,
/* Create a declaration statement for the declaration given by the DECL. */
void
-add_decl_stmt (tree decl)
+add_decl_expr (tree decl)
{
- tree r = build_stmt (DECL_STMT, decl);
+ tree r = build_stmt (DECL_EXPR, decl);
if (DECL_INITIAL (decl))
r = maybe_cleanup_point_expr (r);
add_stmt (r);
/* Begin a conditional that might contain a declaration. When generating
normal code, we want the declaration to appear before the statement
containing the conditional. When generating template code, we want the
- conditional to be rendered as the raw DECL_STMT. */
+ conditional to be rendered as the raw DECL_EXPR. */
static void
begin_cond (tree *cond_p)
if (processing_template_decl)
{
tree cond = pop_stmt_list (*cond_p);
- if (TREE_CODE (cond) == DECL_STMT)
+ if (TREE_CODE (cond) == DECL_EXPR)
expr = cond;
}
*cond_p = expr;
finish_label_decl (tree name)
{
tree decl = declare_local_label (name);
- add_decl_stmt (decl);
+ add_decl_expr (decl);
}
/* When DECL goes out of scope, make sure that CLEANUP is executed. */
type = cp_build_qualified_type (type, quals);
}
- return build_min (COMPONENT_REF, type, object, decl);
+ return build_min (COMPONENT_REF, type, object, decl, NULL_TREE);
}
else
{
{
tree scope;
tree qualifying_type = NULL_TREE;
+
+ /* If we're not checking, return imediately. */
+ if (deferred_access_no_check)
+ return;
/* Determine the SCOPE of DECL. */
scope = context_for_name_lookup (decl);
return decl;
}
-/* Begin a function definition declared with DECL_SPECS, ATTRIBUTES,
- and DECLARATOR. Returns nonzero if the function-declaration is
- valid. */
-
-int
-begin_function_definition (tree decl_specs, tree attributes, tree declarator)
-{
- if (!start_function (decl_specs, declarator, attributes, SF_DEFAULT))
- return 0;
-
- /* The things we're about to see are not directly qualified by any
- template headers we've seen thus far. */
- reset_specialization ();
-
- return 1;
-}
-
/* Finish a translation unit. */
void
return argument;
}
-/* Finish a parameter list, indicated by PARMS. If ELLIPSIS is
- nonzero, the parameter list was terminated by a `...'. */
-
-tree
-finish_parmlist (tree parms, int ellipsis)
-{
- if (parms)
- {
- /* We mark the PARMS as a parmlist so that declarator processing can
- disambiguate certain constructs. */
- TREE_PARMLIST (parms) = 1;
- /* We do not append void_list_node here, but leave it to grokparms
- to do that. */
- PARMLIST_ELLIPSIS_P (parms) = ellipsis;
- }
- return parms;
-}
-
/* Begin a class definition, as indicated by T. */
tree
}
}
-/* Finish processing the declaration of a member class template
- TYPES whose template parameters are given by PARMS. */
-
-tree
-finish_member_class_template (tree types)
-{
- tree t;
-
- /* If there are declared, but undefined, partial specializations
- mixed in with the typespecs they will not yet have passed through
- maybe_process_partial_specialization, so we do that here. */
- for (t = types; t != NULL_TREE; t = TREE_CHAIN (t))
- if (IS_AGGR_TYPE_CODE (TREE_CODE (TREE_VALUE (t))))
- maybe_process_partial_specialization (TREE_VALUE (t));
-
- grok_x_components (types);
- if (TYPE_CONTEXT (TREE_VALUE (types)) != current_class_type)
- /* The component was in fact a friend declaration. We avoid
- finish_member_template_decl performing certain checks by
- unsetting TYPES. */
- types = NULL_TREE;
-
- finish_member_template_decl (types);
-
- /* As with other component type declarations, we do
- not store the new DECL on the list of
- component_decls. */
- return NULL_TREE;
-}
-
/* Finish processing a complete template declaration. The PARMS are
the template parameters. */
Return a TREE_LIST containing the ACCESS_SPECIFIER and the
BASE_CLASS, or NULL_TREE if an error occurred. The
ACCESS_SPECIFIER is one of
- access_{default,public,protected_private}[_virtual]_node.*/
+ access_{default,public,protected_private}_node. For a virtual base
+ we set TREE_TYPE. */
tree
finish_base_specifier (tree base, tree access, bool virtual_p)
base = TYPE_MAIN_VARIANT (base);
}
result = build_tree_list (access, base);
- TREE_VIA_VIRTUAL (result) = virtual_p;
+ if (virtual_p)
+ TREE_TYPE (result) = integer_type_node;
}
return result;
else if (TREE_CODE (*tp) == CLEANUP_STMT
&& CLEANUP_DECL (*tp) == dp->var)
CLEANUP_EH_ONLY (*tp) = 1;
- /* Replace the DECL_STMT for the NRV with an initialization of the
+ /* Replace the DECL_EXPR for the NRV with an initialization of the
RESULT_DECL, if needed. */
- else if (TREE_CODE (*tp) == DECL_STMT
- && DECL_STMT_DECL (*tp) == dp->var)
+ else if (TREE_CODE (*tp) == DECL_EXPR
+ && DECL_EXPR_DECL (*tp) == dp->var)
{
tree init;
if (DECL_INITIAL (dp->var)