* 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
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
PR c++/17232
* pt.c (tsubst) [ARRAY_TYPE]: Use abstract_virtuals_error_sfinae.
ICV_THIRD_IN_FOR /* for increment expression */
} 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. */
#define IDENTIFIER_NAMESPACE_BINDINGS(NODE) \
extern void cxx_readonly_error (tree, enum lvalue_use);
extern void complete_type_check_abstract (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 (abstract_class_use, tree, tsubst_flags_t);
extern tree store_init_value (tree, tree, vec<tree, va_gc>**, int);
extern void check_narrowing (tree, tree);
/* 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, TREE_TYPE (type));
- else
- abstract_virtuals_error (decl, type);
+ abstract_virtuals_error (decl, type);
if (TREE_TYPE (decl) == error_mark_node)
/* No initialization required. */
bool template_type_arg = false;
bool template_parm_flag = false;
bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
+ source_location saved_loc = input_location;
const char *errmsg;
signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
if (declspecs->std_attributes)
{
/* Apply the c++11 attributes to the type preceding them. */
- source_location saved_loc = input_location;
input_location = declspecs->locations[ds_std_attribute];
decl_attributes (&type, declspecs->std_attributes, 0);
input_location = saved_loc;
error ("%qs declared as function returning an array", name);
return error_mark_node;
}
- /* When decl_context == NORMAL we emit a better error message
- later in abstract_virtuals_error. */
- if (decl_context == TYPENAME && ABSTRACT_CLASS_TYPE_P (type))
- error ("%qs declared as function returning an abstract "
- "class type", name);
+
+ input_location = declspecs->locations[ds_type_spec];
+ abstract_virtuals_error (ACU_RETURN, type);
+ input_location = saved_loc;
/* Pick up type qualifiers which should be applied to `this'. */
memfn_quals = declarator->u.function.qualifiers;
/* 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
conversion. */
- else if (ABSTRACT_CLASS_TYPE_P (type))
- {
- 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 (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type))
+ return false;
else if (!is_throw
&& TREE_CODE (type) == REFERENCE_TYPE
&& TYPE_REF_IS_RVALUE (type))
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;
is_initialized = (type_build_ctor_call (elt_type) || *init != NULL);
return error_mark_node;
}
/* DR 657. */
- if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain))
+ if (abstract_virtuals_error_sfinae (ACU_PARM, type, complain))
return error_mark_node;
/* Do array-to-pointer, function-to-pointer conversion, and ignore
return error_mark_node;
}
/* 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;
/* Substitute the argument types. */
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;
r = build_cplus_array_type (type, domain);
if (TREE_CODE (type) == VOID_TYPE)
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]
An expression e can be explicitly converted to a type T using a
/* Type which will be checked for abstractness. */
tree type;
+ /* Kind of use in an unnamed declarator. */
+ abstract_class_use use;
+
/* Position of the declaration. This is only needed for IDENTIFIER_NODEs,
because DECLs already carry locus information. */
location_t locus;
static GTY ((param_is (struct pending_abstract_type)))
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
are pending declarations for which we still need to verify the abstractness
location. Notice that this is only needed if the decl is an
IDENTIFIER_NODE. */
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;
}
}
/* 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
- occurred; zero if all was well. */
+ NULL_TREE if the declaration is unavailable, in which case USE specifies
+ the kind of invalid use. Returns 1 if an error occurred; zero if
+ all was well. */
-int
-abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
+static int
+abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
+ tsubst_flags_t complain)
{
vec<tree, va_gc> *pure;
pat = ggc_alloc_pending_abstract_type ();
pat->type = type;
pat->decl = decl;
+ pat->use = use;
pat->locus = ((decl && DECL_P (decl))
? DECL_SOURCE_LOCATION (decl)
: input_location);
error ("cannot declare variable %q+D to be of abstract "
"type %qT", decl, type);
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)
error ("cannot declare field %q+D to be of abstract type %qT",
decl, type);
else
error ("invalid abstract type for %q+D", decl);
}
- else
- error ("cannot allocate an object of abstract type %qT", type);
+ else switch (use)
+ {
+ 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. */
if (pure->length ())
again. */
pure->truncate (0);
}
- else
- inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)),
- " since type %qT has pure virtual functions",
- type);
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. */
int
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.
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
if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
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;
/* [expr.type.conv]
--- /dev/null
+struct A
+{
+ virtual void f() = 0;
+};
+
+typedef A (*fp)(); // { dg-error "abstract" }