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> 2004-07-12 Paolo Bonzini <bonzini@gnu.org>
PR tree-optimization/14107 PR tree-optimization/14107
......
...@@ -99,7 +99,7 @@ $(srcdir)/cp/cfns.h: $(srcdir)/cp/cfns.gperf ...@@ -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 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-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: # Build hooks:
...@@ -231,7 +231,7 @@ cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) flags.h cp/decl.h stack.h \ ...@@ -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) \ 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 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) \ 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 \ cp/typeck.o: cp/typeck.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) $(EXPR_H) toplev.h \
diagnostic.h convert.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 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) ...@@ -5270,8 +5270,24 @@ finish_struct (tree t, tree attributes)
if (processing_template_decl) if (processing_template_decl)
{ {
tree x;
finish_struct_methods (t); finish_struct_methods (t);
TYPE_SIZE (t) = bitsize_zero_node; 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 else
finish_struct_1 (t); finish_struct_1 (t);
......
...@@ -34,4 +34,4 @@ stagestuff="g++\$(exeext) g++-cross\$(exeext) cc1plus\$(exeext)" ...@@ -34,4 +34,4 @@ stagestuff="g++\$(exeext) g++-cross\$(exeext) cc1plus\$(exeext)"
target_libs="target-libstdc++-v3 target-gperf" 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); ...@@ -4315,6 +4315,7 @@ extern void cxx_incomplete_type_error (tree, tree);
extern tree error_not_base_type (tree, tree); extern tree error_not_base_type (tree, tree);
extern tree binfo_or_else (tree, tree); extern tree binfo_or_else (tree, tree);
extern void readonly_error (tree, const char *, int); extern void readonly_error (tree, const char *, int);
extern void complete_type_check_abstract (tree);
extern int abstract_virtuals_error (tree, tree); extern int abstract_virtuals_error (tree, tree);
extern tree store_init_value (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) ...@@ -4821,21 +4821,12 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
make_rtl_for_nonlocal_decl (decl, init, asmspec); 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 if (TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE) || TREE_CODE (type) == METHOD_TYPE)
abstract_virtuals_error (decl, abstract_virtuals_error (decl, TREE_TYPE (type));
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));
}
else else
abstract_virtuals_error (decl, type); abstract_virtuals_error (decl, type);
...@@ -6162,6 +6153,11 @@ create_array_type_for_decl (tree name, tree type, tree size) ...@@ -6162,6 +6153,11 @@ create_array_type_for_decl (tree name, tree type, tree size)
if (size) if (size)
itype = compute_array_index_type (name, 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); return build_cplus_array_type (type, itype);
} }
...@@ -10592,6 +10588,9 @@ complete_vars (tree type) ...@@ -10592,6 +10588,9 @@ complete_vars (tree type)
else else
list = &TREE_CHAIN (*list); 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 /* 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) ...@@ -114,6 +114,119 @@ readonly_error (tree arg, const char* string, int soft)
(*fn) ("%s of read-only location", string); (*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 /* If TYPE has abstract virtual functions, issue an error about trying
to create an object of that type. DECL is the object declared, or 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 NULL_TREE if the declaration is unavailable. Returns 1 if an error
...@@ -125,7 +238,45 @@ abstract_virtuals_error (tree decl, tree type) ...@@ -125,7 +238,45 @@ abstract_virtuals_error (tree decl, tree type)
tree u; tree u;
tree tu; 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; return 0;
if (!TYPE_SIZE (type)) if (!TYPE_SIZE (type))
...@@ -133,11 +284,6 @@ abstract_virtuals_error (tree decl, tree type) ...@@ -133,11 +284,6 @@ abstract_virtuals_error (tree decl, tree type)
CLASSTYPE_PURE_VIRTUALS holds the inline friends. */ CLASSTYPE_PURE_VIRTUALS holds the inline friends. */
return 0; 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); u = CLASSTYPE_PURE_VIRTUALS (type);
if (decl) if (decl)
{ {
...@@ -160,6 +306,10 @@ abstract_virtuals_error (tree decl, tree type) ...@@ -160,6 +306,10 @@ abstract_virtuals_error (tree decl, tree type)
else if (TREE_CODE (decl) == FUNCTION_DECL) else if (TREE_CODE (decl) == FUNCTION_DECL)
cp_error_at ("invalid abstract return type for function `%+#D'", cp_error_at ("invalid abstract return type for function `%+#D'",
decl); 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 else
cp_error_at ("invalid abstract type for `%+D'", decl); cp_error_at ("invalid abstract type for `%+D'", decl);
} }
...@@ -1405,3 +1555,6 @@ require_complete_eh_spec_types (tree fntype, tree 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> 2004-07-12 Paul Brook <paul@codesourcery.com>
* gfortran.dg/pointer_init_1.f90: New test. * 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