[PATCH] Fix PR c++/29475: Incomplete template diagnostics
Simon Martin
simartin@users.sourceforge.net
Fri Dec 1 19:54:00 GMT 2006
Hello Mark.
On Tuesday 14 November 2006 05:57, you wrote:
> [...]
> > I am willing to try to change the "storage" of the deferred checks from a
> > TREE_LIST to a VEC.
>
> Thanks!
As promised, here's a patch that changes the way deferred access checks are
stored: one uses a VEC of a new 'struct deferred_access_check' instead of a
tree list. It is rather straight-forward except for the parser.c bits...
In some cases, the deferred access checks would be attached to a tree, and
would be retrieved afterwards for processing; this is not possible anymore
since we don't use a tree list anymore to store the deferred checks. To solve
this problem, I've created a hashtable of a structure that associates a VEC
of 'struct deferred_access_check' to a tree, and two accessors to add and
lookup such an association.
This is my first use of both VEC and htab_t; I hope there are no mistakes.
I've regtested this patch with no new unexpected failure on i686-pc-linux-gnu.
Is it OK?
Thanks in advance.
Best regards,
Simon
-------------- next part --------------
2006-12-01 Simon Martin <simartin@users.sourceforge.net>
PR c++/29475
* cp-tree.h (struct deferred_access_check): New structure to represent a
deferred access check. It replaces the previous representation as a tree.
(get_deferred_access_checks): Return a vector of struct
deferred_access_check instead of a tree list.
(perform_access_checks): Take a vector of struct deferred_access_check
instead of a tree list.
* semantics.c (struct deferred_access): Store the deferred access checks
as a vector of struct deferred_access_check instead of a tree list.
(push_deferring_access_checks): Handle the change in struct
deferred_access.
(get_deferred_access_checks): Likewise.
(pop_to_parent_deferring_access_checks): Likewise.
(perform_or_defer_access_check): Likewise.
(perform_access_checks): Take a vector of struct deferred_access_check
instead of a tree list.
* parser.c (struct deferred_access_check_hash_node): New structure to
associate a tree with a vector of struct deferred_access_check.
(deferred_access_check_hash, deferred_access_check_hash_node_eq): New
functions to be able to create hash table(s) of struct
deferred_access_check_hash_node.
(deferred_access_checks_hash): New hashtable used to store tree / vector
of deferred access checks associations.
(save_deferred_access_checks): New function to save the association
between a tree and a vector of deferred access checks in
deferred_access_checks_hash.
(get_saved_deferred_access_checks): New function to lookup the vector of
deferred access checks associated with a given tree.
(cp_parser_nested_name_specifier_opt): Associate the current deferred
access checks with token->value by calling save_deferred_access_checks.
(cp_parser_template_id): Use get_saved_deferred_access_checks and
save_deferred_access_checks.
(cp_parser_pre_parsed_nested_name_specifier): Likewise.
(cp_parser_template_declaration_after_export): Adjusted the call to
get_deferred_access_checks.
(cp_parser_init_declarator): Take the access checks as a vector of struct
deferred_access_check instead of a tree list.
(cp_parser_single_declaration): Likewise.
(cp_parser_perform_template_parameter_access_checks): Likewise.
(cp_parser_simple_declaration): Adjusted the call to
cp_parser_init_declarator.
(cp_parser_explicit_specialization): Adjusted the call to
cp_parser_single_declaration.
-------------- next part --------------
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 119333)
+++ gcc/cp/cp-tree.h (working copy)
@@ -4227,14 +4227,29 @@ extern tree copied_binfo (tree, tree);
extern tree original_binfo (tree, tree);
extern int shared_member_p (tree);
+
+/* The representation of a deferred access check. */
+
+typedef struct deferred_access_check GTY(())
+{
+ /* The base class in which the declaration is referenced. */
+ tree binfo;
+ /* The declaration whose access must be checked. */
+ tree decl;
+ /* The declaration that should be used in the error message. */
+ tree diag_decl;
+} deferred_access_check;
+DEF_VEC_O(deferred_access_check);
+DEF_VEC_ALLOC_O(deferred_access_check,gc);
+
/* in semantics.c */
extern void push_deferring_access_checks (deferring_kind);
extern void resume_deferring_access_checks (void);
extern void stop_deferring_access_checks (void);
extern void pop_deferring_access_checks (void);
-extern tree get_deferred_access_checks (void);
+extern VEC (deferred_access_check,gc)* get_deferred_access_checks (void);
extern void pop_to_parent_deferring_access_checks (void);
-extern void perform_access_checks (tree);
+extern void perform_access_checks (VEC (deferred_access_check,gc)*);
extern void perform_deferred_access_checks (void);
extern void perform_or_defer_access_check (tree, tree, tree);
extern int stmts_are_full_exprs_p (void);
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c (revision 119333)
+++ gcc/cp/semantics.c (working copy)
@@ -96,7 +96,7 @@ static tree finalize_nrv_r (tree *, int
2. When a declaration such as a type, or a variable, is encountered,
the function `perform_or_defer_access_check' is called. It
- maintains a TREE_LIST of all deferred checks.
+ maintains a VECTOR of all deferred checks.
3. The global `current_class_type' or `current_function_decl' is then
setup by the parser. `enforce_access' relies on these information
@@ -104,7 +104,7 @@ static tree finalize_nrv_r (tree *, int
4. Upon exiting the context mentioned in step 1,
`perform_deferred_access_checks' is called to check all declaration
- stored in the TREE_LIST. `pop_deferring_access_checks' is then
+ stored in the VECTOR. `pop_deferring_access_checks' is then
called to restore the previous access checking mode.
In case of parsing error, we simply call `pop_deferring_access_checks'
@@ -112,7 +112,7 @@ static tree finalize_nrv_r (tree *, int
typedef struct deferred_access GTY(())
{
- /* A TREE_LIST representing name-lookups for which we have deferred
+ /* A VECTOR 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:
@@ -124,12 +124,8 @@ typedef struct deferred_access GTY(())
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;
+ is valid, even though `A::B' is not generally accessible. */
+ VEC (deferred_access_check,gc)* GTY(()) deferred_access_checks;
/* The current mode of access checks. */
enum deferring_kind deferring_access_checks_kind;
@@ -157,7 +153,7 @@ push_deferring_access_checks (deferring_
deferred_access *ptr;
ptr = VEC_safe_push (deferred_access, gc, deferred_access_stack, NULL);
- ptr->deferred_access_checks = NULL_TREE;
+ ptr->deferred_access_checks = NULL;
ptr->deferring_access_checks_kind = deferring;
}
}
@@ -200,7 +196,7 @@ pop_deferring_access_checks (void)
access occurred; the TREE_VALUE is the declaration named.
*/
-tree
+VEC (deferred_access_check,gc)*
get_deferred_access_checks (void)
{
if (deferred_access_no_check)
@@ -221,7 +217,7 @@ pop_to_parent_deferring_access_checks (v
deferred_access_no_check--;
else
{
- tree checks;
+ VEC (deferred_access_check,gc) *checks;
deferred_access *ptr;
checks = (VEC_last (deferred_access, deferred_access_stack)
@@ -232,29 +228,31 @@ pop_to_parent_deferring_access_checks (v
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), TREE_VALUE (checks));
+ perform_access_checks (checks);
}
else
{
/* Merge with parent. */
- tree next;
- tree original = ptr->deferred_access_checks;
-
- for (; checks; checks = next)
- {
- tree probe;
-
- next = TREE_CHAIN (checks);
+ int i, j;
+ deferred_access_check *chk, *probe;
- for (probe = original; probe; probe = TREE_CHAIN (probe))
- if (TREE_VALUE (probe) == TREE_VALUE (checks)
- && TREE_PURPOSE (probe) == TREE_PURPOSE (checks))
- goto found;
+ for (i = 0 ;
+ VEC_iterate (deferred_access_check, checks, i, chk) ;
+ ++i)
+ {
+ for (j = 0 ;
+ VEC_iterate (deferred_access_check,
+ ptr->deferred_access_checks, j, probe) ;
+ ++j)
+ {
+ if (probe->binfo == chk->binfo &&
+ probe->decl == chk->decl &&
+ probe->diag_decl == chk->diag_decl)
+ goto found;
+ }
/* Insert into parent's checks. */
- TREE_CHAIN (checks) = ptr->deferred_access_checks;
- ptr->deferred_access_checks = checks;
+ VEC_safe_push (deferred_access_check, gc,
+ ptr->deferred_access_checks, chk);
found:;
}
}
@@ -266,14 +264,16 @@ pop_to_parent_deferring_access_checks (v
DECL node stored in the TREE_VALUE of the node. */
void
-perform_access_checks (tree checks)
+perform_access_checks (VEC (deferred_access_check,gc)* checks)
{
- while (checks)
- {
- enforce_access (TREE_PURPOSE (checks),
- TREE_VALUE (checks), TREE_VALUE (checks));
- checks = TREE_CHAIN (checks);
- }
+ int i;
+ deferred_access_check *chk;
+
+ if (!checks)
+ return;
+
+ for (i = 0 ; VEC_iterate (deferred_access_check, checks, i, chk) ; ++i)
+ enforce_access (chk->binfo, chk->decl, chk->diag_decl);
}
/* Perform the deferred access checks.
@@ -304,8 +304,11 @@ perform_deferred_access_checks (void)
void
perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
{
- tree check;
+ int i;
deferred_access *ptr;
+ deferred_access_check *chk;
+ deferred_access_check *new_access;
+
/* Exit if we are in a context that no access checking is performed.
*/
@@ -324,14 +327,24 @@ perform_or_defer_access_check (tree binf
}
/* See if we are already going to perform this check. */
- for (check = ptr->deferred_access_checks;
- check;
- check = TREE_CHAIN (check))
- if (TREE_VALUE (check) == decl && TREE_PURPOSE (check) == binfo)
- return;
+ for (i = 0 ;
+ VEC_iterate (deferred_access_check,
+ ptr->deferred_access_checks, i, chk) ;
+ ++i)
+ {
+ if (chk->decl == decl && chk->binfo == binfo &&
+ chk->diag_decl == diag_decl)
+ {
+ return;
+ }
+ }
/* If not, record the check. */
- ptr->deferred_access_checks
- = tree_cons (binfo, decl, ptr->deferred_access_checks);
+ new_access =
+ VEC_safe_push (deferred_access_check, gc,
+ ptr->deferred_access_checks, 0);
+ new_access->binfo = binfo;
+ new_access->decl = decl;
+ new_access->diag_decl = diag_decl;
}
/* Returns nonzero if the current statement is a full expression,
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 119333)
+++ gcc/cp/parser.c (working copy)
@@ -1599,7 +1599,7 @@ static void cp_parser_static_assert
/* Declarators [gram.dcl.decl] */
static tree cp_parser_init_declarator
- (cp_parser *, cp_decl_specifier_seq *, tree, bool, bool, int, bool *);
+ (cp_parser *, cp_decl_specifier_seq *, VEC (deferred_access_check,gc)*, bool, bool, int, bool *);
static cp_declarator *cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, int *, bool *, bool);
static cp_declarator *cp_parser_direct_declarator
@@ -1799,9 +1799,9 @@ static tree cp_parser_function_definitio
static void cp_parser_template_declaration_after_export
(cp_parser *, bool);
static void cp_parser_perform_template_parameter_access_checks
- (tree);
+ (VEC (deferred_access_check,gc)*);
static tree cp_parser_single_declaration
- (cp_parser *, tree, bool, bool *);
+ (cp_parser *, VEC (deferred_access_check,gc)*, bool, bool *);
static tree cp_parser_functional_cast
(cp_parser *, tree);
static tree cp_parser_save_member_function_body
@@ -2575,6 +2575,87 @@ cp_parser_make_typename_type (cp_parser
}
+/* Deferred checks management.
+ Some deferred checks are not done immediately, but rather "attached"
+ a tree for later processing. The "tree / deferred access checks"
+ associations are stored in a hash table. */
+
+/* A node in the deferred access checks hash table. */
+
+typedef struct deferred_access_check_hash_node GTY(())
+{
+ tree t;
+ /* The checks that have been associated with T. */
+ VEC (deferred_access_check, gc)* GTY(()) checks;
+} deferred_access_check_hash_node;
+
+/* Computes a hash of a given node. The node's T pointer is hashed. */
+
+static hashval_t
+deferred_access_check_hash (const void *node)
+{
+ deferred_access_check_hash_node *n =
+ (deferred_access_check_hash_node*) node;
+ return htab_hash_pointer (n->t);
+}
+
+/* Determines whether NODE1 and NODE2 are equal, i.e. whether their T
+ pointers are equal. */
+
+static int
+deferred_access_check_node_eq (const void *node1, const void *node2)
+{
+ deferred_access_check_hash_node *n1 =
+ (deferred_access_check_hash_node*) node1;
+ deferred_access_check_hash_node *n2 =
+ (deferred_access_check_hash_node*) node2;
+ return htab_eq_pointer (n1->t, n2->t);
+}
+
+/* The deferred access checks hash table. */
+
+static GTY((param_is (deferred_access_check_hash_node))) htab_t
+deferred_access_checks_hash;
+
+
+/* Saves that the CHECKS deferred checks must be performed for T. */
+
+static void
+save_deferred_access_checks (tree t,
+ VEC (deferred_access_check, gc) *checks)
+{
+ deferred_access_check_hash_node proxy, **chk;
+
+ /* Create the hash table if needed. */
+ if (deferred_access_checks_hash == NULL)
+ deferred_access_checks_hash =
+ htab_create_ggc (31, deferred_access_check_hash,
+ deferred_access_check_node_eq, NULL);
+
+ /* Create an entry for T. */
+ proxy.t = t;
+ chk = (deferred_access_check_hash_node**)
+ htab_find_slot (deferred_access_checks_hash, &proxy, INSERT);
+
+ /* Setup the entry for T. */
+ *chk = GGC_CNEW (deferred_access_check_hash_node);
+ (*chk)->t = t;
+ (*chk)->checks = checks;
+}
+
+
+/* Gets the deferred checks saved for T. */
+
+static VEC (deferred_access_check, gc)*
+get_saved_deferred_access_checks (tree t)
+{
+ deferred_access_check_hash_node proxy, *chk;
+ proxy.t = t;
+ chk = htab_find (deferred_access_checks_hash, &proxy);
+ return chk ? chk->checks : NULL;
+}
+
+
/* Create a new C++ parser. */
static cp_parser *
@@ -3889,16 +3970,16 @@ cp_parser_nested_name_specifier_opt (cp_
if (success && start)
{
cp_token *token;
- tree access_checks;
token = cp_lexer_token_at (parser->lexer, start);
/* Reset the contents of the START token. */
token->type = CPP_NESTED_NAME_SPECIFIER;
/* Retrieve any deferred checks. Do not pop this access checks yet
so the memory will not be reclaimed during token replacing below. */
- access_checks = get_deferred_access_checks ();
- token->value = build_tree_list (copy_list (access_checks),
+ token->value = build_tree_list (NULL_TREE,
parser->scope);
+ save_deferred_access_checks (token->value,
+ get_deferred_access_checks ());
TREE_TYPE (token->value) = parser->qualifying_scope;
token->keyword = RID_MAX;
@@ -7392,7 +7473,7 @@ cp_parser_simple_declaration (cp_parser*
/* Parse the init-declarator. */
decl = cp_parser_init_declarator (parser, &decl_specifiers,
- /*checks=*/NULL_TREE,
+ /*checks=*/NULL,
function_definition_allowed_p,
/*member_p=*/false,
declares_class_or_enum,
@@ -8817,11 +8898,13 @@ cp_parser_template_id (cp_parser *parser
bool check_dependency_p,
bool is_declaration)
{
+ int i;
tree template;
tree arguments;
tree template_id;
cp_token_position start_of_id = 0;
- tree access_check = NULL_TREE;
+ deferred_access_check *chk;
+ VEC (deferred_access_check,gc) *access_check;
cp_token *next_token, *next_token_2;
bool is_identifier;
@@ -8831,15 +8914,22 @@ cp_parser_template_id (cp_parser *parser
if (next_token->type == CPP_TEMPLATE_ID)
{
tree value;
- tree check;
/* Get the stored value. */
value = cp_lexer_consume_token (parser->lexer)->value;
/* Perform any access checks that were deferred. */
- for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
- perform_or_defer_access_check (TREE_PURPOSE (check),
- TREE_VALUE (check),
- TREE_VALUE (check));
+ access_check = get_saved_deferred_access_checks (value);
+ if (access_check)
+ {
+ for (i = 0 ;
+ VEC_iterate (deferred_access_check, access_check, i, chk) ;
+ ++i)
+ {
+ perform_or_defer_access_check (chk->binfo,
+ chk->decl,
+ chk->diag_decl);
+ }
+ }
/* Return the stored value. */
return TREE_VALUE (value);
}
@@ -8957,10 +9047,6 @@ cp_parser_template_id (cp_parser *parser
template_id = lookup_template_function (template, arguments);
}
- /* Retrieve any deferred checks. Do not pop this access checks yet
- so the memory will not be reclaimed during token replacing below. */
- access_check = get_deferred_access_checks ();
-
/* If parsing tentatively, replace the sequence of tokens that makes
up the template-id with a CPP_TEMPLATE_ID token. That way,
should we re-parse the token stream, we will not have to repeat
@@ -8973,7 +9059,11 @@ cp_parser_template_id (cp_parser *parser
/* Reset the contents of the START_OF_ID token. */
token->type = CPP_TEMPLATE_ID;
- token->value = build_tree_list (access_check, template_id);
+ /* Retrieve any deferred checks. Do not pop this access checks yet
+ so the memory will not be reclaimed during token replacing below. */
+ token->value = build_tree_list (NULL_TREE, template_id);
+ save_deferred_access_checks (token->value,
+ get_deferred_access_checks ());
token->keyword = RID_MAX;
/* Purge all subsequent tokens. */
@@ -9638,7 +9728,7 @@ cp_parser_explicit_specialization (cp_pa
else
/* Parse the dependent declaration. */
cp_parser_single_declaration (parser,
- /*checks=*/NULL_TREE,
+ /*checks=*/NULL,
/*member_p=*/false,
/*friend_p=*/NULL);
/* We're done with the specialization. */
@@ -11086,7 +11176,7 @@ cp_parser_asm_definition (cp_parser* par
static tree
cp_parser_init_declarator (cp_parser* parser,
cp_decl_specifier_seq *decl_specifiers,
- tree checks,
+ VEC (deferred_access_check,gc)* checks,
bool function_definition_allowed_p,
bool member_p,
int declares_class_or_enum,
@@ -15674,7 +15764,7 @@ static void
cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
{
tree decl = NULL_TREE;
- tree checks;
+ VEC (deferred_access_check,gc) *checks;
tree parameter_list;
bool friend_p = false;
bool need_lang_pop;
@@ -15788,7 +15878,7 @@ cp_parser_template_declaration_after_exp
get_deferred_access_checks. */
static void
-cp_parser_perform_template_parameter_access_checks (tree checks)
+cp_parser_perform_template_parameter_access_checks (VEC (deferred_access_check,gc)* checks)
{
++processing_template_parmlist;
perform_access_checks (checks);
@@ -15804,7 +15894,7 @@ cp_parser_perform_template_parameter_acc
static tree
cp_parser_single_declaration (cp_parser* parser,
- tree checks,
+ VEC (deferred_access_check,gc)* checks,
bool member_p,
bool* friend_p)
{
@@ -16750,16 +16840,26 @@ cp_parser_optional_template_keyword (cp_
static void
cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser)
{
+ int i;
tree value;
- tree check;
+ deferred_access_check *chk;
+ VEC (deferred_access_check,gc) *checks;
/* Get the stored value. */
value = cp_lexer_consume_token (parser->lexer)->value;
/* Perform any access checks that were deferred. */
- for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
- perform_or_defer_access_check (TREE_PURPOSE (check),
- TREE_VALUE (check),
- TREE_VALUE (check));
+ checks = get_saved_deferred_access_checks (value);
+ if (checks)
+ {
+ for (i = 0 ;
+ VEC_iterate (deferred_access_check, checks, i, chk) ;
+ ++i)
+ {
+ perform_or_defer_access_check (chk->binfo,
+ chk->decl,
+ chk->diag_decl);
+ }
+ }
/* Set the scope from the stored value. */
parser->scope = TREE_VALUE (value);
parser->qualifying_scope = TREE_TYPE (value);
More information about the Gcc-patches
mailing list