Commit 7fb213d8 by Giovanni Bajo

re PR c++/2204 (G++ doesn't check (member) function parameter for abstract-ness.)

	PR c++/2204
	* config-lang.in (gtfiles): Add typeck2.c.
	* Make-lang.in: Tweak typeck2.c dependencies, and add rule for
	gt-cp-typeck2.h.
	* cp-tree.h: Declare complete_type_check_abstract.
	* typeck2.c (pat_calc_hash, pat_compare,
	complete_type_check_abstract): New functions.
	(abstract_virtuals_error): If the type is abstract, register the
	declaration within abstract_pending_vars for further checks.
	Inspect also dependent types. Handle IDENTIFIER_NODEs as decl.
	* decl.c (cp_finish_decl): Do not strip array types.
	(create_array_type_for_decl): Check for abstractness of the element
	type.
	(complete_vars): Call complete_type_check_abstract.
	* class.c (finish_struct): Prepare a list of virtual functions for
	template types, and call complete_vars on it to check for abstractness.

	PR c++/2204
	* g++.dg/other/abstract2.C: New test.

From-SVN: r84552
parent b55e3aad
2004-07-12 Giovanni Bajo <giovannibajo@gcc.gnu.org>
PR c++/2204
* config-lang.in (gtfiles): Add typeck2.c.
* Make-lang.in: Tweak typeck2.c dependencies, and add rule for
gt-cp-typeck2.h.
* cp-tree.h: Declare complete_type_check_abstract.
* typeck2.c (pat_calc_hash, pat_compare,
complete_type_check_abstract): New functions.
(abstract_virtuals_error): If the type is abstract, register the
declaration within abstract_pending_vars for further checks.
Inspect also dependent types. Handle IDENTIFIER_NODEs as decl.
* decl.c (cp_finish_decl): Do not strip array types.
(create_array_type_for_decl): Check for abstractness of the element
type.
(complete_vars): Call complete_type_check_abstract.
* class.c (finish_struct): Prepare a list of virtual functions for
template types, and call complete_vars on it to check for abstractness.
2004-07-12 Paolo Bonzini <bonzini@gnu.org>
PR tree-optimization/14107
......
......@@ -99,7 +99,7 @@ $(srcdir)/cp/cfns.h: $(srcdir)/cp/cfns.gperf
gtype-cp.h gt-cp-call.h gt-cp-decl.h gt-cp-decl2.h : s-gtype; @true
gt-cp-pt.h gt-cp-repo.h gt-cp-parser.h gt-cp-method.h : s-gtype; @true
gt-cp-tree.h gt-cp-mangle.h gt-cp-name-lookup.h: s-gtype; @true
gt-cp-tree.h gt-cp-mangle.h gt-cp-name-lookup.h gt-cp-typeck2.h: s-gtype; @true
#
# Build hooks:
......@@ -231,7 +231,7 @@ cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) flags.h cp/decl.h stack.h \
cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) flags.h cp/decl.h $(EXPR_H) \
output.h except.h toplev.h $(RTL_H) c-common.h gt-cp-decl2.h cgraph.h
cp/typeck2.o: cp/typeck2.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h output.h $(TM_P_H) \
diagnostic.h
diagnostic.h gt-cp-typeck2.h
cp/typeck.o: cp/typeck.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) $(EXPR_H) toplev.h \
diagnostic.h convert.h
cp/class.o: cp/class.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h $(RTL_H) $(TARGET_H) convert.h
......
......@@ -5270,8 +5270,24 @@ finish_struct (tree t, tree attributes)
if (processing_template_decl)
{
tree x;
finish_struct_methods (t);
TYPE_SIZE (t) = bitsize_zero_node;
/* We need to emit an error message if this type was used as a parameter
and it is an abstract type, even if it is a template. We construct
a simple CLASSTYPE_PURE_VIRTUALS list without taking bases into
account and we call complete_vars with this type, which will check
the PARM_DECLS. Note that while the type is being defined,
CLASSTYPE_PURE_VIRTUALS contains the list of the inline friends
(see CLASSTYPE_INLINE_FRIENDS) so we need to clear it. */
CLASSTYPE_PURE_VIRTUALS (t) = NULL_TREE;
for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x))
if (DECL_PURE_VIRTUAL_P (x))
CLASSTYPE_PURE_VIRTUALS (t)
= tree_cons (NULL_TREE, x, CLASSTYPE_PURE_VIRTUALS (t));
complete_vars (t);
}
else
finish_struct_1 (t);
......
......@@ -34,4 +34,4 @@ stagestuff="g++\$(exeext) g++-cross\$(exeext) cc1plus\$(exeext)"
target_libs="target-libstdc++-v3 target-gperf"
gtfiles="\$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-lex.c \$(srcdir)/c-pragma.c"
gtfiles="\$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-common.c \$(srcdir)/c-common.h \$(srcdir)/c-lex.c \$(srcdir)/c-pragma.c"
......@@ -4315,6 +4315,7 @@ extern void cxx_incomplete_type_error (tree, tree);
extern tree error_not_base_type (tree, tree);
extern tree binfo_or_else (tree, tree);
extern void readonly_error (tree, const char *, int);
extern void complete_type_check_abstract (tree);
extern int abstract_virtuals_error (tree, tree);
extern tree store_init_value (tree, tree);
......
......@@ -4821,21 +4821,12 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
make_rtl_for_nonlocal_decl (decl, init, asmspec);
/* Check for abstractness of the type. Notice that there is no
need to strip array types here since the check for those types
is already done within create_array_type_for_decl. */
if (TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE)
abstract_virtuals_error (decl,
strip_array_types (TREE_TYPE (type)));
else if (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
{
/* If it's either a pointer or an array type, strip through all
of them but the last one. If the last is an array type, issue
an error if the element type is abstract. */
while (POINTER_TYPE_P (TREE_TYPE (type))
|| TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE)
type = TREE_TYPE (type);
if (TREE_CODE (type) == ARRAY_TYPE)
abstract_virtuals_error (decl, TREE_TYPE (type));
}
abstract_virtuals_error (decl, TREE_TYPE (type));
else
abstract_virtuals_error (decl, type);
......@@ -6162,6 +6153,11 @@ create_array_type_for_decl (tree name, tree type, tree size)
if (size)
itype = compute_array_index_type (name, size);
/* [dcl.array]
T is called the array element type; this type shall not be [...] an
abstract class type. */
abstract_virtuals_error (name, type);
return build_cplus_array_type (type, itype);
}
......@@ -10592,6 +10588,9 @@ complete_vars (tree type)
else
list = &TREE_CHAIN (*list);
}
/* Check for pending declarations which may have abstract type. */
complete_type_check_abstract (type);
}
/* If DECL is of a type which needs a cleanup, build that cleanup
......
......@@ -114,6 +114,119 @@ readonly_error (tree arg, const char* string, int soft)
(*fn) ("%s of read-only location", string);
}
/* Structure that holds information about declarations whose type was
incomplete and we could not check whether it was abstract or not. */
struct pending_abstract_type GTY((chain_next ("%h.next")))
{
/* Declaration which we are checking for abstractness. It is either
a DECL node, or an IDENTIFIER_NODE if we do not have a full
declaration available. */
tree decl;
/* Type which will be checked for abstractness. */
tree type;
/* Position of the declaration. This is only needed for IDENTIFIER_NODEs,
because DECLs already carry locus information. */
location_t locus;
/* Link to the next element in list. */
struct pending_abstract_type* next;
};
/* Compute the hash value of the node VAL. This function is used by the
hash table abstract_pending_vars. */
static hashval_t
pat_calc_hash (const void* val)
{
const struct pending_abstract_type* pat = val;
return (hashval_t) TYPE_UID (pat->type);
}
/* Compare node VAL1 with the type VAL2. This function is used by the
hash table abstract_pending_vars. */
static int
pat_compare (const void* val1, const void* val2)
{
const struct pending_abstract_type* pat1 = val1;
tree type2 = (tree)val2;
return (pat1->type == type2);
}
/* Hash table that maintains pending_abstract_type nodes, for which we still
need to check for type abstractness. The key of the table is the type
of the declaration. */
static GTY ((param_is (struct pending_abstract_type)))
htab_t abstract_pending_vars = NULL;
/* This function is called after TYPE is completed, and will check if there
are pending declarations for which we still need to verify the abstractness
of TYPE, and emit a diagnostic (through abstract_virtuals_error) if TYPE
turned out to be incomplete. */
void
complete_type_check_abstract (tree type)
{
void **slot;
struct pending_abstract_type *pat;
location_t cur_loc = input_location;
my_friendly_assert (COMPLETE_TYPE_P (type), 20040620_3);
if (!abstract_pending_vars)
return;
/* Retrieve the list of pending declarations for this type. */
slot = htab_find_slot_with_hash (abstract_pending_vars, type,
(hashval_t)TYPE_UID (type), NO_INSERT);
if (!slot)
return;
pat = (struct pending_abstract_type*)*slot;
my_friendly_assert (pat, 20040620_2);
/* If the type is not abstract, do not do anything. */
if (CLASSTYPE_PURE_VIRTUALS (type))
{
struct pending_abstract_type *prev = 0, *next;
/* Reverse the list to emit the errors in top-down order. */
for (; pat; pat = next)
{
next = pat->next;
pat->next = prev;
prev = pat;
}
pat = prev;
/* Go through the list, and call abstract_virtuals_error for each
element: it will issue a diagostic if the type is abstract. */
while (pat)
{
my_friendly_assert (type == pat->type, 20040620_4);
/* Tweak input_location so that the diagnostic appears at the correct
location. Notice that this is only needed if the decl is an
IDENTIFIER_NODE, otherwise cp_error_at. */
input_location = pat->locus;
abstract_virtuals_error (pat->decl, pat->type);
pat = pat->next;
}
}
htab_clear_slot (abstract_pending_vars, slot);
input_location = cur_loc;
}
/* If TYPE has abstract virtual functions, issue an error about trying
to create an object of that type. DECL is the object declared, or
NULL_TREE if the declaration is unavailable. Returns 1 if an error
......@@ -125,7 +238,45 @@ abstract_virtuals_error (tree decl, tree type)
tree u;
tree tu;
if (!CLASS_TYPE_P (type) || !CLASSTYPE_PURE_VIRTUALS (type))
/* This function applies only to classes. Any other entity can never
be abstract. */
if (!CLASS_TYPE_P (type))
return 0;
/* If the type is incomplete, we register it within a hash table,
so that we can check again once it is completed. This makes sense
only for objects for which we have a declaration or at least a
name. */
if (!COMPLETE_TYPE_P (type))
{
void **slot;
struct pending_abstract_type *pat;
my_friendly_assert (!decl || (DECL_P (decl)
|| TREE_CODE (decl) == IDENTIFIER_NODE),
20040620_1);
if (!abstract_pending_vars)
abstract_pending_vars = htab_create_ggc (31, &pat_calc_hash,
&pat_compare, NULL);
slot = htab_find_slot_with_hash (abstract_pending_vars, type,
(hashval_t)TYPE_UID (type), INSERT);
pat = ggc_alloc (sizeof (struct pending_abstract_type));
pat->type = type;
pat->decl = decl;
pat->locus = ((decl && DECL_P (decl))
? DECL_SOURCE_LOCATION (decl)
: input_location);
pat->next = *slot;
*slot = pat;
return 0;
}
if (!CLASSTYPE_PURE_VIRTUALS (type))
return 0;
if (!TYPE_SIZE (type))
......@@ -133,11 +284,6 @@ abstract_virtuals_error (tree decl, tree type)
CLASSTYPE_PURE_VIRTUALS holds the inline friends. */
return 0;
if (dependent_type_p (type))
/* For a dependent type, we do not yet know which functions are pure
virtuals. */
return 0;
u = CLASSTYPE_PURE_VIRTUALS (type);
if (decl)
{
......@@ -160,6 +306,10 @@ abstract_virtuals_error (tree decl, tree type)
else if (TREE_CODE (decl) == FUNCTION_DECL)
cp_error_at ("invalid abstract return type for function `%+#D'",
decl);
else if (TREE_CODE (decl) == IDENTIFIER_NODE)
/* Here we do not have location information, so use error instead
of cp_error_at. */
error ("invalid abstract type `%T' for `%E'", type, decl);
else
cp_error_at ("invalid abstract type for `%+D'", decl);
}
......@@ -1405,3 +1555,6 @@ require_complete_eh_spec_types (tree fntype, tree decl)
}
}
}
#include "gt-cp-typeck2.h"
2004-07-12 Giovanni Bajo <giovannibajo@gcc.gnu.org>
PR c++/2204
* g++.dg/other/abstract2.C: New test.
2004-07-12 Paul Brook <paul@codesourcery.com>
* gfortran.dg/pointer_init_1.f90: New test.
......
// { dg-do compile }
// Contributed by Gabriel Dos Reis <gdr at integrable-solutions dot net>
// PR c++/2204: Check for parameters of abstract type in function declarations.
namespace N1 {
struct X;
struct Y1 {
void g(X parm1); // { dg-error "abstract" }
void g(X parm2[2]); // { dg-error "abstract" }
void g(X (*parm3)[2]); // { dg-error "abstract" }
};
template <int N>
struct Y2 {
void g(X parm4); // { dg-error "abstract" }
void g(X parm5[2]); // { dg-error "abstract" }
void g(X (*parm6)[2]); // { dg-error "abstract" }
};
struct X { // { dg-error "note" }
virtual void xfunc(void) = 0; // { dg-error "note" }
};
}
namespace N2 {
struct X1 { // { dg-error "note" }
virtual void xfunc(void) = 0; // { dg-error "note" }
void g(X1 parm7); // { dg-error "abstract" }
void g(X1 parm8[2]); // { dg-error "abstract" }
void g(X1 (*parm9)[2]); // { dg-error "abstract" }
};
template <int N>
struct X2 { // { dg-error "note" }
virtual void xfunc(void) = 0; // { dg-error "note" }
void g(X2 parm10); // { dg-error "abstract" }
void g(X2 parm11[2]); // { dg-error "abstract" }
void g(X2 (*parm12)[2]); // { dg-error "abstract" }
};
}
namespace N3 {
struct X { // { dg-error "note" "" }
virtual void xfunc(void) = 0; // { dg-error "note" }
};
void g(X parm13); // { dg-error "abstract" }
void g(X parm14[2]); // { dg-error "abstract" }
void g(X (*parm15)[2]); // { dg-error "abstract" }
template <int N>
void g(X parm16); // { dg-error "abstract" }
template <int N>
void g(X parm17[2]); // { dg-error "abstract" }
template <int N>
void g(X (*parm18)[2]); // { dg-error "abstract" }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment