This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] Stage 2: Implement access check for template instantiation(2/n) (Take 2)
- From: Kriang Lerdsuwanakij <lerdsuwa at users dot sourceforge dot net>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 18 May 2005 17:02:45 +0700
- Subject: [C++ PATCH] Stage 2: Implement access check for template instantiation(2/n) (Take 2)
Hello
This is a revised version of my patch:
http://gcc.gnu.org/ml/gcc-patches/2005-05/msg01320.html
The only change compare to the previous version is the addition
of ACCESS_CHAIN macro and use it instead of TREE_CHAIN
as suggested in a couple followup to the original patch.
Part 1 and 3 of this work are not affected by the change and don't
need to be updated.
OK for the mainline?
--Kriang
2005-05-18 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
Defer access check until template instantiation 2/n
* cp-tree.def (ACCESS): New tree code.
* cp-tree.h (ACCESS_CHAIN): New macro.
(find_access_checks_append_location, build_access): Add
declarations.
* parser.c (cp_parser_template_id,
cp_parser_pre_parsed_nested_name_specifier): Adjust.
* semantics.c (find_access_checks_append_location, build_access):
New functions.
(pop_to_parent_deferring_access_checks,
perform_or_defer_access_check): Use them.
(perform_deferred_access_checks): Adjust.
diff -cprN gcc-main-save/gcc/cp/cp-tree.def gcc-main-new/gcc/cp/cp-tree.def
*** gcc-main-save/gcc/cp/cp-tree.def 2005-05-18 11:53:06.763229672 +0700
--- gcc-main-new/gcc/cp/cp-tree.def 2005-05-18 11:56:46.632804416 +0700
*************** DEFTREECODE (ALIAS_DECL, "alias_decl", t
*** 105,110 ****
--- 105,121 ----
overloaded. */
DEFTREECODE (BASELINK, "baselink", tcc_exceptional, 0)
+ /* A tree node to store information used for deferred access checking.
+ There are two possibilities for the operands of this tree node.
+ Case 1: Operand 0 is the BINFO of scope through which access
+ checking is performed. Operand 1 is the DECL.
+ Case 2: Operand 0 is NULL_TREE. Operand 1 is the TYPENAME_TYPE,
+ UNBOUND_CLASS_TEMPLATE, or SCOPE_REF.
+ Its ACCESS_CHAIN points to the next ACCESS node to be checked, and
+ its EXPR_LOCATION is the source location where this ACCESS first
+ appear. */
+ DEFTREECODE (ACCESS, "access", tcc_expression, 2)
+
/* Template definition. The following fields have the specified uses,
although there are other macros in cp-tree.h that should be used for
accessing this data.
diff -cprN gcc-main-save/gcc/cp/cp-tree.h gcc-main-new/gcc/cp/cp-tree.h
*** gcc-main-save/gcc/cp/cp-tree.h 2005-05-18 11:53:06.766229216 +0700
--- gcc-main-new/gcc/cp/cp-tree.h 2005-05-18 11:56:44.187176208 +0700
*************** struct tree_baselink GTY(())
*** 339,344 ****
--- 339,348 ----
tree access_binfo;
};
+ /* The next ACCESS node in the chain. */
+ #define ACCESS_CHAIN(NODE) \
+ (TREE_CHAIN (ACCESS_CHECK (NODE)))
+
/* The different kinds of ids that we encounter. */
typedef enum cp_id_kind
*************** extern void stop_deferring_access_checks
*** 4061,4066 ****
--- 4065,4073 ----
extern void pop_deferring_access_checks (void);
extern tree get_deferred_access_checks (void);
extern void pop_to_parent_deferring_access_checks (void);
+ extern tree *find_access_checks_append_location (tree *, tree, tree,
+ location_t);
+ extern tree build_access (tree, tree, tree, location_t);
extern void perform_deferred_access_checks (void);
extern void perform_or_defer_access_check (tree, tree);
extern void init_cp_semantics (void);
diff -cprN gcc-main-save/gcc/cp/parser.c gcc-main-new/gcc/cp/parser.c
*** gcc-main-save/gcc/cp/parser.c 2005-05-18 11:53:06.774228000 +0700
--- gcc-main-new/gcc/cp/parser.c 2005-05-18 11:59:56.382958008 +0700
*************** cp_parser_template_id (cp_parser *parser
*** 8435,8443 ****
/* 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));
/* Return the stored value. */
return TREE_VALUE (value);
}
--- 8435,8443 ----
/* 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 = ACCESS_CHAIN (check))
! perform_or_defer_access_check (TREE_OPERAND (check, 0),
! TREE_OPERAND (check, 1));
/* Return the stored value. */
return TREE_VALUE (value);
}
*************** cp_parser_pre_parsed_nested_name_specifi
*** 15893,15900 ****
/* 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));
/* Set the scope from the stored value. */
parser->scope = TREE_VALUE (value);
parser->qualifying_scope = TREE_TYPE (value);
--- 15893,15901 ----
/* 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 = ACCESS_CHAIN (check))
! perform_or_defer_access_check (TREE_OPERAND (check, 0),
! TREE_OPERAND (check, 1));
/* Set the scope from the stored value. */
parser->scope = TREE_VALUE (value);
parser->qualifying_scope = TREE_TYPE (value);
diff -cprN gcc-main-save/gcc/cp/semantics.c gcc-main-new/gcc/cp/semantics.c
*** gcc-main-save/gcc/cp/semantics.c 2005-05-18 11:53:06.775227848 +0700
--- gcc-main-new/gcc/cp/semantics.c 2005-05-18 11:58:19.903625096 +0700
*************** static tree finalize_nrv_r (tree *, int
*** 100,106 ****
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.
3. The global `current_class_type' or `current_function_decl' is then
setup by the parser. `enforce_access' relies on these information
--- 100,106 ----
2. When a declaration such as a type, or a variable, is encountered,
the function `perform_or_defer_access_check' is called. It
! maintains the list of deferred checks in a chain of ACCESS tree node.
3. The global `current_class_type' or `current_function_decl' is then
setup by the parser. `enforce_access' relies on these information
*************** static tree finalize_nrv_r (tree *, int
*** 108,114 ****
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
called to restore the previous access checking mode.
In case of parsing error, we simply call `pop_deferring_access_checks'
--- 108,114 ----
4. Upon exiting the context mentioned in step 1,
`perform_deferred_access_checks' is called to check all declaration
! stored in the ACCESS list. `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'
*************** static tree finalize_nrv_r (tree *, int
*** 116,125 ****
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 {};
--- 116,125 ----
typedef struct deferred_access GTY(())
{
! /* A chain of ACCESS tree nodes 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 {};
*************** typedef struct deferred_access GTY(())
*** 128,138 ****
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. */
--- 128,134 ----
A::B* A::f() { return 0; }
! is valid, even though `A::B' is not generally accessible. */
tree deferred_access_checks;
/* The current mode of access checks. */
*************** pop_deferring_access_checks (void)
*** 199,207 ****
VEC_pop (deferred_access, deferred_access_stack);
}
! /* Returns a TREE_LIST representing the deferred checks.
! The TREE_PURPOSE of each node is the type through which the
! access occurred; the TREE_VALUE is the declaration named.
*/
tree
--- 195,203 ----
VEC_pop (deferred_access, deferred_access_stack);
}
! /* Returns a chain of ACCESS tree node representing the deferred
! checks. The operand 0 of each node is the type through which the
! access occurred; the operand 1 is the declaration named.
*/
tree
*************** get_deferred_access_checks (void)
*** 214,219 ****
--- 210,237 ----
->deferred_access_checks);
}
+ /* Search the chain of ACCESS tree node for BINFO and DECL.
+ If found, returns NULL. Otherwise return the location of the
+ end of the chain where the chain can be extended. With this
+ method of node insertion, the ACCESS nodes in the chain is sorted
+ in the order of appearance in the source code to aid diagnostics. */
+
+ tree *
+ find_access_checks_append_location (tree *list, tree binfo, tree decl,
+ location_t location)
+ {
+ tree *probe;
+ for (probe = list; *probe; probe = &ACCESS_CHAIN (*probe))
+ {
+ location_t probe_location = EXPR_LOCATION (*probe);
+ if (TREE_OPERAND (*probe, 0) == binfo
+ && TREE_OPERAND (*probe, 1) == decl
+ && !memcmp (&location, &probe_location, sizeof (location_t)))
+ return NULL;
+ }
+ return probe;
+ }
+
/* Take current deferred checks and combine with the
previous states if we also defer checks previously.
Otherwise perform checks now. */
*************** pop_to_parent_deferring_access_checks (v
*** 236,265 ****
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:;
}
}
}
--- 254,282 ----
if (ptr->deferring_access_checks_kind == dk_no_deferred)
{
/* Check access. */
! for (; checks; checks = ACCESS_CHAIN (checks))
! enforce_access (TREE_OPERAND (checks, 0),
! TREE_OPERAND (checks, 1));
}
else
{
/* Merge with parent. */
tree next;
! tree *list = &ptr->deferred_access_checks;
for (; checks; checks = next)
{
! tree *tail;
! next = ACCESS_CHAIN (checks);
! tail = find_access_checks_append_location
! (list,
! TREE_OPERAND (checks, 0),
! TREE_OPERAND (checks, 1),
! EXPR_LOCATION (checks));
! if (tail)
! *tail = checks;
! ACCESS_CHAIN (checks) = NULL_TREE;
}
}
}
*************** perform_deferred_access_checks (void)
*** 288,297 ****
for (deferred_check = get_deferred_access_checks ();
deferred_check;
! deferred_check = TREE_CHAIN (deferred_check))
/* Check access. */
! enforce_access (TREE_PURPOSE (deferred_check),
! TREE_VALUE (deferred_check));
}
/* Defer checking the accessibility of DECL, when looked up in
--- 305,325 ----
for (deferred_check = get_deferred_access_checks ();
deferred_check;
! deferred_check = ACCESS_CHAIN (deferred_check))
/* Check access. */
! enforce_access (TREE_OPERAND (deferred_check, 0),
! TREE_OPERAND (deferred_check, 1));
! }
!
! /* Build ACCESS tree node to store deferred access information. */
!
! tree
! build_access (tree binfo, tree decl, tree chain, location_t location)
! {
! tree t = build_nt (ACCESS, binfo, decl);
! ACCESS_CHAIN (t) = chain;
! SET_EXPR_LOCATION (t, location);
! return t;
}
/* Defer checking the accessibility of DECL, when looked up in
*************** perform_deferred_access_checks (void)
*** 300,306 ****
void
perform_or_defer_access_check (tree binfo, tree decl)
{
- tree check;
deferred_access *ptr;
/* Exit if we are in a context that no access checking is performed.
--- 328,333 ----
*************** perform_or_defer_access_check (tree binf
*** 318,333 ****
enforce_access (binfo, decl);
return;
}
!
! /* 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;
! /* If not, record the check. */
! ptr->deferred_access_checks
! = tree_cons (binfo, decl, ptr->deferred_access_checks);
}
/* Returns nonzero if the current statement is a full expression,
--- 345,361 ----
enforce_access (binfo, decl);
return;
}
! else
! {
! tree *tail;
! /* See if we are already going to perform this check. */
! tail = find_access_checks_append_location
! (&(ptr->deferred_access_checks), binfo, decl,
! input_location);
! /* If not, record the check. */
! if (tail)
! *tail = build_access (binfo, decl, NULL_TREE, input_location);
! }
}
/* Returns nonzero if the current statement is a full expression,