aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2008-09-08 16:52:44 -0400
committerJason Merrill <jason@gcc.gnu.org>2008-09-08 16:52:44 -0400
commitb344d949d25164341ca4532ce067af1b254198a0 (patch)
tree0142184b1cea337fc342e6818257e4f6cb77fa58 /gcc/cp
parent37022b7c72c96135c90798684598f39fd1371b40 (diff)
downloadgcc-b344d949d25164341ca4532ce067af1b254198a0.zip
gcc-b344d949d25164341ca4532ce067af1b254198a0.tar.gz
gcc-b344d949d25164341ca4532ce067af1b254198a0.tar.bz2
re PR c++/37302 (function parameters are declared too late)
PR c++/37302 * parser.c (cp_parser_parameter_declaration_list): Process the PARM_DECLs as we go and push them. Return a TREE_LIST. (cp_parser_parameter_declaration_clause): Return a TREE_LIST. (cp_parser_direct_declarator): Create a binding level and suppress deprecated warnings in the parameter list. (make_call_declarator): PARMS is now a tree. * cp-tree.h (struct cp_declarator): Function parms are now a tree. * decl.h (enum deprecated_states, deprecated_state): Move here. * decl.c: From here. (type_is_deprecated): New fn. (grokparms): PARMLIST is a tree now. Warn about parms that use deprecated types. * mangle.c (write_expression): Handle PARM_DECL, CALL_EXPR and 0-operand cast. * pt.c (tsubst) [DECLTYPE_TYPE]: Set skip_evaluation. (tsubst_copy) [PARM_DECL]: Handle a PARM_DECL used outside of a function. * name-lookup.c (pushtag): Look through function parameter scopes. (pushdecl_maybe_friend): Don't set DECL_CONTEXT on a PARM_DECL when we're parsing a function declarator. From-SVN: r140120
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog24
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/decl.c81
-rw-r--r--gcc/cp/decl.h13
-rw-r--r--gcc/cp/mangle.c28
-rw-r--r--gcc/cp/name-lookup.c11
-rw-r--r--gcc/cp/parser.c80
-rw-r--r--gcc/cp/pt.c32
8 files changed, 197 insertions, 76 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index cb5c314..cd5b52c 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,27 @@
+2008-09-06 Jason Merrill <jason@redhat.com>
+
+ PR c++/37302
+ * parser.c (cp_parser_parameter_declaration_list): Process the
+ PARM_DECLs as we go and push them. Return a TREE_LIST.
+ (cp_parser_parameter_declaration_clause): Return a TREE_LIST.
+ (cp_parser_direct_declarator): Create a binding level and
+ suppress deprecated warnings in the parameter list.
+ (make_call_declarator): PARMS is now a tree.
+ * cp-tree.h (struct cp_declarator): Function parms are now a tree.
+ * decl.h (enum deprecated_states, deprecated_state): Move here.
+ * decl.c: From here.
+ (type_is_deprecated): New fn.
+ (grokparms): PARMLIST is a tree now. Warn about parms that
+ use deprecated types.
+ * mangle.c (write_expression): Handle PARM_DECL, CALL_EXPR and
+ 0-operand cast.
+ * pt.c (tsubst) [DECLTYPE_TYPE]: Set skip_evaluation.
+ (tsubst_copy) [PARM_DECL]: Handle a PARM_DECL used outside of a
+ function.
+ * name-lookup.c (pushtag): Look through function parameter scopes.
+ (pushdecl_maybe_friend): Don't set DECL_CONTEXT on a PARM_DECL
+ when we're parsing a function declarator.
+
2008-09-05 Douglas Gregor <doug.gregor@gmail.com>
PR c++/37342
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ca069b7..4f6716b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4108,8 +4108,8 @@ struct cp_declarator {
} id;
/* For functions. */
struct {
- /* The parameters to the function. */
- cp_parameter_declarator *parameters;
+ /* The parameters to the function as a TREE_LIST of decl/default. */
+ tree parameters;
/* The cv-qualifiers for the function. */
cp_cv_quals qualifiers;
/* The exception-specification for the function. */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index c045353..3348d28 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -54,7 +54,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-flow.h"
#include "pointer-set.h"
-static tree grokparms (cp_parameter_declarator *, tree *);
+static tree grokparms (tree parmlist, tree *);
static const char *redeclaration_error_message (tree, tree);
static int decl_jump_unsafe (tree);
@@ -236,13 +236,7 @@ VEC(tree, gc) *deferred_mark_used_calls;
with __attribute__((deprecated)). An object declared as
__attribute__((deprecated)) suppresses warnings of uses of other
deprecated items. */
-
-enum deprecated_states {
- DEPRECATED_NORMAL,
- DEPRECATED_SUPPRESS
-};
-
-static enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
+enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
/* A TREE_LIST of VAR_DECLs. The TREE_PURPOSE is a RECORD_TYPE or
@@ -9494,6 +9488,32 @@ check_default_argument (tree decl, tree arg)
return arg;
}
+/* Returns a deprecated type used within TYPE, or NULL_TREE if none. */
+
+static tree
+type_is_deprecated (tree type)
+{
+ enum tree_code code;
+ if (TREE_DEPRECATED (type))
+ return type;
+ if (TYPE_NAME (type)
+ && TREE_DEPRECATED (TYPE_NAME (type)))
+ return type;
+
+ code = TREE_CODE (type);
+
+ if (code == POINTER_TYPE || code == REFERENCE_TYPE
+ || code == OFFSET_TYPE || code == FUNCTION_TYPE
+ || code == METHOD_TYPE || code == ARRAY_TYPE)
+ return type_is_deprecated (TREE_TYPE (type));
+
+ if (TYPE_PTRMEMFUNC_P (type))
+ return type_is_deprecated
+ (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type))));
+
+ return NULL_TREE;
+}
+
/* Decode the list of parameter types for a function type.
Given the list of things declared inside the parens,
return a list of types.
@@ -9504,41 +9524,31 @@ check_default_argument (tree decl, tree arg)
*PARMS is set to the chain of PARM_DECLs created. */
static tree
-grokparms (cp_parameter_declarator *first_parm, tree *parms)
+grokparms (tree parmlist, tree *parms)
{
tree result = NULL_TREE;
tree decls = NULL_TREE;
- int ellipsis = !first_parm || first_parm->ellipsis_p;
- cp_parameter_declarator *parm;
+ tree parm;
int any_error = 0;
- struct pointer_set_t *unique_decls = pointer_set_create ();
- for (parm = first_parm; parm != NULL; parm = parm->next)
+ for (parm = parmlist; parm != NULL_TREE; parm = TREE_CHAIN (parm))
{
tree type = NULL_TREE;
- tree init = parm->default_argument;
- tree attrs;
- tree decl;
+ tree init = TREE_PURPOSE (parm);
+ tree decl = TREE_VALUE (parm);
- if (parm == no_parameters)
+ if (parm == void_list_node)
break;
- attrs = parm->decl_specifiers.attributes;
- parm->decl_specifiers.attributes = NULL_TREE;
- decl = grokdeclarator (parm->declarator, &parm->decl_specifiers,
- PARM, init != NULL_TREE, &attrs);
if (! decl || TREE_TYPE (decl) == error_mark_node)
continue;
- if (attrs)
- cplus_decl_attributes (&decl, attrs, 0);
-
type = TREE_TYPE (decl);
if (VOID_TYPE_P (type))
{
if (same_type_p (type, void_type_node)
&& DECL_SELF_REFERENCE_P (type)
- && !DECL_NAME (decl) && !result && !parm->next && !ellipsis)
+ && !DECL_NAME (decl) && !result && TREE_CHAIN (parm) == void_list_node)
/* this is a parmlist of `(void)', which is ok. */
break;
cxx_incomplete_type_error (decl, type);
@@ -9561,6 +9571,13 @@ grokparms (cp_parameter_declarator *first_parm, tree *parms)
if (type != error_mark_node)
{
+ if (deprecated_state != DEPRECATED_SUPPRESS)
+ {
+ tree deptype = type_is_deprecated (type);
+ if (deptype)
+ warn_deprecated_use (deptype);
+ }
+
/* Top-level qualifiers on the parameters are
ignored for function types. */
type = cp_build_qualified_type (type, 0);
@@ -9603,28 +9620,20 @@ grokparms (cp_parameter_declarator *first_parm, tree *parms)
if (TREE_CODE (decl) == PARM_DECL
&& FUNCTION_PARAMETER_PACK_P (decl)
- && parm->next)
+ && TREE_CHAIN (parm)
+ && TREE_CHAIN (parm) != void_list_node)
error ("parameter packs must be at the end of the parameter list");
- if (DECL_NAME (decl))
- {
- if (pointer_set_contains (unique_decls, DECL_NAME (decl)))
- error ("multiple parameters named %qE", DECL_NAME (decl));
- else
- pointer_set_insert (unique_decls, DECL_NAME (decl));
- }
-
TREE_CHAIN (decl) = decls;
decls = decl;
result = tree_cons (init, type, result);
}
decls = nreverse (decls);
result = nreverse (result);
- if (!ellipsis)
+ if (parm)
result = chainon (result, void_list_node);
*parms = decls;
- pointer_set_destroy (unique_decls);
return result;
}
diff --git a/gcc/cp/decl.h b/gcc/cp/decl.h
index 52ab0fb..ed28714 100644
--- a/gcc/cp/decl.h
+++ b/gcc/cp/decl.h
@@ -34,3 +34,16 @@ enum decl_context
extern tree grokdeclarator (const cp_declarator *,
const cp_decl_specifier_seq *,
enum decl_context, int, tree*);
+
+/* States indicating how grokdeclarator() should handle declspecs marked
+ with __attribute__((deprecated)). An object declared as
+ __attribute__((deprecated)) suppresses warnings of uses of other
+ deprecated items. */
+
+enum deprecated_states {
+ DEPRECATED_NORMAL,
+ DEPRECATED_SUPPRESS
+};
+
+extern enum deprecated_states deprecated_state;
+
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index dea92b9..7b4c303 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -2016,7 +2016,8 @@ write_template_args (tree args)
<expr-primary> ::= <template-param>
::= L <type> <value number> E # literal
::= L <mangled-name> E # external name
- ::= sr <type> <unqualified-name>
+ ::= st <type> # sizeof
+ ::= sr <type> <unqualified-name> # dependent name
::= sr <type> <unqualified-name> <template-args> */
static void
@@ -2042,6 +2043,12 @@ write_expression (tree expr)
code = TREE_CODE (expr);
}
+ if (code == OVERLOAD)
+ {
+ expr = OVL_FUNCTION (expr);
+ code = TREE_CODE (expr);
+ }
+
/* Handle pointers-to-members by making them look like expression
nodes. */
if (code == PTRMEM_CST)
@@ -2064,6 +2071,13 @@ write_expression (tree expr)
else if (TREE_CODE_CLASS (code) == tcc_constant
|| (abi_version_at_least (2) && code == CONST_DECL))
write_template_arg_literal (expr);
+ else if (code == PARM_DECL)
+ {
+ /* A function parameter used under decltype in a late-specified
+ return type. Represented with a type placeholder. */
+ write_string ("sT");
+ write_type (non_reference (TREE_TYPE (expr)));
+ }
else if (DECL_P (expr))
{
/* G++ 3.2 incorrectly mangled non-type template arguments of
@@ -2175,16 +2189,17 @@ write_expression (tree expr)
switch (code)
{
case CALL_EXPR:
- sorry ("call_expr cannot be mangled due to a defect in the C++ ABI");
+ write_expression (CALL_EXPR_FN (expr));
+ for (i = 0; i < call_expr_nargs (expr); ++i)
+ write_expression (CALL_EXPR_ARG (expr, i));
+ write_char ('E');
break;
case CAST_EXPR:
write_type (TREE_TYPE (expr));
- /* There is no way to mangle a zero-operand cast like
- "T()". */
if (!TREE_OPERAND (expr, 0))
- sorry ("zero-operand casts cannot be mangled due to a defect "
- "in the C++ ABI");
+ /* "T()" is mangled as "T(void)". */
+ write_char ('v');
else
write_expression (TREE_VALUE (TREE_OPERAND (expr, 0)));
break;
@@ -2195,7 +2210,6 @@ write_expression (tree expr)
write_expression (TREE_OPERAND (expr, 0));
break;
-
/* Handle pointers-to-members specially. */
case SCOPE_REF:
write_type (TREE_OPERAND (expr, 0));
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 7fc6a93..743f0236 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -604,6 +604,13 @@ pushdecl_maybe_friend (tree x, bool is_friend)
scope of the current namespace, not the current
function. */
&& !(TREE_CODE (x) == VAR_DECL && DECL_EXTERNAL (x))
+ /* When parsing the parameter list of a function declarator,
+ don't set DECL_CONTEXT to an enclosing function. When we
+ push the PARM_DECLs in order to process the function body,
+ current_binding_level->this_entity will be set. */
+ && !(TREE_CODE (x) == PARM_DECL
+ && current_binding_level->kind == sk_function_parms
+ && current_binding_level->this_entity == NULL)
&& !DECL_CONTEXT (x))
DECL_CONTEXT (x) = current_function_decl;
@@ -712,8 +719,6 @@ pushdecl_maybe_friend (tree x, bool is_friend)
}
else if (TREE_CODE (t) == PARM_DECL)
{
- gcc_assert (DECL_CONTEXT (t));
-
/* Check for duplicate params. */
if (duplicate_decls (x, t, is_friend))
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
@@ -4987,6 +4992,8 @@ pushtag (tree name, tree type, tag_scope scope)
while (/* Cleanup scopes are not scopes from the point of view of
the language. */
b->kind == sk_cleanup
+ /* Neither are function parameter scopes. */
+ || b->kind == sk_function_parms
/* Neither are the scopes used to hold template parameters
for an explicit specialization. For an ordinary template
declaration, these scopes are not scopes from the point of
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 3f6e370..88f92e7 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -853,7 +853,7 @@ clear_decl_specs (cp_decl_specifier_seq *decl_specs)
VAR_DECLs or FUNCTION_DECLs) should do that directly. */
static cp_declarator *make_call_declarator
- (cp_declarator *, cp_parameter_declarator *, cp_cv_quals, tree, tree);
+ (cp_declarator *, tree, cp_cv_quals, tree, tree);
static cp_declarator *make_array_declarator
(cp_declarator *, tree);
static cp_declarator *make_pointer_declarator
@@ -1013,7 +1013,7 @@ make_ptrmem_declarator (cp_cv_quals cv_qualifiers, tree class_type,
cp_declarator *
make_call_declarator (cp_declarator *target,
- cp_parameter_declarator *parms,
+ tree parms,
cp_cv_quals cv_qualifiers,
tree exception_specification,
tree late_return_type)
@@ -1736,9 +1736,9 @@ static tree cp_parser_type_id
(cp_parser *);
static void cp_parser_type_specifier_seq
(cp_parser *, bool, cp_decl_specifier_seq *);
-static cp_parameter_declarator *cp_parser_parameter_declaration_clause
+static tree cp_parser_parameter_declaration_clause
(cp_parser *);
-static cp_parameter_declarator *cp_parser_parameter_declaration_list
+static tree cp_parser_parameter_declaration_list
(cp_parser *, bool *);
static cp_parameter_declarator *cp_parser_parameter_declaration
(cp_parser *, bool, bool *);
@@ -12986,8 +12986,10 @@ cp_parser_direct_declarator (cp_parser* parser,
if (!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)
{
- cp_parameter_declarator *params;
+ tree params;
unsigned saved_num_template_parameter_lists;
+ bool is_declarator = false;
+ tree t;
/* In a member-declarator, the only valid interpretation
of a parenthesis is the start of a
@@ -13014,6 +13016,8 @@ cp_parser_direct_declarator (cp_parser* parser,
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
+ begin_scope (sk_function_parms, NULL_TREE);
+
/* Parse the parameter-declaration-clause. */
params = cp_parser_parameter_declaration_clause (parser);
@@ -13028,6 +13032,8 @@ cp_parser_direct_declarator (cp_parser* parser,
tree exception_specification;
tree late_return;
+ is_declarator = true;
+
if (ctor_dtor_or_conv_p)
*ctor_dtor_or_conv_p = *ctor_dtor_or_conv_p < 0;
first = false;
@@ -13053,10 +13059,16 @@ cp_parser_direct_declarator (cp_parser* parser,
return type, so are not those of the declared
function. */
parser->default_arg_ok_p = false;
-
- /* Repeat the main loop. */
- continue;
}
+
+ /* Remove the function parms from scope. */
+ for (t = current_binding_level->names; t; t = TREE_CHAIN (t))
+ pop_binding (DECL_NAME (t), t);
+ leave_scope();
+
+ if (is_declarator)
+ /* Repeat the main loop. */
+ continue;
}
/* If this is the first, we can try a parenthesized
@@ -13728,10 +13740,10 @@ cp_parser_type_specifier_seq (cp_parser* parser,
value of NULL indicates a parameter-declaration-clause consisting
only of an ellipsis. */
-static cp_parameter_declarator *
+static tree
cp_parser_parameter_declaration_clause (cp_parser* parser)
{
- cp_parameter_declarator *parameters;
+ tree parameters;
cp_token *token;
bool ellipsis_p;
bool is_error;
@@ -13743,7 +13755,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
{
/* Consume the `...' token. */
cp_lexer_consume_token (parser->lexer);
- return NULL;
+ return NULL_TREE;
}
else if (token->type == CPP_CLOSE_PAREN)
/* There are no parameters. */
@@ -13751,10 +13763,10 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
#ifndef NO_IMPLICIT_EXTERN_C
if (in_system_header && current_class_type == NULL
&& current_lang_name == lang_name_c)
- return NULL;
+ return NULL_TREE;
else
#endif
- return no_parameters;
+ return void_list_node;
}
/* Check for `(void)', too, which is a special case. */
else if (token->keyword == RID_VOID
@@ -13764,7 +13776,7 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
/* Consume the `void' token. */
cp_lexer_consume_token (parser->lexer);
/* There are no parameters. */
- return no_parameters;
+ return void_list_node;
}
/* Parse the parameter-declaration-list. */
@@ -13799,8 +13811,8 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
ellipsis_p = false;
/* Finish the parameter list. */
- if (parameters && ellipsis_p)
- parameters->ellipsis_p = true;
+ if (!ellipsis_p)
+ parameters = chainon (parameters, void_list_node);
return parameters;
}
@@ -13816,11 +13828,11 @@ cp_parser_parameter_declaration_clause (cp_parser* parser)
`void_list_node' is never appended to the list. Upon return,
*IS_ERROR will be true iff an error occurred. */
-static cp_parameter_declarator *
+static tree
cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
{
- cp_parameter_declarator *parameters = NULL;
- cp_parameter_declarator **tail = &parameters;
+ tree parameters = NULL_TREE;
+ tree *tail = &parameters;
bool saved_in_unbraced_linkage_specification_p;
/* Assume all will go well. */
@@ -13836,6 +13848,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
while (true)
{
cp_parameter_declarator *parameter;
+ tree decl = error_mark_node;
bool parenthesized_p;
/* Parse the parameter. */
parameter
@@ -13843,17 +13856,38 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
/*template_parm_p=*/false,
&parenthesized_p);
+ /* We don't know yet if the enclosing context is deprecated, so wait
+ and warn in grokparms if appropriate. */
+ deprecated_state = DEPRECATED_SUPPRESS;
+
+ if (parameter)
+ decl = grokdeclarator (parameter->declarator,
+ &parameter->decl_specifiers,
+ PARM,
+ parameter->default_argument != NULL_TREE,
+ &parameter->decl_specifiers.attributes);
+
+ deprecated_state = DEPRECATED_NORMAL;
+
/* If a parse error occurred parsing the parameter declaration,
then the entire parameter-declaration-list is erroneous. */
- if (!parameter)
+ if (decl == error_mark_node)
{
*is_error = true;
- parameters = NULL;
+ parameters = error_mark_node;
break;
}
+
+ if (parameter->decl_specifiers.attributes)
+ cplus_decl_attributes (&decl,
+ parameter->decl_specifiers.attributes,
+ 0);
+ if (DECL_NAME (decl))
+ decl = pushdecl (decl);
+
/* Add the new parameter to the list. */
- *tail = parameter;
- tail = &parameter->next;
+ *tail = build_tree_list (parameter->default_argument, decl);
+ tail = &TREE_CHAIN (*tail);
/* Peek at the next token. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7c9165c..4aa7b1a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -9556,11 +9556,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{
tree type;
- type =
- finish_decltype_type (tsubst_expr
- (DECLTYPE_TYPE_EXPR (t), args,
- complain, in_decl,
- /*integral_constant_expression_p=*/false),
+ ++skip_evaluation;
+
+ type = tsubst_expr (DECLTYPE_TYPE_EXPR (t), args,
+ complain, in_decl,
+ /*integral_constant_expression_p=*/false);
+
+ --skip_evaluation;
+
+ type =
+ finish_decltype_type (type,
DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t));
return cp_build_qualified_type_real (type,
cp_type_quals (t)
@@ -9796,7 +9801,22 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{
case PARM_DECL:
r = retrieve_local_specialization (t);
- gcc_assert (r != NULL);
+
+ if (r == NULL)
+ {
+ /* This can happen for a parameter name used later in a function
+ declaration (such as in a late-specified return type).
+ Replace it with an arbitrary expression with the same type
+ (*(T*)0). This should only occur in an unevaluated context
+ (i.e. decltype). */
+ gcc_assert (skip_evaluation && DECL_CONTEXT (t) == NULL_TREE);
+ r = non_reference (TREE_TYPE (t));
+ r = tsubst (r, args, complain, in_decl);
+ r = build_pointer_type (r);
+ r = build_c_cast (r, null_node);
+ return cp_build_indirect_ref (r, NULL, tf_warning_or_error);
+ }
+
if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
r = ARGUMENT_PACK_SELECT_ARG (r);
mark_used (r);