From 5cce22b6c2bfebd556b36a9c89d1bdf3eee900ae Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Fri, 17 Nov 2000 10:05:31 +0000 Subject: [PATCH] cp-tree.h (PARMLIST_ELLIPSIS_P): New macro. cp: * cp-tree.h (PARMLIST_ELLIPSIS_P): New macro. * decl.c (grokdeclarator): Don't reject void parms here. (require_complete_types_for_parms): Simplify, use complete_type_or_else. (grokparms): Remove bitrot. Remove funcdef parm. Deal with ellipsis parm lists here. * semantics.c (finish_parmlist): Don't append void_list_node here. Set PARMLIST_ELLIPSIS_P. testsuite: * g++.old-deja/g++.other/incomplete.C: Add more tests. * g++.old-deja/g++.pt/crash9.C: Mark new expected error. From-SVN: r37517 --- gcc/cp/ChangeLog | 11 + gcc/cp/cp-tree.h | 4 + gcc/cp/decl.c | 316 ++++++------------ gcc/cp/semantics.c | 16 +- gcc/testsuite/ChangeLog | 5 + .../g++.old-deja/g++.other/incomplete.C | 15 +- gcc/testsuite/g++.old-deja/g++.pt/crash9.C | 2 +- 7 files changed, 147 insertions(+), 222 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f059212cd3a..1cbeac8055a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2000-11-17 Nathan Sidwell + + * cp-tree.h (PARMLIST_ELLIPSIS_P): New macro. + * decl.c (grokdeclarator): Don't reject void parms here. + (require_complete_types_for_parms): Simplify, use + complete_type_or_else. + (grokparms): Remove bitrot. Remove funcdef parm. + Deal with ellipsis parm lists here. + * semantics.c (finish_parmlist): Don't append void_list_node + here. Set PARMLIST_ELLIPSIS_P. + 2000-11-17 Nathan Sidwell * typeck2.c (incomplete_type_error): Reorganise to avoid diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 67e4c239c1e..34c9d136511 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -44,6 +44,7 @@ Boston, MA 02111-1307, USA. */ CTOR_BEGIN_P (in CTOR_STMT) BV_USE_VCALL_INDEX_P (in the BINFO_VIRTUALS TREE_LIST) PTRMEM_OK_P (in ADDR_EXPR, OFFSET_REF) + PARMLIST_ELLIPSIS_P (in PARMLIST) 1: IDENTIFIER_VIRTUAL_P. TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -1768,6 +1769,9 @@ struct lang_type is a list of parameters, as opposed to a list of expressions. */ #define TREE_PARMLIST(NODE) ((NODE)->common.unsigned_flag) /* overloaded! */ +/* Nonzero for a parmlist means that this parmlist ended in ... */ +#define PARMLIST_ELLIPSIS_P(NODE) TREE_LANG_FLAG_0 (NODE) + /* For FUNCTION_TYPE or METHOD_TYPE, a list of the exceptions that this type can raise. Each TREE_VALUE is a _TYPE. The TREE_VALUE will be NULL_TREE to indicate a throw specification of `()', or diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 192a7cd857e..a357526aa0c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -100,7 +100,7 @@ extern int (*valid_lang_attribute) PARAMS ((tree, tree, tree, tree)); : "long long unsigned int")) #endif -static tree grokparms PARAMS ((tree, int)); +static tree grokparms PARAMS ((tree)); static const char *redeclaration_error_message PARAMS ((tree, tree)); static void push_binding_level PARAMS ((struct binding_level *, int, @@ -10738,7 +10738,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) /* FIXME: This is where default args should be fully processed. */ - arg_types = grokparms (inner_parms, funcdecl_p ? funcdef_flag : 0); + arg_types = grokparms (inner_parms); if (declarator && flags == DTOR_FLAG) { @@ -11367,11 +11367,6 @@ friend declaration requires class-key, i.e. `friend %#T'", type = build_pointer_type (type); else if (TREE_CODE (type) == OFFSET_TYPE) type = build_pointer_type (type); - else if (TREE_CODE (type) == VOID_TYPE && declarator) - { - error ("declaration of `%s' as void", name); - return NULL_TREE; - } } { @@ -11837,25 +11832,13 @@ require_complete_types_for_parms (parms) { for (; parms; parms = TREE_CHAIN (parms)) { - tree type = TREE_TYPE (parms); - - /* Try to complete the TYPE. */ - type = complete_type (type); - - if (type == error_mark_node) - continue; - - if (!COMPLETE_TYPE_P (type)) - { - if (DECL_NAME (parms)) - error ("parameter `%s' has incomplete type", - IDENTIFIER_POINTER (DECL_NAME (parms))); - else - error ("parameter has incomplete type"); - TREE_TYPE (parms) = error_mark_node; - } - else + if (VOID_TYPE_P (TREE_TYPE (parms))) + /* grokparms will have already issued an error */ + TREE_TYPE (parms) = error_mark_node; + else if (complete_type_or_else (TREE_TYPE (parms), parms)) layout_decl (parms, 0); + else + TREE_TYPE (parms) = error_mark_node; } } @@ -11986,205 +11969,114 @@ check_default_argument (decl, arg) Given the list of things declared inside the parens, return a list of types. - The list we receive can have three kinds of elements: - an IDENTIFIER_NODE for names given without types, - a TREE_LIST node for arguments given as typespecs or names with typespecs, - or void_type_node, to mark the end of an argument list - when additional arguments are not permitted (... was not used). + We determine whether ellipsis parms are used by PARMLIST_ELLIPSIS_P + flag. If unset, we append void_list_node. A parmlist declared + as `(void)' is accepted as the empty parmlist. - FUNCDEF_FLAG is nonzero for a function definition, 0 for - a mere declaration. A nonempty identifier-list gets an error message - when FUNCDEF_FLAG is zero. - If FUNCDEF_FLAG is 1, then parameter types must be complete. - If FUNCDEF_FLAG is -1, then parameter types may be incomplete. - - If all elements of the input list contain types, - we return a list of the types. - If all elements contain no type (except perhaps a void_type_node - at the end), we return a null list. - If some have types and some do not, it is an error, and we - return a null list. - - Also set last_function_parms to either - a list of names (IDENTIFIER_NODEs) or a chain of PARM_DECLs. - A list of names is converted to a chain of PARM_DECLs - by store_parm_decls so that ultimately it is always a chain of decls. - - Note that in C++, parameters can take default values. These default - values are in the TREE_PURPOSE field of the TREE_LIST. It is - an error to specify default values which are followed by parameters - that have no default values, or an ELLIPSES. For simplicities sake, - only parameters which are specified with their types can take on - default values. */ + Also set last_function_parms to the chain of PARM_DECLs. */ static tree -grokparms (first_parm, funcdef_flag) +grokparms (first_parm) tree first_parm; - int funcdef_flag; { tree result = NULL_TREE; tree decls = NULL_TREE; + int ellipsis = !first_parm || PARMLIST_ELLIPSIS_P (first_parm); + tree parm, chain; + int any_error = 0; - if (first_parm != NULL_TREE - && TREE_CODE (TREE_VALUE (first_parm)) == IDENTIFIER_NODE) - { - if (! funcdef_flag) - pedwarn ("parameter names (without types) in function declaration"); - last_function_parms = first_parm; - return NULL_TREE; - } - else if (first_parm != NULL_TREE - && TREE_CODE (TREE_VALUE (first_parm)) != TREE_LIST - && TREE_CODE (TREE_VALUE (first_parm)) != VOID_TYPE) - my_friendly_abort (145); - else - { - /* Types were specified. This is a list of declarators - each represented as a TREE_LIST node. */ - register tree parm, chain; - int any_init = 0, any_error = 0; + my_friendly_assert (!first_parm || TREE_PARMLIST (first_parm), 20001115); - if (first_parm != NULL_TREE) + for (parm = first_parm; parm != NULL_TREE; parm = chain) + { + tree type = NULL_TREE, list_node = parm; + register tree decl = TREE_VALUE (parm); + tree init = TREE_PURPOSE (parm); + + chain = TREE_CHAIN (parm); + /* @@ weak defense against parse errors. */ + if (TREE_CODE (decl) != VOID_TYPE + && TREE_CODE (decl) != TREE_LIST) { - tree last_result = NULL_TREE; - tree last_decl = NULL_TREE; - - for (parm = first_parm; parm != NULL_TREE; parm = chain) - { - tree type = NULL_TREE, list_node = parm; - register tree decl = TREE_VALUE (parm); - tree init = TREE_PURPOSE (parm); - - chain = TREE_CHAIN (parm); - /* @@ weak defense against parse errors. */ - if (TREE_CODE (decl) != VOID_TYPE - && TREE_CODE (decl) != TREE_LIST) - { - /* Give various messages as the need arises. */ - if (TREE_CODE (decl) == STRING_CST) - cp_error ("invalid string constant `%E'", decl); - else if (TREE_CODE (decl) == INTEGER_CST) - error ("invalid integer constant in parameter list, did you forget to give parameter name?"); - continue; - } - - if (TREE_CODE (decl) != VOID_TYPE) - { - decl = grokdeclarator (TREE_VALUE (decl), - TREE_PURPOSE (decl), - PARM, init != NULL_TREE, - NULL_TREE); - if (! decl || TREE_TYPE (decl) == error_mark_node) - continue; - - /* Top-level qualifiers on the parameters are - ignored for function types. */ - type = TYPE_MAIN_VARIANT (TREE_TYPE (decl)); - - if (TREE_CODE (type) == VOID_TYPE) - decl = void_type_node; - else if (TREE_CODE (type) == METHOD_TYPE) - { - if (DECL_NAME (decl)) - /* Cannot use the decl here because - we don't have DECL_CONTEXT set up yet. */ - cp_error ("parameter `%D' invalidly declared method type", - DECL_NAME (decl)); - else - error ("parameter invalidly declared method type"); - type = build_pointer_type (type); - TREE_TYPE (decl) = type; - } - else if (TREE_CODE (type) == OFFSET_TYPE) - { - if (DECL_NAME (decl)) - cp_error ("parameter `%D' invalidly declared offset type", - DECL_NAME (decl)); - else - error ("parameter invalidly declared offset type"); - type = build_pointer_type (type); - TREE_TYPE (decl) = type; - } - else if (abstract_virtuals_error (decl, type)) - any_error = 1; /* Seems like a good idea. */ - else if (POINTER_TYPE_P (type)) - { - tree t = type; - while (POINTER_TYPE_P (t) - || (TREE_CODE (t) == ARRAY_TYPE - && TYPE_DOMAIN (t) != NULL_TREE)) - t = TREE_TYPE (t); - if (TREE_CODE (t) == ARRAY_TYPE) - cp_error ("parameter type `%T' includes %s to array of unknown bound", - type, - TYPE_PTR_P (type) ? "pointer" : "reference"); - } - } - - if (TREE_CODE (decl) == VOID_TYPE) - { - if (result == NULL_TREE) - { - result = void_list_node; - last_result = result; - } - else - { - TREE_CHAIN (last_result) = void_list_node; - last_result = void_list_node; - } - if (chain - && (chain != void_list_node || TREE_CHAIN (chain))) - error ("`void' in parameter list must be entire list"); - break; - } - - /* Since there is a prototype, args are passed in their own types. */ - DECL_ARG_TYPE (decl) = TREE_TYPE (decl); - if (PROMOTE_PROTOTYPES - && (TREE_CODE (type) == INTEGER_TYPE - || TREE_CODE (type) == ENUMERAL_TYPE) - && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) - DECL_ARG_TYPE (decl) = integer_type_node; - if (!any_error && init) - { - any_init++; - init = check_default_argument (decl, init); - } - else - init = NULL_TREE; - - if (decls == NULL_TREE) - { - decls = decl; - last_decl = decls; - } - else - { - TREE_CHAIN (last_decl) = decl; - last_decl = decl; - } - list_node = tree_cons (init, type, NULL_TREE); - if (result == NULL_TREE) - { - result = list_node; - last_result = result; - } - else - { - TREE_CHAIN (last_result) = list_node; - last_result = list_node; - } - } - if (last_result) - TREE_CHAIN (last_result) = NULL_TREE; - /* If there are no parameters, and the function does not end - with `...', then last_decl will be NULL_TREE. */ - if (last_decl != NULL_TREE) - TREE_CHAIN (last_decl) = NULL_TREE; + /* Give various messages as the need arises. */ + if (TREE_CODE (decl) == STRING_CST) + cp_error ("invalid string constant `%E'", decl); + else if (TREE_CODE (decl) == INTEGER_CST) + error ("invalid integer constant in parameter list, did you forget to give parameter name?"); + continue; } - } + if (parm == void_list_node) + break; + + decl = grokdeclarator (TREE_VALUE (decl), TREE_PURPOSE (decl), + PARM, init != NULL_TREE, NULL_TREE); + if (! decl || TREE_TYPE (decl) == error_mark_node) + continue; + + type = TREE_TYPE (decl); + if (VOID_TYPE_P (type)) + { + if (same_type_p (type, void_type_node) + && !DECL_NAME (decl) && !result && !chain && !ellipsis) + /* this is a parmlist of `(void)', which is ok. */ + break; + incomplete_type_error (decl, type); + } + + /* Top-level qualifiers on the parameters are + ignored for function types. */ + type = TYPE_MAIN_VARIANT (type); + if (TREE_CODE (type) == METHOD_TYPE) + { + cp_error ("parameter `%D' invalidly declared method type", decl); + type = build_pointer_type (type); + TREE_TYPE (decl) = type; + } + else if (TREE_CODE (type) == OFFSET_TYPE) + { + cp_error ("parameter `%D' invalidly declared offset type", decl); + type = build_pointer_type (type); + TREE_TYPE (decl) = type; + } + else if (abstract_virtuals_error (decl, type)) + any_error = 1; /* Seems like a good idea. */ + else if (POINTER_TYPE_P (type)) + { + /* [dcl.fct]/6, parameter types cannot contain pointers (references) + to arrays of unknown bound. */ + tree t = type; + + while (POINTER_TYPE_P (t) + || (TREE_CODE (t) == ARRAY_TYPE + && TYPE_DOMAIN (t) != NULL_TREE)) + t = TREE_TYPE (t); + if (TREE_CODE (t) == ARRAY_TYPE) + cp_error ("parameter `%D' includes %s to array of unknown bound `%T'", + decl, TYPE_PTR_P (type) ? "pointer" : "reference", t); + } + + DECL_ARG_TYPE (decl) = TREE_TYPE (decl); + if (PROMOTE_PROTOTYPES + && (TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) + DECL_ARG_TYPE (decl) = integer_type_node; + if (!any_error && init) + init = check_default_argument (decl, init); + else + init = NULL_TREE; + + TREE_CHAIN (decl) = decls; + decls = decl; + list_node = tree_cons (init, type, NULL_TREE); + TREE_CHAIN (list_node) = result; + result = list_node; + } + decls = nreverse (decls); + result = nreverse (result); + if (!ellipsis) + result = chainon (result, void_list_node); last_function_parms = decls; return result; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 28c0f35b075..b372fdd4a7e 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1695,13 +1695,15 @@ finish_parmlist (parms, ellipsis) tree parms; int ellipsis; { - if (!ellipsis) - chainon (parms, void_list_node); - /* We mark the PARMS as a parmlist so that declarator processing can - disambiguate certain constructs. */ - if (parms != NULL_TREE) - TREE_PARMLIST (parms) = 1; - + 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; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d0c3dbf8adb..b6acd130c18 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2000-11-17 Nathan Sidwell + + * g++.old-deja/g++.other/incomplete.C: Add more tests. + * g++.old-deja/g++.pt/crash9.C: Mark new expected error. + 2000-11-16 Nick Clifton * gcc.c-torture/execute/nestfunc-2.c: New test. diff --git a/gcc/testsuite/g++.old-deja/g++.other/incomplete.C b/gcc/testsuite/g++.old-deja/g++.other/incomplete.C index 0c230c18777..f5e9a581faf 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/incomplete.C +++ b/gcc/testsuite/g++.old-deja/g++.other/incomplete.C @@ -1,5 +1,16 @@ // Build don't link: -struct S; +// gcc represents non-ellipsis parmlists by terminating them with +// a void parm. We need to distinguish between a parmlist of (void), and +// some ill-formed ones. -void f(S s) {} // ERROR - incomplete type +struct S; // ERROR - forward ref + +void f(S); // ok +void f(S s) {} // ERROR - incomplete type +void j (int){}; // ok +void k (){}; // ok +void q (void){} // ok +void t (void t); // ERROR - incomplete +void r (void, ...); // ERROR - incomplete +void s (void const); // ERROR - incomplete diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash9.C b/gcc/testsuite/g++.old-deja/g++.pt/crash9.C index 297b8accaad..d72699d2360 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/crash9.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/crash9.C @@ -3,7 +3,7 @@ template void f(T) {} // ERROR - parameter has incomplete type -class C; +class C; // ERROR - forward declaration void g(const C& c) {