diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 9861be1f8561..3a6ad1332a78 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -213,6 +213,7 @@ static conversion *merge_conversion_sequences (conversion *, conversion *); static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t); static conversion *build_identity_conv (tree, tree); static inline bool conv_binds_to_array_of_unknown_bound (conversion *); +static bool conv_is_prvalue (conversion *); static tree prevent_lifetime_extension (tree); /* Returns nonzero iff the destructor name specified in NAME matches BASETYPE. @@ -1963,14 +1964,12 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, return conv; } -/* Returns the implicit conversion sequence (see [over.ics]) from type - FROM to type TO. The optional expression EXPR may affect the - conversion. FLAGS are the usual overloading flags. If C_CAST_P is - true, this conversion is coming from a C-style cast. */ +/* Most of the implementation of implicit_conversion, with the same + parameters. */ static conversion * -implicit_conversion (tree to, tree from, tree expr, bool c_cast_p, - int flags, tsubst_flags_t complain) +implicit_conversion_1 (tree to, tree from, tree expr, bool c_cast_p, + int flags, tsubst_flags_t complain) { conversion *conv; @@ -2096,6 +2095,26 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p, return NULL; } +/* Returns the implicit conversion sequence (see [over.ics]) from type + FROM to type TO. The optional expression EXPR may affect the + conversion. FLAGS are the usual overloading flags. If C_CAST_P is + true, this conversion is coming from a C-style cast. */ + +static conversion * +implicit_conversion (tree to, tree from, tree expr, bool c_cast_p, + int flags, tsubst_flags_t complain) +{ + conversion *conv = implicit_conversion_1 (to, from, expr, c_cast_p, + flags, complain); + if (!conv || conv->bad_p) + return conv; + if (conv_is_prvalue (conv) + && CLASS_TYPE_P (conv->type) + && CLASSTYPE_PURE_VIRTUALS (conv->type)) + conv->bad_p = true; + return conv; +} + /* Like implicit_conversion, but return NULL if the conversion is bad. This is not static so that check_non_deducible_conversion can call it within @@ -7407,7 +7426,7 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, else if (t->kind == ck_identity) break; } - if (!complained) + if (!complained && expr != error_mark_node) { range_label_for_type_mismatch label (TREE_TYPE (expr), totype); gcc_rich_location richloc (loc, &label); @@ -8438,6 +8457,24 @@ unsafe_copy_elision_p (tree target, tree exp) && !AGGR_INIT_VIA_CTOR_P (init)); } +/* True IFF the result of the conversion C is a prvalue. */ + +static bool +conv_is_prvalue (conversion *c) +{ + if (c->kind == ck_rvalue) + return true; + if (c->kind == ck_base && c->need_temporary_p) + return true; + if (c->kind == ck_user && !TYPE_REF_P (c->type)) + return true; + if (c->kind == ck_identity && c->u.expr + && TREE_CODE (c->u.expr) == TARGET_EXPR) + return true; + + return false; +} + /* True iff C is a conversion that binds a reference to a prvalue. */ static bool @@ -8448,17 +8485,7 @@ conv_binds_ref_to_prvalue (conversion *c) if (c->need_temporary_p) return true; - c = next_conversion (c); - - if (c->kind == ck_rvalue) - return true; - if (c->kind == ck_user && !TYPE_REF_P (c->type)) - return true; - if (c->kind == ck_identity && c->u.expr - && TREE_CODE (c->u.expr) == TARGET_EXPR) - return true; - - return false; + return conv_is_prvalue (next_conversion (c)); } /* True iff converting EXPR to a reference type TYPE does not involve diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c52111e329ce..89bae06cd6bb 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7926,10 +7926,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, 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. */ - abstract_virtuals_error (decl, type); + /* Check for abstractness of the type. */ + if (var_definition_p) + abstract_virtuals_error (decl, type); if (TREE_TYPE (decl) == error_mark_node) /* No initialization required. */ @@ -10701,11 +10700,6 @@ create_array_type_for_decl (tree name, tree type, tree size, location_t loc) itype = compute_array_index_type_loc (loc, name, size, tf_warning_or_error); - /* [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); } @@ -12097,11 +12091,6 @@ grokdeclarator (const cp_declarator *declarator, /* Declaring a function type. */ - { - iloc_sentinel ils (declspecs->locations[ds_type_spec]); - abstract_virtuals_error (ACU_RETURN, type); - } - /* Pick up type qualifiers which should be applied to `this'. */ memfn_quals = declarator->u.function.qualifiers; /* Pick up virt-specifiers. */ @@ -13872,6 +13861,7 @@ require_complete_types_for_parms (tree parms) relayout_decl (parms); DECL_ARG_TYPE (parms) = type_passed_as (TREE_TYPE (parms)); + abstract_virtuals_error (parms, TREE_TYPE (parms)); maybe_warn_parm_abi (TREE_TYPE (parms), DECL_SOURCE_LOCATION (parms)); } @@ -14109,9 +14099,6 @@ grokparms (tree parmlist, tree *parms) type = build_pointer_type (type); TREE_TYPE (decl) = type; } - else if (abstract_virtuals_error (decl, type)) - /* Ignore any default argument. */ - init = NULL_TREE; else if (cxx_dialect < cxx17 && INDIRECT_TYPE_P (type)) { /* Before C++17 DR 393: @@ -17427,9 +17414,6 @@ complete_vars (tree type) else ix++; } - - /* 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 and return an diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a932c2133e17..1babf833d321 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -14932,9 +14932,6 @@ tsubst_arg_types (tree arg_types, } return error_mark_node; } - /* DR 657. */ - if (abstract_virtuals_error_sfinae (ACU_PARM, type, complain)) - return error_mark_node; /* Do array-to-pointer, function-to-pointer conversion, and ignore top-level qualifiers as required. */ @@ -15052,9 +15049,6 @@ tsubst_function_type (tree t, } return error_mark_node; } - /* And DR 657. */ - if (abstract_virtuals_error_sfinae (ACU_RETURN, return_type, complain)) - return error_mark_node; if (!late_return_type_p) { @@ -15880,9 +15874,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) return error_mark_node; } - if (abstract_virtuals_error_sfinae (ACU_ARRAY, type, complain)) - return error_mark_node; - r = build_cplus_array_type (type, domain); if (!valid_array_size_p (input_location, r, in_decl, diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 445e2a211c86..412869946a53 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -123,123 +123,6 @@ cxx_readonly_error (location_t loc, tree arg, enum lvalue_use errstring) readonly_error (loc, arg, errstring); } -/* Structure that holds information about declarations whose type was - incomplete and we could not check whether it was abstract or not. */ - -struct GTY((chain_next ("%h.next"), for_user)) pending_abstract_type { - /* 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; - - /* Kind of use in an unnamed declarator. */ - enum abstract_class_use use; - - /* 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; -}; - -struct abstract_type_hasher : ggc_ptr_hash -{ - typedef tree compare_type; - static hashval_t hash (pending_abstract_type *); - static bool equal (pending_abstract_type *, tree); -}; - -/* Compute the hash value of the node VAL. This function is used by the - hash table abstract_pending_vars. */ - -hashval_t -abstract_type_hasher::hash (pending_abstract_type *pat) -{ - 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. */ - -bool -abstract_type_hasher::equal (pending_abstract_type *pat1, tree type2) -{ - 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 (()) hash_table *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 - of TYPE, and emit a diagnostic (through abstract_virtuals_error) if TYPE - turned out to be incomplete. */ - -void -complete_type_check_abstract (tree type) -{ - struct pending_abstract_type *pat; - location_t cur_loc = input_location; - - gcc_assert (COMPLETE_TYPE_P (type)); - - if (!abstract_pending_vars) - return; - - /* Retrieve the list of pending declarations for this type. */ - pending_abstract_type **slot - = abstract_pending_vars->find_slot_with_hash (type, TYPE_UID (type), - NO_INSERT); - if (!slot) - return; - pat = *slot; - gcc_assert (pat); - - /* 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 diagnostic if the type is abstract. */ - while (pat) - { - gcc_assert (type == pat->type); - - /* 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. */ - input_location = pat->locus; - abstract_virtuals_error_sfinae (pat->decl, pat->type, pat->use, - tf_warning_or_error); - pat = pat->next; - } - } - - abstract_pending_vars->clear_slot (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, in which case USE specifies @@ -252,6 +135,13 @@ abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use, { vec *pure; + if (TREE_CODE (type) == ARRAY_TYPE) + { + decl = NULL_TREE; + use = ACU_ARRAY; + type = strip_array_types (type); + } + /* This function applies only to classes. Any other entity can never be abstract. */ if (!CLASS_TYPE_P (type)) @@ -266,38 +156,6 @@ abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use, complete_type (type); #endif - /* 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) && (complain & tf_error)) - { - struct pending_abstract_type *pat; - - gcc_assert (!decl || DECL_P (decl) || identifier_p (decl)); - - if (!abstract_pending_vars) - abstract_pending_vars - = hash_table::create_ggc (31); - - pending_abstract_type **slot - = abstract_pending_vars->find_slot_with_hash (type, TYPE_UID (type), - INSERT); - - pat = ggc_alloc (); - pat->type = type; - pat->decl = decl; - pat->use = use; - pat->locus = ((decl && DECL_P (decl)) - ? DECL_SOURCE_LOCATION (decl) - : input_location); - - pat->next = *slot; - *slot = pat; - - return 0; - } - if (!TYPE_SIZE (type)) /* TYPE is being defined, and during that time CLASSTYPE_PURE_VIRTUALS holds the inline friends. */ @@ -2594,6 +2452,3 @@ require_complete_eh_spec_types (tree fntype, tree decl) } } } - - -#include "gt-cp-typeck2.h" diff --git a/gcc/testsuite/g++.dg/other/abstract1.C b/gcc/testsuite/g++.dg/other/abstract1.C index 53d767acd453..6ded7ec75476 100644 --- a/gcc/testsuite/g++.dg/other/abstract1.C +++ b/gcc/testsuite/g++.dg/other/abstract1.C @@ -5,34 +5,38 @@ // c++/9256: Make sure that a pointer to an array of abstract elements // cannot be created, not even during template substitution (DR337). +// Changed massively by P0929R2: now only creating an object of the array type +// is ill-formed, not merely forming the array type. + struct Abstract { virtual void f() = 0; }; // { dg-message "note" } struct Complete { void f(); }; /* * TEST 1 - * Arrays of abstract elements cannot be declared. + * Arrays of abstract elements cannot be defined. */ Abstract a0[2]; // { dg-error "" } -Abstract (*a1)[2]; // { dg-error "" } -Abstract (**a2)[2]; // { dg-error "" } -Abstract (***a3)[2]; // { dg-error "" } +Abstract (*a1)[2]; +Abstract (**a2)[2]; +Abstract (***a3)[2]; Abstract *a4; Abstract *a5[2]; -Abstract (*a6[2])[2]; // { dg-error "" } +Abstract (*a6[2])[2]; Abstract **a7[2]; -Abstract *(*a8[2])[2]; -Abstract (**a9[2])[2]; // { dg-error "" } +Abstract *(*a8[2])[2]; +Abstract (**a9[2])[2]; /* * TEST 2 - * If a pointer to an array of abstract elements is created during template + * If an array of abstract elements is created during template * instantiation, an error should occur. */ template struct K { - T (*a)[2]; // { dg-error "abstract class type" } + T (*a1)[2]; + T (a2)[2]; // { dg-error "abstract" } }; template struct K; // { dg-message "required" } @@ -41,8 +45,9 @@ template struct K; // { dg-message "required" } /* * TEST 3 - * Deducing an array of abstract elements during type deduction is a silent - * failure (rejects overload). + + * Deducing an array of abstract elements during type deduction is no longer a + * silent failure. */ template struct StaticAssert; @@ -54,6 +59,6 @@ typedef struct { char x[2]; } No; template No is_abstract(U (*k)[1]); template Yes is_abstract(...); -StaticAssert(0)) == sizeof(Yes)> b1; +StaticAssert(0)) == sizeof(No)> b1; StaticAssert(0)) == sizeof(No)> b2; StaticAssert(0)) == sizeof(No)> b3; diff --git a/gcc/testsuite/g++.dg/other/abstract2.C b/gcc/testsuite/g++.dg/other/abstract2.C index 60a4e41b5a9f..0a8009e9bb39 100644 --- a/gcc/testsuite/g++.dg/other/abstract2.C +++ b/gcc/testsuite/g++.dg/other/abstract2.C @@ -5,54 +5,59 @@ 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 - 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-message "note" } virtual void xfunc(void) = 0; // { dg-message "note" } }; + + struct Y1 { + void g(X parm1) {} // { dg-error "abstract" } + void g(X parm2[2]) {} + void g(X (*parm3)[2]) {} + }; + + template + struct Y2 { + void g(X parm4) {} // { dg-error "abstract" } + void g(X parm5[2]) {} + void g(X (*parm6)[2]) {} + }; + + template struct Y2<42>; } namespace N2 { struct X1 { // { dg-message "note" } virtual void xfunc(void) = 0; // { dg-message "note" } - void g(X1 parm7); // { dg-error "abstract" } - void g(X1 parm8[2]); // { dg-error "abstract" } - void g(X1 (*parm9)[2]); // { dg-error "abstract" } + void g(X1 parm7) {} // { dg-error "abstract" } + void g(X1 parm8[2]) {} + void g(X1 (*parm9)[2]) {} }; template struct X2 { // { dg-message "note" } virtual void xfunc(void) = 0; // { dg-message "note" } - void g(X2 parm10); // { dg-error "abstract" } - void g(X2 parm11[2]); // { dg-error "abstract" } - void g(X2 (*parm12)[2]); // { dg-error "abstract" } + void g(X2 parm10) {} // { dg-error "abstract" } + void g(X2 parm11[2]) {} + void g(X2 (*parm12)[2]) {} }; + + template struct X2<42>; } namespace N3 { struct X { // { dg-message "note" } virtual void xfunc(void) = 0; // { dg-message "note" } }; - void g(X parm13); // { dg-error "abstract" } - void g(X parm14[2]); // { dg-error "abstract" } - void g(X (*parm15)[2]); // { dg-error "abstract" } + void g(X parm13) {} // { dg-error "abstract" } + void g(X parm14[2]) {} + void g(X (*parm15)[2]) {} - template - void g(X parm16); // { dg-error "abstract" } - template - void g(X parm17[2]); // { dg-error "abstract" } - template - void g(X (*parm18)[2]); // { dg-error "abstract" } + template + void g(X parm16) {} // { dg-error "abstract" } + template + void g(X parm17[2]) {} + template + void g(X (*parm18)[2]) {} + + template void g<42>(X); } diff --git a/gcc/testsuite/g++.dg/other/abstract4.C b/gcc/testsuite/g++.dg/other/abstract4.C index 68b2eb27b8c3..6a8c8c75918d 100644 --- a/gcc/testsuite/g++.dg/other/abstract4.C +++ b/gcc/testsuite/g++.dg/other/abstract4.C @@ -13,6 +13,6 @@ struct Abs int main() { - S s; // { dg-error "abstract" } - foo(); // { dg-error "abstract" } + S s; + foo(); } diff --git a/gcc/testsuite/g++.dg/other/abstract5.C b/gcc/testsuite/g++.dg/other/abstract5.C index d13dd9e5160e..c17d60d3a3a0 100644 --- a/gcc/testsuite/g++.dg/other/abstract5.C +++ b/gcc/testsuite/g++.dg/other/abstract5.C @@ -3,4 +3,4 @@ struct A virtual void f() = 0; }; -typedef A (*fp)(); // { dg-error "abstract" } +typedef A (*fp)(); diff --git a/gcc/testsuite/g++.dg/other/abstract8.C b/gcc/testsuite/g++.dg/other/abstract8.C new file mode 100644 index 000000000000..bc5afbbdc7f0 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/abstract8.C @@ -0,0 +1,40 @@ +// P0929R2: Checking for abstract class types. +// { dg-do compile { target c++11 } } +// { dg-additional-options -Wno-return-type } + +struct A +{ + virtual void f() = 0; +}; + +struct B +{ + A a; // { dg-error "abstract" } + A ar[4]; // { dg-error "abstract" } +}; + +using Aa = A[4]; // OK +Aa* aap; // OK + +extern A a; // OK +extern Aa aa; // OK +A f(); // OK +void g(A); // OK + +A a; // { dg-error "abstract" } +Aa aa; // { dg-error "abstract" } +A f() { } // { dg-error "abstract" } +void g(A) { } // { dg-error "abstract" } + +int main() +{ + (A(a)); // { dg-error "abstract" } + A{}; // { dg-error "abstract" } + static_cast(a); // { dg-error "abstract" } + Aa{}; // { dg-error "abstract" } + f(); // { dg-error "abstract" } + decltype(f())* p; // OK + g(a); // { dg-error "abstract" } + + throw a; // { dg-error "abstract" } +} diff --git a/gcc/testsuite/g++.dg/template/sfinae-dr657.C b/gcc/testsuite/g++.dg/template/sfinae-dr657.C index b78b5a919c17..36c11e659186 100644 --- a/gcc/testsuite/g++.dg/template/sfinae-dr657.C +++ b/gcc/testsuite/g++.dg/template/sfinae-dr657.C @@ -1,6 +1,7 @@ -// DR 657 -// Test that a return or parameter type with abstract class type causes a -// deduction failure. +// DR 657 SUPERSEDED BY DR 1646 +// Test that a return or parameter type with abstract class type DOES NOT cause +// a deduction failure, but there is no implicit conversion sequence for +// a parameter of abstract class type. struct A { @@ -17,6 +18,6 @@ template int arg(...); int main() { - int i = declval(); + int i = declval(); // { dg-error "ambiguous" } i = arg(1); } diff --git a/gcc/testsuite/g++.old-deja/g++.other/decl3.C b/gcc/testsuite/g++.old-deja/g++.other/decl3.C index bdcfcb02c6f5..4534bd16aadb 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/decl3.C +++ b/gcc/testsuite/g++.old-deja/g++.other/decl3.C @@ -13,7 +13,7 @@ struct cow_t { // { dg-message "pure" } int main() { - cow_t cow[2]; // { dg-error "invalid abstract type" } + cow_t cow[2]; // { dg-error "abstract" } cow[0].f(); return 0; } diff --git a/libstdc++-v3/testsuite/20_util/result_of/sfinae_friendly_1.cc b/libstdc++-v3/testsuite/20_util/result_of/sfinae_friendly_1.cc index 4b44b797b979..cce481292bd6 100644 --- a/libstdc++-v3/testsuite/20_util/result_of/sfinae_friendly_1.cc +++ b/libstdc++-v3/testsuite/20_util/result_of/sfinae_friendly_1.cc @@ -379,19 +379,19 @@ static_assert(is_type, const volatile Abstract&>(), "Error!"); static_assert(!has_type>(), "Error!"); -static_assert(!has_type>(), "Error!"); +static_assert(is_type,Abstract>(), "Error!"); static_assert(!has_type>(), "Error!"); -static_assert(!has_type>(), +static_assert(is_type,const Abstract>(), "Error!"); static_assert(!has_type>(), "Error!"); static_assert(!has_type>(), "Error!"); -static_assert(!has_type>(), +static_assert(is_type,Abstract>(), "Error!"); -static_assert(!has_type>(), "Error!"); +static_assert(is_type,const Abstract>(), "Error!"); static_assert(!has_type>(), "Error!"); static_assert(!has_type>(),