diff options
author | Jason Merrill <jason@redhat.com> | 2008-09-08 16:52:44 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2008-09-08 16:52:44 -0400 |
commit | b344d949d25164341ca4532ce067af1b254198a0 (patch) | |
tree | 0142184b1cea337fc342e6818257e4f6cb77fa58 /gcc/cp | |
parent | 37022b7c72c96135c90798684598f39fd1371b40 (diff) | |
download | gcc-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/ChangeLog | 24 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 4 | ||||
-rw-r--r-- | gcc/cp/decl.c | 81 | ||||
-rw-r--r-- | gcc/cp/decl.h | 13 | ||||
-rw-r--r-- | gcc/cp/mangle.c | 28 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 11 | ||||
-rw-r--r-- | gcc/cp/parser.c | 80 | ||||
-rw-r--r-- | gcc/cp/pt.c | 32 |
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 = ¶meters; + tree parameters = NULL_TREE; + tree *tail = ¶meters; 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, + ¶meter->decl_specifiers, + PARM, + parameter->default_argument != NULL_TREE, + ¶meter->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 = ¶meter->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); |