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.
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;
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
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);
&& !AGGR_INIT_VIA_CTOR_P (init));
}
-/* True iff C is a conversion that binds a reference to a prvalue. */
+/* True IFF the result of the conversion C is a prvalue. */
static bool
-conv_binds_ref_to_prvalue (conversion *c)
+conv_is_prvalue (conversion *c)
{
- if (c->kind != ck_ref_bind)
- return false;
- if (c->need_temporary_p)
- return true;
-
- c = next_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
return false;
}
+/* True iff C is a conversion that binds a reference to a prvalue. */
+
+static bool
+conv_binds_ref_to_prvalue (conversion *c)
+{
+ if (c->kind != ck_ref_bind)
+ return false;
+ if (c->need_temporary_p)
+ return true;
+
+ return conv_is_prvalue (next_conversion (c));
+}
+
/* True iff converting EXPR to a reference type TYPE does not involve
creating a temporary. */
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. */
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);
}
/* 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. */
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));
}
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:
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
}
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. */
}
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)
{
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,
readonly_error (loc, arg, errstring);
}
\f
-/* 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<pending_abstract_type>
-{
- 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_type_hasher> *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
{
vec<tree, va_gc> *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))
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<abstract_type_hasher>::create_ggc (31);
-
- pending_abstract_type **slot
- = abstract_pending_vars->find_slot_with_hash (type, TYPE_UID (type),
- INSERT);
-
- 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);
-
- 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. */
}
}
}
-
-\f
-#include "gt-cp-typeck2.h"
// 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 <class T> struct K {
- T (*a)[2]; // { dg-error "abstract class type" }
+ T (*a1)[2];
+ T (a2)[2]; // { dg-error "abstract" }
};
template struct K<Abstract>; // { 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 <bool> struct StaticAssert;
template<typename U> No is_abstract(U (*k)[1]);
template<typename U> Yes is_abstract(...);
-StaticAssert<sizeof(is_abstract<Abstract>(0)) == sizeof(Yes)> b1;
+StaticAssert<sizeof(is_abstract<Abstract>(0)) == sizeof(No)> b1;
StaticAssert<sizeof(is_abstract<Complete>(0)) == sizeof(No)> b2;
StaticAssert<sizeof(is_abstract<int>(0)) == sizeof(No)> b3;
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" }
+ 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 <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" }
+ void g(X parm4) {} // { dg-error "abstract" }
+ void g(X parm5[2]) {}
+ void g(X (*parm6)[2]) {}
};
- struct X { // { dg-message "note" }
- virtual void xfunc(void) = 0; // { dg-message "note" }
- };
+ 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 <int N>
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" }
-
- 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" }
+ void g(X parm13) {} // { dg-error "abstract" }
+ void g(X parm14[2]) {}
+ void g(X (*parm15)[2]) {}
+
+ template <int N>
+ void g(X parm16) {} // { dg-error "abstract" }
+ template <int N>
+ void g(X parm17[2]) {}
+ template <int N>
+ void g(X (*parm18)[2]) {}
+
+ template void g<42>(X);
}
int main()
{
- S<Abs(int)> s; // { dg-error "abstract" }
- foo<Abs(int)>(); // { dg-error "abstract" }
+ S<Abs(int)> s;
+ foo<Abs(int)>();
}
virtual void f() = 0;
};
-typedef A (*fp)(); // { dg-error "abstract" }
+typedef A (*fp)();
--- /dev/null
+// 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>(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" }
+}
-// 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
{
int main()
{
- int i = declval<A>();
+ int i = declval<A>(); // { dg-error "ambiguous" }
i = arg<A>(1);
}
int main()
{
- cow_t cow[2]; // { dg-error "invalid abstract type" }
+ cow_t cow[2]; // { dg-error "abstract" }
cow[0].f();
return 0;
}
const volatile Abstract&>(), "Error!");
static_assert(!has_type<std::result_of<ident_functor(int(&&)[1])>>(), "Error!");
-static_assert(!has_type<std::result_of<ident_functor(Abstract&&)>>(), "Error!");
+static_assert(is_type<std::result_of<ident_functor(Abstract&&)>,Abstract>(), "Error!");
static_assert(!has_type<std::result_of<ident_functor(const int(&&)[1])>>(),
"Error!");
-static_assert(!has_type<std::result_of<ident_functor(const Abstract&&)>>(),
+static_assert(is_type<std::result_of<ident_functor(const Abstract&&)>,const Abstract>(),
"Error!");
static_assert(!has_type<std::result_of<ident_functor_noref(int(&)[1])>>(),
"Error!");
static_assert(!has_type<std::result_of<ident_functor_noref
(const int(&)[1])>>(), "Error!");
-static_assert(!has_type<std::result_of<ident_functor_noref(Abstract&)>>(),
+static_assert(is_type<std::result_of<ident_functor_noref(Abstract&)>,Abstract>(),
"Error!");
-static_assert(!has_type<std::result_of
- <ident_functor_noref(const Abstract&)>>(), "Error!");
+static_assert(is_type<std::result_of
+ <ident_functor_noref(const Abstract&)>,const Abstract>(), "Error!");
static_assert(!has_type<std::result_of<ident_functor_noref(void(&)())>>(),
"Error!");
static_assert(!has_type<std::result_of<ident_functor_noref(void(&&)())>>(),