From 2df663ccedf750ffe5ac481b3fe2aaff0d985a7f Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 16 Mar 2013 22:36:55 -0400 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 11 +++++ gcc/cp/cp-tree.h | 15 ++++++ gcc/cp/decl.c | 17 +++---- gcc/cp/except.c | 12 +---- gcc/cp/init.c | 2 +- gcc/cp/pt.c | 6 +-- gcc/cp/typeck.c | 6 +++ gcc/cp/typeck2.c | 84 ++++++++++++++++++++++++++++------ gcc/testsuite/g++.dg/other/abstract5.C | 6 +++ 9 files changed, 120 insertions(+), 39 deletions(-) create mode 100644 gcc/testsuite/g++.dg/other/abstract5.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 20414dc..b57800e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,16 @@ 2013-03-16 Jason Merrill + * 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. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d9496d2..53940a6 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -463,6 +463,19 @@ typedef enum impl_conv_void { 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) \ @@ -5983,7 +5996,9 @@ extern tree binfo_or_else (tree, tree); 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**, int); extern void check_narrowing (tree, tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 0e66840..40152b1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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 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. */ @@ -8656,6 +8652,7 @@ grokdeclarator (const cp_declarator *declarator, 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); @@ -9340,7 +9337,6 @@ grokdeclarator (const cp_declarator *declarator, 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; @@ -9428,11 +9424,10 @@ grokdeclarator (const cp_declarator *declarator, 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; diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 216ec10..52ba1cd 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -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, 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)) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 697f11f..679c47d 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2301,7 +2301,7 @@ build_new_1 (vec **placement, tree type, tree nelts, 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); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ce07fa4..edc2d0b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10851,7 +10851,7 @@ tsubst_arg_types (tree arg_types, 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 @@ -10930,7 +10930,7 @@ tsubst_function_type (tree t, 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. */ @@ -11654,7 +11654,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) 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); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 96e0ad8..3ced858 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -6238,6 +6238,12 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p, 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 diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index dc17776..3bac67c 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -141,6 +141,9 @@ struct GTY((chain_next ("%h.next"))) pending_abstract_type { /* 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; @@ -181,6 +184,7 @@ pat_compare (const void* val1, const void* val2) 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 @@ -231,7 +235,8 @@ complete_type_check_abstract (tree type) 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; } } @@ -244,11 +249,13 @@ complete_type_check_abstract (tree type) /* 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 *pure; @@ -284,6 +291,7 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain) 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); @@ -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 " "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); @@ -328,8 +342,34 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain) 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 ()) @@ -351,14 +391,24 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain) 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 @@ -367,6 +417,12 @@ abstract_virtuals_error (tree decl, tree type) 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 @@ -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)) 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] diff --git a/gcc/testsuite/g++.dg/other/abstract5.C b/gcc/testsuite/g++.dg/other/abstract5.C new file mode 100644 index 0000000..d13dd9e --- /dev/null +++ b/gcc/testsuite/g++.dg/other/abstract5.C @@ -0,0 +1,6 @@ +struct A +{ + virtual void f() = 0; +}; + +typedef A (*fp)(); // { dg-error "abstract" } -- 2.7.4