Commit 2df663cc by Jason Merrill Committed by Jason Merrill

cp-tree.h (abstract_class_use): New enum.

	* cp-tree.h (abstract_class_use): New enum.
	* typeck2.c (pending_abstract_type): Add use field.
	(abstract_virtuals_error_sfinae): Add overloads taking
	abstract_class_use instead of tree.
	* typeck.c (build_static_cast_1): Call it.
	* except.c (is_admissible_throw_operand_or_catch_parameter): Call it.
	* pt.c: Adjust calls.
	* decl.c (cp_finish_decl): Don't handle functions specially.
	(grokdeclarator): Always check return type.
	* init.c (build_new_1): Adjust call.

From-SVN: r196735
parent 95ffad49
2013-03-16 Jason Merrill <jason@redhat.com> 2013-03-16 Jason Merrill <jason@redhat.com>
* cp-tree.h (abstract_class_use): New enum.
* typeck2.c (pending_abstract_type): Add use field.
(abstract_virtuals_error_sfinae): Add overloads taking
abstract_class_use instead of tree.
* typeck.c (build_static_cast_1): Call it.
* except.c (is_admissible_throw_operand_or_catch_parameter): Call it.
* pt.c: Adjust calls.
* decl.c (cp_finish_decl): Don't handle functions specially.
(grokdeclarator): Always check return type.
* init.c (build_new_1): Adjust call.
DR 337 DR 337
PR c++/17232 PR c++/17232
* pt.c (tsubst) [ARRAY_TYPE]: Use abstract_virtuals_error_sfinae. * pt.c (tsubst) [ARRAY_TYPE]: Use abstract_virtuals_error_sfinae.
......
...@@ -463,6 +463,19 @@ typedef enum impl_conv_void { ...@@ -463,6 +463,19 @@ typedef enum impl_conv_void {
ICV_THIRD_IN_FOR /* for increment expression */ ICV_THIRD_IN_FOR /* for increment expression */
} impl_conv_void; } impl_conv_void;
/* Possible invalid uses of an abstract class that might not have a
specific associated declaration. */
typedef enum abstract_class_use {
ACU_UNKNOWN, /* unknown or decl provided */
ACU_CAST, /* cast to abstract class */
ACU_NEW, /* new-expression of abstract class */
ACU_THROW, /* throw-expression of abstract class */
ACU_CATCH, /* catch-parameter of abstract class */
ACU_ARRAY, /* array of abstract class */
ACU_RETURN, /* return type of abstract class */
ACU_PARM /* parameter type of abstract class */
} abstract_class_use;
/* Macros for access to language-specific slots in an identifier. */ /* Macros for access to language-specific slots in an identifier. */
#define IDENTIFIER_NAMESPACE_BINDINGS(NODE) \ #define IDENTIFIER_NAMESPACE_BINDINGS(NODE) \
...@@ -5983,7 +5996,9 @@ extern tree binfo_or_else (tree, tree); ...@@ -5983,7 +5996,9 @@ extern tree binfo_or_else (tree, tree);
extern void cxx_readonly_error (tree, enum lvalue_use); extern void cxx_readonly_error (tree, enum lvalue_use);
extern void complete_type_check_abstract (tree); extern void complete_type_check_abstract (tree);
extern int abstract_virtuals_error (tree, tree); extern int abstract_virtuals_error (tree, tree);
extern int abstract_virtuals_error (abstract_class_use, tree);
extern int abstract_virtuals_error_sfinae (tree, tree, tsubst_flags_t); extern int abstract_virtuals_error_sfinae (tree, tree, tsubst_flags_t);
extern int abstract_virtuals_error_sfinae (abstract_class_use, tree, tsubst_flags_t);
extern tree store_init_value (tree, tree, vec<tree, va_gc>**, int); extern tree store_init_value (tree, tree, vec<tree, va_gc>**, int);
extern void check_narrowing (tree, tree); extern void check_narrowing (tree, tree);
......
...@@ -6434,11 +6434,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, ...@@ -6434,11 +6434,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
/* Check for abstractness of the type. Notice that there is no /* Check for abstractness of the type. Notice that there is no
need to strip array types here since the check for those types need to strip array types here since the check for those types
is already done within create_array_type_for_decl. */ is already done within create_array_type_for_decl. */
if (TREE_CODE (type) == FUNCTION_TYPE abstract_virtuals_error (decl, type);
|| TREE_CODE (type) == METHOD_TYPE)
abstract_virtuals_error (decl, TREE_TYPE (type));
else
abstract_virtuals_error (decl, type);
if (TREE_TYPE (decl) == error_mark_node) if (TREE_TYPE (decl) == error_mark_node)
/* No initialization required. */ /* No initialization required. */
...@@ -8656,6 +8652,7 @@ grokdeclarator (const cp_declarator *declarator, ...@@ -8656,6 +8652,7 @@ grokdeclarator (const cp_declarator *declarator,
bool template_type_arg = false; bool template_type_arg = false;
bool template_parm_flag = false; bool template_parm_flag = false;
bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr); bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
source_location saved_loc = input_location;
const char *errmsg; const char *errmsg;
signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed); signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
...@@ -9340,7 +9337,6 @@ grokdeclarator (const cp_declarator *declarator, ...@@ -9340,7 +9337,6 @@ grokdeclarator (const cp_declarator *declarator,
if (declspecs->std_attributes) if (declspecs->std_attributes)
{ {
/* Apply the c++11 attributes to the type preceding them. */ /* Apply the c++11 attributes to the type preceding them. */
source_location saved_loc = input_location;
input_location = declspecs->locations[ds_std_attribute]; input_location = declspecs->locations[ds_std_attribute];
decl_attributes (&type, declspecs->std_attributes, 0); decl_attributes (&type, declspecs->std_attributes, 0);
input_location = saved_loc; input_location = saved_loc;
...@@ -9428,11 +9424,10 @@ grokdeclarator (const cp_declarator *declarator, ...@@ -9428,11 +9424,10 @@ grokdeclarator (const cp_declarator *declarator,
error ("%qs declared as function returning an array", name); error ("%qs declared as function returning an array", name);
return error_mark_node; return error_mark_node;
} }
/* When decl_context == NORMAL we emit a better error message
later in abstract_virtuals_error. */ input_location = declspecs->locations[ds_type_spec];
if (decl_context == TYPENAME && ABSTRACT_CLASS_TYPE_P (type)) abstract_virtuals_error (ACU_RETURN, type);
error ("%qs declared as function returning an abstract " input_location = saved_loc;
"class type", name);
/* Pick up type qualifiers which should be applied to `this'. */ /* Pick up type qualifiers which should be applied to `this'. */
memfn_quals = declarator->u.function.qualifiers; memfn_quals = declarator->u.function.qualifiers;
......
...@@ -972,16 +972,8 @@ is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw) ...@@ -972,16 +972,8 @@ is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw)
/* 10.4/3 An abstract class shall not be used as a parameter type, /* 10.4/3 An abstract class shall not be used as a parameter type,
as a function return type or as type of an explicit as a function return type or as type of an explicit
conversion. */ conversion. */
else if (ABSTRACT_CLASS_TYPE_P (type)) else if (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type))
{ return false;
if (is_throw)
error ("expression %qE of abstract class type %qT cannot "
"be used in throw-expression", expr, type);
else
error ("cannot declare catch parameter to be of abstract "
"class type %qT", type);
return false;
}
else if (!is_throw else if (!is_throw
&& TREE_CODE (type) == REFERENCE_TYPE && TREE_CODE (type) == REFERENCE_TYPE
&& TYPE_REF_IS_RVALUE (type)) && TYPE_REF_IS_RVALUE (type))
......
...@@ -2301,7 +2301,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, ...@@ -2301,7 +2301,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
return error_mark_node; return error_mark_node;
} }
if (abstract_virtuals_error_sfinae (NULL_TREE, elt_type, complain)) if (abstract_virtuals_error_sfinae (ACU_NEW, elt_type, complain))
return error_mark_node; return error_mark_node;
is_initialized = (type_build_ctor_call (elt_type) || *init != NULL); is_initialized = (type_build_ctor_call (elt_type) || *init != NULL);
......
...@@ -10851,7 +10851,7 @@ tsubst_arg_types (tree arg_types, ...@@ -10851,7 +10851,7 @@ tsubst_arg_types (tree arg_types,
return error_mark_node; return error_mark_node;
} }
/* DR 657. */ /* DR 657. */
if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain)) if (abstract_virtuals_error_sfinae (ACU_PARM, type, complain))
return error_mark_node; return error_mark_node;
/* Do array-to-pointer, function-to-pointer conversion, and ignore /* Do array-to-pointer, function-to-pointer conversion, and ignore
...@@ -10930,7 +10930,7 @@ tsubst_function_type (tree t, ...@@ -10930,7 +10930,7 @@ tsubst_function_type (tree t,
return error_mark_node; return error_mark_node;
} }
/* And DR 657. */ /* And DR 657. */
if (abstract_virtuals_error_sfinae (NULL_TREE, return_type, complain)) if (abstract_virtuals_error_sfinae (ACU_RETURN, return_type, complain))
return error_mark_node; return error_mark_node;
/* Substitute the argument types. */ /* Substitute the argument types. */
...@@ -11654,7 +11654,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -11654,7 +11654,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
return error_mark_node; return error_mark_node;
} }
if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain)) if (abstract_virtuals_error_sfinae (ACU_ARRAY, type, complain))
return error_mark_node; return error_mark_node;
r = build_cplus_array_type (type, domain); r = build_cplus_array_type (type, domain);
......
...@@ -6238,6 +6238,12 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p, ...@@ -6238,6 +6238,12 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
if (TREE_CODE (type) == VOID_TYPE) if (TREE_CODE (type) == VOID_TYPE)
return convert_to_void (expr, ICV_CAST, complain); return convert_to_void (expr, ICV_CAST, complain);
/* [class.abstract]
An abstract class shall not be used ... as the type of an explicit
conversion. */
if (abstract_virtuals_error_sfinae (ACU_CAST, type, complain))
return error_mark_node;
/* [expr.static.cast] /* [expr.static.cast]
An expression e can be explicitly converted to a type T using a An expression e can be explicitly converted to a type T using a
......
...@@ -141,6 +141,9 @@ struct GTY((chain_next ("%h.next"))) pending_abstract_type { ...@@ -141,6 +141,9 @@ struct GTY((chain_next ("%h.next"))) pending_abstract_type {
/* Type which will be checked for abstractness. */ /* Type which will be checked for abstractness. */
tree type; tree type;
/* Kind of use in an unnamed declarator. */
abstract_class_use use;
/* Position of the declaration. This is only needed for IDENTIFIER_NODEs, /* Position of the declaration. This is only needed for IDENTIFIER_NODEs,
because DECLs already carry locus information. */ because DECLs already carry locus information. */
location_t locus; location_t locus;
...@@ -181,6 +184,7 @@ pat_compare (const void* val1, const void* val2) ...@@ -181,6 +184,7 @@ pat_compare (const void* val1, const void* val2)
static GTY ((param_is (struct pending_abstract_type))) static GTY ((param_is (struct pending_abstract_type)))
htab_t abstract_pending_vars = NULL; htab_t abstract_pending_vars = NULL;
static int abstract_virtuals_error_sfinae (tree, tree, abstract_class_use, tsubst_flags_t);
/* This function is called after TYPE is completed, and will check if there /* 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 are pending declarations for which we still need to verify the abstractness
...@@ -231,7 +235,8 @@ complete_type_check_abstract (tree type) ...@@ -231,7 +235,8 @@ complete_type_check_abstract (tree type)
location. Notice that this is only needed if the decl is an location. Notice that this is only needed if the decl is an
IDENTIFIER_NODE. */ IDENTIFIER_NODE. */
input_location = pat->locus; input_location = pat->locus;
abstract_virtuals_error (pat->decl, pat->type); abstract_virtuals_error_sfinae (pat->decl, pat->type, pat->use,
tf_warning_or_error);
pat = pat->next; pat = pat->next;
} }
} }
...@@ -244,11 +249,13 @@ complete_type_check_abstract (tree type) ...@@ -244,11 +249,13 @@ complete_type_check_abstract (tree type)
/* 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, in which case USE specifies
occurred; zero if all was well. */ the kind of invalid use. Returns 1 if an error occurred; zero if
all was well. */
int static int
abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain) abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
tsubst_flags_t complain)
{ {
vec<tree, va_gc> *pure; vec<tree, va_gc> *pure;
...@@ -284,6 +291,7 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain) ...@@ -284,6 +291,7 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
pat = ggc_alloc_pending_abstract_type (); pat = ggc_alloc_pending_abstract_type ();
pat->type = type; pat->type = type;
pat->decl = decl; pat->decl = decl;
pat->use = use;
pat->locus = ((decl && DECL_P (decl)) pat->locus = ((decl && DECL_P (decl))
? DECL_SOURCE_LOCATION (decl) ? DECL_SOURCE_LOCATION (decl)
: input_location); : input_location);
...@@ -312,8 +320,14 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain) ...@@ -312,8 +320,14 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
error ("cannot declare variable %q+D to be of abstract " error ("cannot declare variable %q+D to be of abstract "
"type %qT", decl, type); "type %qT", decl, type);
else if (TREE_CODE (decl) == PARM_DECL) else if (TREE_CODE (decl) == PARM_DECL)
error ("cannot declare parameter %q+D to be of abstract type %qT", {
decl, type); if (DECL_NAME (decl))
error ("cannot declare parameter %q+D to be of abstract type %qT",
decl, type);
else
error ("cannot declare parameter to be of abstract type %qT",
type);
}
else if (TREE_CODE (decl) == FIELD_DECL) else if (TREE_CODE (decl) == FIELD_DECL)
error ("cannot declare field %q+D to be of abstract type %qT", error ("cannot declare field %q+D to be of abstract type %qT",
decl, type); decl, type);
...@@ -328,8 +342,34 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain) ...@@ -328,8 +342,34 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
else else
error ("invalid abstract type for %q+D", decl); error ("invalid abstract type for %q+D", decl);
} }
else else switch (use)
error ("cannot allocate an object of abstract type %qT", type); {
case ACU_ARRAY:
error ("creating array of %qT, which is an abstract class type", type);
break;
case ACU_CAST:
error ("invalid cast to abstract class type %qT", type);
break;
case ACU_NEW:
error ("invalid new-expression of abstract class type %qT", type);
break;
case ACU_RETURN:
error ("invalid abstract return type %qT", type);
break;
case ACU_PARM:
error ("invalid abstract parameter type %qT", type);
break;
case ACU_THROW:
error ("expression of abstract class type %qT cannot "
"be used in throw-expression", type);
break;
case ACU_CATCH:
error ("cannot declare catch parameter to be of abstract "
"class type %qT", type);
break;
default:
error ("cannot allocate an object of abstract type %qT", type);
}
/* Only go through this once. */ /* Only go through this once. */
if (pure->length ()) if (pure->length ())
...@@ -351,14 +391,24 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain) ...@@ -351,14 +391,24 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
again. */ again. */
pure->truncate (0); pure->truncate (0);
} }
else
inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)),
" since type %qT has pure virtual functions",
type);
return 1; return 1;
} }
int
abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
{
return abstract_virtuals_error_sfinae (decl, type, ACU_UNKNOWN, complain);
}
int
abstract_virtuals_error_sfinae (abstract_class_use use, tree type,
tsubst_flags_t complain)
{
return abstract_virtuals_error_sfinae (NULL_TREE, type, use, complain);
}
/* Wrapper for the above function in the common case of wanting errors. */ /* Wrapper for the above function in the common case of wanting errors. */
int int
...@@ -367,6 +417,12 @@ abstract_virtuals_error (tree decl, tree type) ...@@ -367,6 +417,12 @@ abstract_virtuals_error (tree decl, tree type)
return abstract_virtuals_error_sfinae (decl, type, tf_warning_or_error); return abstract_virtuals_error_sfinae (decl, type, tf_warning_or_error);
} }
int
abstract_virtuals_error (abstract_class_use use, tree type)
{
return abstract_virtuals_error_sfinae (use, type, tf_warning_or_error);
}
/* Print an error message for invalid use of an incomplete type. /* Print an error message for invalid use of an incomplete type.
VALUE is the expression that was used (or 0 if that isn't known) VALUE is the expression that was used (or 0 if that isn't known)
and TYPE is the type that was invalid. DIAG_KIND indicates the and TYPE is the type that was invalid. DIAG_KIND indicates the
...@@ -1733,7 +1789,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain) ...@@ -1733,7 +1789,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
if (!complete_type_or_maybe_complain (type, NULL_TREE, complain)) if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
return error_mark_node; return error_mark_node;
if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain)) if (abstract_virtuals_error_sfinae (ACU_CAST, type, complain))
return error_mark_node; return error_mark_node;
/* [expr.type.conv] /* [expr.type.conv]
......
struct A
{
virtual void f() = 0;
};
typedef A (*fp)(); // { 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