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
This commit is contained in:
Nathan Sidwell 2000-11-17 10:05:31 +00:00 committed by Nathan Sidwell
parent 146c8d6034
commit 5cce22b6c2
7 changed files with 147 additions and 222 deletions

View File

@ -1,3 +1,14 @@
2000-11-17 Nathan Sidwell <nathan@codesourcery.com>
* 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 <nathan@codesourcery.com>
* typeck2.c (incomplete_type_error): Reorganise to avoid

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -1,3 +1,8 @@
2000-11-17 Nathan Sidwell <nathan@codesourcery.com>
* 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 <nickc@redhat.com>
* gcc.c-torture/execute/nestfunc-2.c: New test.

View File

@ -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

View File

@ -3,7 +3,7 @@
template <class T>
void f(T) {} // ERROR - parameter has incomplete type
class C;
class C; // ERROR - forward declaration
void g(const C& c)
{