mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-02-23 05:59:08 +08:00
Implement C++20 P0388R4, DR 1307, and DR 330.
This patch implements P0388R4, Permit conversions to arrays of unknown bound, <http://wg21.link/p0388r4>. CWG 393 allowed references to arrays of unknown bound and this C++20 feature allows conversions like void f(int(&)[]); int arr[1]; void g() { f(arr); } int(&r)[] = arr; The proposal seemed fairly straightforward but it turned out to be quite shifty. I found out that I needed to implement DR 2352 (done), and also DR 1307 (done in this patch). The latter DR added wording for list-initialization ranking of references to arrays which this proposal extends. DR 330 was also implemented in this patch. PR c++/91364 - P0388R4: Permit conversions to arrays of unknown bound. PR c++/69531 - DR 1307: Differently bounded array parameters. PR c++/88128 - DR 330: Qual convs and pointers to arrays of pointers. * call.c (build_array_conv): Build ck_identity at the beginning of the conversion. (standard_conversion): Pass bounds_none to comp_ptr_ttypes_const. (maybe_warn_array_conv): New. (convert_like_real): Call it. Add an error message about converting from arrays of unknown bounds. (conv_get_original_expr): New. (nelts_initialized_by_list_init): New. (conv_binds_to_array_of_unknown_bound): New. (compare_ics): Implement list-initialization ranking based on array sizes, as specified in DR 1307 and P0388R. * cp-tree.h (comp_ptr_ttypes_const): Adjust declaration. (compare_bounds_t): New enum. * typeck.c (comp_array_types): New bool and compare_bounds_t parameters. Use them. (structural_comptypes): Adjust the call to comp_array_types. (similar_type_p): Handle ARRAY_TYPE. (build_const_cast_1): Pass bounds_none to comp_ptr_ttypes_const. (comp_ptr_ttypes_real): Don't check cv-quals of ARRAY_TYPEs. Use comp_array_types to compare array types. Look through arrays as per DR 330. (comp_ptr_ttypes_const): Use comp_array_types to compare array types. Look through arrays as per DR 330. * g++.dg/conversion/qual1.C: New test. * g++.dg/conversion/qual2.C: New test. * g++.dg/conversion/qual3.C: New test. * g++.dg/conversion/ref2.C: New test. * g++.dg/conversion/ref3.C: New test. * g++.dg/cpp0x/initlist-array3.C: Remove dg-error. * g++.dg/cpp0x/initlist-array7.C: New test. * g++.dg/cpp0x/initlist-array8.C: New test. * g++.dg/cpp2a/array-conv1.C: New test. * g++.dg/cpp2a/array-conv10.C: New test. * g++.dg/cpp2a/array-conv11.C: New test. * g++.dg/cpp2a/array-conv12.C: New test. * g++.dg/cpp2a/array-conv13.C: New test. * g++.dg/cpp2a/array-conv14.C: New test. * g++.dg/cpp2a/array-conv15.C: New test. * g++.dg/cpp2a/array-conv16.C: New test. * g++.dg/cpp2a/array-conv17.C: New test. * g++.dg/cpp2a/array-conv2.C: New test. * g++.dg/cpp2a/array-conv3.C: New test. * g++.dg/cpp2a/array-conv4.C: New test. * g++.dg/cpp2a/array-conv5.C: New test. * g++.dg/cpp2a/array-conv6.C: New test. * g++.dg/cpp2a/array-conv7.C: New test. * g++.dg/cpp2a/array-conv8.C: New test. * g++.dg/cpp2a/array-conv9.C: New test. * g++.old-deja/g++.bugs/900321_01.C: Adjust dg-error. * testsuite/23_containers/span/lwg3255.cc: Adjust test to match the post-P0388R4 behavior. From-SVN: r276771
This commit is contained in:
parent
3b29211acb
commit
89e0a492af
@ -1,3 +1,32 @@
|
||||
2019-10-09 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/91364 - P0388R4: Permit conversions to arrays of unknown bound.
|
||||
PR c++/69531 - DR 1307: Differently bounded array parameters.
|
||||
PR c++/88128 - DR 330: Qual convs and pointers to arrays of pointers.
|
||||
* call.c (build_array_conv): Build ck_identity at the beginning
|
||||
of the conversion.
|
||||
(standard_conversion): Pass bounds_none to comp_ptr_ttypes_const.
|
||||
(maybe_warn_array_conv): New.
|
||||
(convert_like_real): Call it. Add an error message about converting
|
||||
from arrays of unknown bounds.
|
||||
(conv_get_original_expr): New.
|
||||
(nelts_initialized_by_list_init): New.
|
||||
(conv_binds_to_array_of_unknown_bound): New.
|
||||
(compare_ics): Implement list-initialization ranking based on
|
||||
array sizes, as specified in DR 1307 and P0388R.
|
||||
* cp-tree.h (comp_ptr_ttypes_const): Adjust declaration.
|
||||
(compare_bounds_t): New enum.
|
||||
* typeck.c (comp_array_types): New bool and compare_bounds_t
|
||||
parameters. Use them.
|
||||
(structural_comptypes): Adjust the call to comp_array_types.
|
||||
(similar_type_p): Handle ARRAY_TYPE.
|
||||
(build_const_cast_1): Pass bounds_none to comp_ptr_ttypes_const.
|
||||
(comp_ptr_ttypes_real): Don't check cv-quals of ARRAY_TYPEs. Use
|
||||
comp_array_types to compare array types. Look through arrays as per
|
||||
DR 330.
|
||||
(comp_ptr_ttypes_const): Use comp_array_types to compare array types.
|
||||
Look through arrays as per DR 330.
|
||||
|
||||
2019-10-09 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/92032 - DR 1601: Promotion of enum with fixed underlying type.
|
||||
|
160
gcc/cp/call.c
160
gcc/cp/call.c
@ -122,7 +122,8 @@ struct conversion {
|
||||
of using this field directly. */
|
||||
conversion *next;
|
||||
/* The expression at the beginning of the conversion chain. This
|
||||
variant is used only if KIND is ck_identity or ck_ambig. */
|
||||
variant is used only if KIND is ck_identity or ck_ambig. You can
|
||||
use conv_get_original_expr to get this expression. */
|
||||
tree expr;
|
||||
/* The array of conversions for an initializer_list, so this
|
||||
variant is used only when KIN D is ck_list. */
|
||||
@ -223,6 +224,8 @@ static void add_candidates (tree, tree, const vec<tree, va_gc> *, tree, tree,
|
||||
tsubst_flags_t);
|
||||
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 *);
|
||||
|
||||
/* Returns nonzero iff the destructor name specified in NAME matches BASETYPE.
|
||||
NAME can take many forms... */
|
||||
@ -1066,7 +1069,7 @@ build_array_conv (tree type, tree ctor, int flags, tsubst_flags_t complain)
|
||||
c->rank = rank;
|
||||
c->user_conv_p = user;
|
||||
c->bad_p = bad;
|
||||
c->u.next = NULL;
|
||||
c->u.next = build_identity_conv (TREE_TYPE (ctor), ctor);
|
||||
return c;
|
||||
}
|
||||
|
||||
@ -1366,7 +1369,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
||||
|
||||
if (same_type_p (from, to))
|
||||
/* OK */;
|
||||
else if (c_cast_p && comp_ptr_ttypes_const (to, from))
|
||||
else if (c_cast_p && comp_ptr_ttypes_const (to, from, bounds_either))
|
||||
/* In a C-style cast, we ignore CV-qualification because we
|
||||
are allowed to perform a static_cast followed by a
|
||||
const_cast. */
|
||||
@ -1668,7 +1671,14 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
||||
maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
|
||||
/* DR 1288: Otherwise, if the initializer list has a single element
|
||||
of type E and ... [T's] referenced type is reference-related to E,
|
||||
the object or reference is initialized from that element... */
|
||||
the object or reference is initialized from that element...
|
||||
|
||||
??? With P0388R4, we should bind 't' directly to U{}:
|
||||
using U = A[2];
|
||||
A (&&t)[] = {U{}};
|
||||
because A[] and A[2] are reference-related. But we don't do it
|
||||
because grok_reference_init has deduced the array size (to 1), and
|
||||
A[1] and A[2] aren't reference-related. */
|
||||
if (CONSTRUCTOR_NELTS (expr) == 1)
|
||||
{
|
||||
tree elt = CONSTRUCTOR_ELT (expr, 0)->value;
|
||||
@ -6958,6 +6968,27 @@ maybe_inform_about_fndecl_for_bogus_argument_init (tree fn, int argnum)
|
||||
" initializing argument %P of %qD", argnum, fn);
|
||||
}
|
||||
|
||||
/* Maybe warn about C++20 Conversions to arrays of unknown bound. C is
|
||||
the conversion, EXPR is the expression we're converting. */
|
||||
|
||||
static void
|
||||
maybe_warn_array_conv (location_t loc, conversion *c, tree expr)
|
||||
{
|
||||
if (cxx_dialect >= cxx2a)
|
||||
return;
|
||||
|
||||
tree type = TREE_TYPE (expr);
|
||||
type = strip_pointer_operator (type);
|
||||
|
||||
if (TREE_CODE (type) != ARRAY_TYPE
|
||||
|| TYPE_DOMAIN (type) == NULL_TREE)
|
||||
return;
|
||||
|
||||
if (conv_binds_to_array_of_unknown_bound (c))
|
||||
pedwarn (loc, OPT_Wpedantic, "conversions to arrays of unknown bound "
|
||||
"are only available with %<-std=c++2a%> or %<-std=gnu++2a%>");
|
||||
}
|
||||
|
||||
/* Perform the conversions in CONVS on the expression EXPR. FN and
|
||||
ARGNUM are used for diagnostics. ARGNUM is zero based, -1
|
||||
indicates the `this' argument of a method. INNER is nonzero when
|
||||
@ -7377,8 +7408,20 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
|
||||
error_at (loc, "cannot bind non-const lvalue reference of "
|
||||
"type %qH to an rvalue of type %qI", totype, extype);
|
||||
else if (!reference_compatible_p (TREE_TYPE (totype), extype))
|
||||
error_at (loc, "binding reference of type %qH to %qI "
|
||||
"discards qualifiers", totype, extype);
|
||||
{
|
||||
/* If we're converting from T[] to T[N], don't talk
|
||||
about discarding qualifiers. (Converting from T[N] to
|
||||
T[] is allowed by P0388R4.) */
|
||||
if (TREE_CODE (extype) == ARRAY_TYPE
|
||||
&& TYPE_DOMAIN (extype) == NULL_TREE
|
||||
&& TREE_CODE (TREE_TYPE (totype)) == ARRAY_TYPE
|
||||
&& TYPE_DOMAIN (TREE_TYPE (totype)) != NULL_TREE)
|
||||
error_at (loc, "cannot bind reference of type %qH to %qI "
|
||||
"due to different array bounds", totype, extype);
|
||||
else
|
||||
error_at (loc, "binding reference of type %qH to %qI "
|
||||
"discards qualifiers", totype, extype);
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
maybe_print_user_conv_context (convs);
|
||||
@ -7386,6 +7429,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
|
||||
|
||||
return error_mark_node;
|
||||
}
|
||||
else if (complain & tf_warning)
|
||||
maybe_warn_array_conv (loc, convs, expr);
|
||||
|
||||
/* If necessary, create a temporary.
|
||||
|
||||
@ -7469,7 +7514,10 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
|
||||
case ck_qual:
|
||||
/* Warn about deprecated conversion if appropriate. */
|
||||
if (complain & tf_warning)
|
||||
string_conv_p (totype, expr, 1);
|
||||
{
|
||||
string_conv_p (totype, expr, 1);
|
||||
maybe_warn_array_conv (loc, convs, expr);
|
||||
}
|
||||
break;
|
||||
|
||||
case ck_ptr:
|
||||
@ -10061,6 +10109,50 @@ maybe_handle_ref_bind (conversion **ics)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the expression at the beginning of the conversion chain C. */
|
||||
|
||||
static tree
|
||||
conv_get_original_expr (conversion *c)
|
||||
{
|
||||
for (; c; c = next_conversion (c))
|
||||
if (c->kind == ck_identity || c->kind == ck_ambig)
|
||||
return c->u.expr;
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Return a tree representing the number of elements initialized by the
|
||||
list-initialization C. The caller must check that C converts to an
|
||||
array type. */
|
||||
|
||||
static tree
|
||||
nelts_initialized_by_list_init (conversion *c)
|
||||
{
|
||||
/* If the array we're converting to has a dimension, we'll use that. */
|
||||
if (TYPE_DOMAIN (c->type))
|
||||
return array_type_nelts_top (c->type);
|
||||
else
|
||||
{
|
||||
/* Otherwise, we look at how many elements the constructor we're
|
||||
initializing from has. */
|
||||
tree ctor = conv_get_original_expr (c);
|
||||
return size_int (CONSTRUCTOR_NELTS (ctor));
|
||||
}
|
||||
}
|
||||
|
||||
/* True iff C is a conversion that binds a reference or a pointer to
|
||||
an array of unknown bound. */
|
||||
|
||||
static inline bool
|
||||
conv_binds_to_array_of_unknown_bound (conversion *c)
|
||||
{
|
||||
/* ck_ref_bind won't have the reference stripped. */
|
||||
tree type = non_reference (c->type);
|
||||
/* ck_qual won't have the pointer stripped. */
|
||||
type = strip_pointer_operator (type);
|
||||
return (TREE_CODE (type) == ARRAY_TYPE
|
||||
&& TYPE_DOMAIN (type) == NULL_TREE);
|
||||
}
|
||||
|
||||
/* Compare two implicit conversion sequences according to the rules set out in
|
||||
[over.ics.rank]. Return values:
|
||||
|
||||
@ -10174,6 +10266,38 @@ compare_ics (conversion *ics1, conversion *ics2)
|
||||
if (f1 != f2)
|
||||
return 0;
|
||||
}
|
||||
/* List-initialization sequence L1 is a better conversion sequence than
|
||||
list-initialization sequence L2 if
|
||||
|
||||
-- L1 and L2 convert to arrays of the same element type, and either
|
||||
the number of elements n1 initialized by L1 is less than the number
|
||||
of elements n2 initialized by L2, or n1=n2 and L2 converts to an array
|
||||
of unknown bound and L1 does not. (Added in CWG 1307 and extended by
|
||||
P0388R4.) */
|
||||
else if (t1->kind == ck_aggr
|
||||
&& TREE_CODE (t1->type) == ARRAY_TYPE
|
||||
&& TREE_CODE (t2->type) == ARRAY_TYPE)
|
||||
{
|
||||
/* The type of the array elements must be the same. */
|
||||
if (!same_type_p (TREE_TYPE (t1->type), TREE_TYPE (t2->type)))
|
||||
return 0;
|
||||
|
||||
tree n1 = nelts_initialized_by_list_init (t1);
|
||||
tree n2 = nelts_initialized_by_list_init (t2);
|
||||
if (tree_int_cst_lt (n1, n2))
|
||||
return 1;
|
||||
else if (tree_int_cst_lt (n2, n1))
|
||||
return -1;
|
||||
/* The n1 == n2 case. */
|
||||
bool c1 = conv_binds_to_array_of_unknown_bound (t1);
|
||||
bool c2 = conv_binds_to_array_of_unknown_bound (t2);
|
||||
if (c1 && !c2)
|
||||
return -1;
|
||||
else if (!c1 && c2)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For ambiguous or aggregate conversions, use the target type as
|
||||
@ -10469,6 +10593,28 @@ compare_ics (conversion *ics1, conversion *ics2)
|
||||
|
||||
if (same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2))
|
||||
{
|
||||
/* Per P0388R4:
|
||||
|
||||
void f (int(&)[]), // (1)
|
||||
f (int(&)[1]), // (2)
|
||||
f (int*); // (3)
|
||||
|
||||
(2) is better than (1), but (3) should be equal to (1) and to
|
||||
(2). For that reason we don't use ck_qual for (1) which would
|
||||
give it the cr_exact rank while (3) remains ck_identity.
|
||||
Therefore we compare (1) and (2) here. For (1) we'll have
|
||||
|
||||
ck_ref_bind <- ck_identity
|
||||
int[] & int[1]
|
||||
|
||||
so to handle this we must look at ref_conv. */
|
||||
bool c1 = conv_binds_to_array_of_unknown_bound (ref_conv1);
|
||||
bool c2 = conv_binds_to_array_of_unknown_bound (ref_conv2);
|
||||
if (c1 && !c2)
|
||||
return -1;
|
||||
else if (!c1 && c2)
|
||||
return 1;
|
||||
|
||||
int q1 = cp_type_quals (TREE_TYPE (ref_conv1->type));
|
||||
int q2 = cp_type_quals (TREE_TYPE (ref_conv2->type));
|
||||
if (ref_conv1->bad_p)
|
||||
|
@ -7372,6 +7372,10 @@ extern void cxx_print_error_function (diagnostic_context *,
|
||||
struct diagnostic_info *);
|
||||
|
||||
/* in typeck.c */
|
||||
/* Says how we should behave when comparing two arrays one of which
|
||||
has unknown bounds. */
|
||||
enum compare_bounds_t { bounds_none, bounds_either, bounds_first };
|
||||
|
||||
extern bool cxx_mark_addressable (tree, bool = false);
|
||||
extern int string_conv_p (const_tree, const_tree, int);
|
||||
extern tree cp_truthvalue_conversion (tree);
|
||||
@ -7462,7 +7466,7 @@ extern tree convert_for_initialization (tree, tree, tree, int,
|
||||
impl_conv_rhs, tree, int,
|
||||
tsubst_flags_t);
|
||||
extern int comp_ptr_ttypes (tree, tree);
|
||||
extern bool comp_ptr_ttypes_const (tree, tree);
|
||||
extern bool comp_ptr_ttypes_const (tree, tree, compare_bounds_t);
|
||||
extern bool error_type_p (const_tree);
|
||||
extern bool ptr_reasonably_similar (const_tree, const_tree);
|
||||
extern tree build_ptrmemfunc (tree, tree, int, bool,
|
||||
|
@ -54,7 +54,7 @@ static tree rationalize_conditional_expr (enum tree_code, tree,
|
||||
tsubst_flags_t);
|
||||
static int comp_ptr_ttypes_real (tree, tree, int);
|
||||
static bool comp_except_types (tree, tree, bool);
|
||||
static bool comp_array_types (const_tree, const_tree, bool);
|
||||
static bool comp_array_types (const_tree, const_tree, compare_bounds_t, bool);
|
||||
static tree pointer_diff (location_t, tree, tree, tree, tsubst_flags_t, tree *);
|
||||
static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
|
||||
static void casts_away_constness_r (tree *, tree *, tsubst_flags_t);
|
||||
@ -1084,11 +1084,15 @@ comp_except_specs (const_tree t1, const_tree t2, int exact)
|
||||
return exact == ce_derived || base == NULL_TREE || length == list_length (t1);
|
||||
}
|
||||
|
||||
/* Compare the array types T1 and T2. ALLOW_REDECLARATION is true if
|
||||
[] can match [size]. */
|
||||
/* Compare the array types T1 and T2. CB says how we should behave when
|
||||
comparing array bounds: bounds_none doesn't allow dimensionless arrays,
|
||||
bounds_either says than any array can be [], bounds_first means that
|
||||
onlt T1 can be an array with unknown bounds. STRICT is true if
|
||||
qualifiers must match when comparing the types of the array elements. */
|
||||
|
||||
static bool
|
||||
comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
|
||||
comp_array_types (const_tree t1, const_tree t2, compare_bounds_t cb,
|
||||
bool strict)
|
||||
{
|
||||
tree d1;
|
||||
tree d2;
|
||||
@ -1098,7 +1102,9 @@ comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
|
||||
return true;
|
||||
|
||||
/* The type of the array elements must be the same. */
|
||||
if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
|
||||
if (strict
|
||||
? !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
|
||||
: !similar_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
|
||||
return false;
|
||||
|
||||
d1 = TYPE_DOMAIN (t1);
|
||||
@ -1119,8 +1125,10 @@ comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
|
||||
declarations for an array object can specify
|
||||
array types that differ by the presence or absence of a major
|
||||
array bound (_dcl.array_). */
|
||||
if (!d1 || !d2)
|
||||
return allow_redeclaration;
|
||||
if (!d1 && d2)
|
||||
return cb >= bounds_either;
|
||||
else if (d1 && !d2)
|
||||
return cb == bounds_either;
|
||||
|
||||
/* Check that the dimensions are the same. */
|
||||
|
||||
@ -1368,7 +1376,9 @@ structural_comptypes (tree t1, tree t2, int strict)
|
||||
|
||||
case ARRAY_TYPE:
|
||||
/* Target types must match incl. qualifiers. */
|
||||
if (!comp_array_types (t1, t2, !!(strict & COMPARE_REDECLARATION)))
|
||||
if (!comp_array_types (t1, t2, ((strict & COMPARE_REDECLARATION)
|
||||
? bounds_either : bounds_none),
|
||||
/*strict=*/true))
|
||||
return false;
|
||||
break;
|
||||
|
||||
@ -1549,10 +1559,10 @@ similar_type_p (tree type1, tree type2)
|
||||
if (same_type_ignoring_top_level_qualifiers_p (type1, type2))
|
||||
return true;
|
||||
|
||||
/* FIXME This ought to handle ARRAY_TYPEs too. */
|
||||
if ((TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
|
||||
|| (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2)))
|
||||
return comp_ptr_ttypes_const (type1, type2);
|
||||
|| (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2))
|
||||
|| (TREE_CODE (type1) == ARRAY_TYPE && TREE_CODE (type2) == ARRAY_TYPE))
|
||||
return comp_ptr_ttypes_const (type1, type2, bounds_either);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -7867,7 +7877,7 @@ build_const_cast_1 (tree dst_type, tree expr, tsubst_flags_t complain,
|
||||
|
||||
if (TYPE_PTR_P (src_type) || TYPE_PTRDATAMEM_P (src_type))
|
||||
{
|
||||
if (comp_ptr_ttypes_const (dst_type, src_type))
|
||||
if (comp_ptr_ttypes_const (dst_type, src_type, bounds_none))
|
||||
{
|
||||
if (valid_p)
|
||||
{
|
||||
@ -9909,9 +9919,10 @@ comp_ptr_ttypes_real (tree to, tree from, int constp)
|
||||
TYPE_OFFSET_BASETYPE (to)))
|
||||
return 0;
|
||||
|
||||
/* Const and volatile mean something different for function types,
|
||||
so the usual checks are not appropriate. */
|
||||
if (!FUNC_OR_METHOD_TYPE_P (to))
|
||||
/* Const and volatile mean something different for function and
|
||||
array types, so the usual checks are not appropriate. We'll
|
||||
check the array type elements in further iterations. */
|
||||
if (!FUNC_OR_METHOD_TYPE_P (to) && TREE_CODE (to) != ARRAY_TYPE)
|
||||
{
|
||||
if (!at_least_as_qualified_p (to, from))
|
||||
return 0;
|
||||
@ -9930,7 +9941,17 @@ comp_ptr_ttypes_real (tree to, tree from, int constp)
|
||||
if (VECTOR_TYPE_P (to))
|
||||
is_opaque_pointer = vector_targets_convertible_p (to, from);
|
||||
|
||||
if (!TYPE_PTR_P (to) && !TYPE_PTRDATAMEM_P (to))
|
||||
/* P0388R4 allows a conversion from int[N] to int[] but not the
|
||||
other way round. When both arrays have bounds but they do
|
||||
not match, then no conversion is possible. */
|
||||
if (TREE_CODE (to) == ARRAY_TYPE
|
||||
&& !comp_array_types (to, from, bounds_first, /*strict=*/false))
|
||||
return 0;
|
||||
|
||||
if (!TYPE_PTR_P (to)
|
||||
&& !TYPE_PTRDATAMEM_P (to)
|
||||
/* CWG 330 says we need to look through arrays. */
|
||||
&& TREE_CODE (to) != ARRAY_TYPE)
|
||||
return ((constp >= 0 || to_more_cv_qualified)
|
||||
&& (is_opaque_pointer
|
||||
|| same_type_ignoring_top_level_qualifiers_p (to, from)));
|
||||
@ -10033,10 +10054,10 @@ ptr_reasonably_similar (const_tree to, const_tree from)
|
||||
|
||||
/* Return true if TO and FROM (both of which are POINTER_TYPEs or
|
||||
pointer-to-member types) are the same, ignoring cv-qualification at
|
||||
all levels. */
|
||||
all levels. CB says how we should behave when comparing array bounds. */
|
||||
|
||||
bool
|
||||
comp_ptr_ttypes_const (tree to, tree from)
|
||||
comp_ptr_ttypes_const (tree to, tree from, compare_bounds_t cb)
|
||||
{
|
||||
bool is_opaque_pointer = false;
|
||||
|
||||
@ -10053,7 +10074,14 @@ comp_ptr_ttypes_const (tree to, tree from)
|
||||
if (VECTOR_TYPE_P (to))
|
||||
is_opaque_pointer = vector_targets_convertible_p (to, from);
|
||||
|
||||
if (!TYPE_PTR_P (to))
|
||||
if (TREE_CODE (to) == ARRAY_TYPE
|
||||
/* Ignore cv-qualification, but if we see e.g. int[3] and int[4],
|
||||
we must fail. */
|
||||
&& !comp_array_types (to, from, cb, /*strict=*/false))
|
||||
return false;
|
||||
|
||||
/* CWG 330 says we need to look through arrays. */
|
||||
if (!TYPE_PTR_P (to) && TREE_CODE (to) != ARRAY_TYPE)
|
||||
return (is_opaque_pointer
|
||||
|| same_type_ignoring_top_level_qualifiers_p (to, from));
|
||||
}
|
||||
|
@ -1,3 +1,35 @@
|
||||
2019-10-09 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/91364 - P0388R4: Permit conversions to arrays of unknown bound.
|
||||
PR c++/69531 - DR 1307: Differently bounded array parameters.
|
||||
PR c++/88128 - DR 330: Qual convs and pointers to arrays of pointers.
|
||||
* g++.dg/conversion/qual1.C: New test.
|
||||
* g++.dg/conversion/qual2.C: New test.
|
||||
* g++.dg/conversion/qual3.C: New test.
|
||||
* g++.dg/conversion/ref2.C: New test.
|
||||
* g++.dg/conversion/ref3.C: New test.
|
||||
* g++.dg/cpp0x/initlist-array3.C: Remove dg-error.
|
||||
* g++.dg/cpp0x/initlist-array7.C: New test.
|
||||
* g++.dg/cpp0x/initlist-array8.C: New test.
|
||||
* g++.dg/cpp2a/array-conv1.C: New test.
|
||||
* g++.dg/cpp2a/array-conv10.C: New test.
|
||||
* g++.dg/cpp2a/array-conv11.C: New test.
|
||||
* g++.dg/cpp2a/array-conv12.C: New test.
|
||||
* g++.dg/cpp2a/array-conv13.C: New test.
|
||||
* g++.dg/cpp2a/array-conv14.C: New test.
|
||||
* g++.dg/cpp2a/array-conv15.C: New test.
|
||||
* g++.dg/cpp2a/array-conv16.C: New test.
|
||||
* g++.dg/cpp2a/array-conv17.C: New test.
|
||||
* g++.dg/cpp2a/array-conv2.C: New test.
|
||||
* g++.dg/cpp2a/array-conv3.C: New test.
|
||||
* g++.dg/cpp2a/array-conv4.C: New test.
|
||||
* g++.dg/cpp2a/array-conv5.C: New test.
|
||||
* g++.dg/cpp2a/array-conv6.C: New test.
|
||||
* g++.dg/cpp2a/array-conv7.C: New test.
|
||||
* g++.dg/cpp2a/array-conv8.C: New test.
|
||||
* g++.dg/cpp2a/array-conv9.C: New test.
|
||||
* g++.old-deja/g++.bugs/900321_01.C: Adjust dg-error.
|
||||
|
||||
2019-10-09 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/92032 - DR 1601: Promotion of enum with fixed underlying type.
|
||||
|
51
gcc/testsuite/g++.dg/conversion/qual1.C
Normal file
51
gcc/testsuite/g++.dg/conversion/qual1.C
Normal file
@ -0,0 +1,51 @@
|
||||
// PR c++/88128 - Implement DR 330: Qualification conversions and pointers to
|
||||
// arrays of pointers.
|
||||
|
||||
int *a[4];
|
||||
const int *const(*ap1)[4] = &a;
|
||||
/* if at some level k the P2 is more cv-qualified than P1, then there
|
||||
must be a const at every single level (other than level zero) of P2
|
||||
up until k. */
|
||||
const int *(*ap2)[4] = &a; // { dg-error "cannot convert" }
|
||||
int *const(*ap3)[4] = &a;
|
||||
int *(*ap4)[4] = &a;
|
||||
int *(*const ap5)[4] = &a;
|
||||
const int *const(*const ap6)[4] = &a;
|
||||
int *const(*const ap7)[4] = &a;
|
||||
int *(*const ap8)[4] = &a;
|
||||
|
||||
const int *b[4];
|
||||
const int *const(*bp1)[4] = &b;
|
||||
const int *(*bp2)[4] = &b;
|
||||
int *const(*bp3)[4] = &b; // { dg-error "cannot convert" }
|
||||
int *(*bp4)[4] = &b; // { dg-error "cannot convert" }
|
||||
int *(*const bp5)[4] = &b; // { dg-error "cannot convert" }
|
||||
const int *const(*const bp6)[4] = &b;
|
||||
int *const(*const bp7)[4] = &b; // { dg-error "cannot convert" }
|
||||
int *(*const bp8)[4] = &b; // { dg-error "cannot convert" }
|
||||
|
||||
int *c[2][3];
|
||||
int const *const (*cp1)[3] = c;
|
||||
int const *(*cp2)[3] = c; // { dg-error "cannot convert" }
|
||||
int const *const (*const cp3)[3] = c;
|
||||
int *const (*cp4)[3] = c;
|
||||
int *(*cp5)[3] = c;
|
||||
|
||||
double *const (*d)[3];
|
||||
double const *const (*e)[3] = d;
|
||||
int *(*f)[3];
|
||||
const int *const (*g)[3] = f;
|
||||
|
||||
// From PR88128.
|
||||
int* (*xx)[];
|
||||
const int* const(*yy)[] = xx;
|
||||
|
||||
// From DR 330.
|
||||
int main()
|
||||
{
|
||||
double *array2D[2][3];
|
||||
|
||||
double * (*array2DPtr1)[3] = array2D;
|
||||
double * const (*array2DPtr2)[3] = array2DPtr1;
|
||||
double const * const (*array2DPtr3)[3] = array2DPtr2;
|
||||
}
|
14
gcc/testsuite/g++.dg/conversion/qual2.C
Normal file
14
gcc/testsuite/g++.dg/conversion/qual2.C
Normal file
@ -0,0 +1,14 @@
|
||||
// PR c++/88128 - DR 330: Qual convs and pointers to arrays of pointers.
|
||||
|
||||
// Make sure we don't accept different bounds.
|
||||
|
||||
int *a[4];
|
||||
const int *const(*ap1)[5] = &a; // { dg-error "cannot convert" }
|
||||
|
||||
int *(*b)[3];
|
||||
const int *const (*bp1)[3] = &b; // { dg-error "cannot convert" }
|
||||
const int *const (*bp2)[4] = &b; // { dg-error "cannot convert" }
|
||||
int *(*bp3)[4] = &b; // { dg-error "cannot convert" }
|
||||
|
||||
int *c[2][3];
|
||||
int const *const (*cp1)[4] = c; // { dg-error "cannot convert" }
|
53
gcc/testsuite/g++.dg/conversion/qual3.C
Normal file
53
gcc/testsuite/g++.dg/conversion/qual3.C
Normal file
@ -0,0 +1,53 @@
|
||||
// PR c++/88128 - DR 330: Qual convs and pointers to arrays of pointers.
|
||||
// { dg-do compile { target c++17 } }
|
||||
|
||||
using P = int *(*)[3];
|
||||
using Q = const int *const (*)[3];
|
||||
using Qi = const int *[3];
|
||||
using Q2 = Qi const *;
|
||||
using R = const int *const (*)[4];
|
||||
using S = const int *const (*)[];
|
||||
using T = const int *(*)[];
|
||||
|
||||
void
|
||||
f (P p, Q q, Q2 q2, R r, S s, T t)
|
||||
{
|
||||
q = p;
|
||||
q2 = p;
|
||||
r = p; // { dg-error "cannot convert" }
|
||||
t = p; // { dg-error "cannot convert" }
|
||||
s = t;
|
||||
t = s; // { dg-error "invalid conversion" }
|
||||
|
||||
// Test const_cast.
|
||||
const_cast<P>(q);
|
||||
const_cast<P>(q2);
|
||||
const_cast<Q>(p);
|
||||
const_cast<Q2>(p);
|
||||
const_cast<S>(p); // { dg-error "invalid .const_cast." }
|
||||
const_cast<P>(s); // { dg-error "invalid .const_cast." }
|
||||
const_cast<S>(q); // { dg-error "invalid .const_cast." }
|
||||
const_cast<S>(q2); // { dg-error "invalid .const_cast." }
|
||||
const_cast<Q>(s); // { dg-error "invalid .const_cast." }
|
||||
const_cast<Q2>(s); // { dg-error "invalid .const_cast." }
|
||||
const_cast<T>(s);
|
||||
const_cast<S>(t);
|
||||
const_cast<T>(q); // { dg-error "invalid .const_cast." }
|
||||
const_cast<Q>(t); // { dg-error "invalid .const_cast." }
|
||||
|
||||
// Test reinterpret_cast.
|
||||
reinterpret_cast<P>(q); // { dg-error "casts away qualifiers" }
|
||||
reinterpret_cast<P>(q2); // { dg-error "casts away qualifiers" }
|
||||
reinterpret_cast<Q>(p);
|
||||
reinterpret_cast<Q2>(p);
|
||||
reinterpret_cast<S>(p);
|
||||
reinterpret_cast<P>(s); // { dg-error "casts away qualifiers" }
|
||||
reinterpret_cast<S>(q);
|
||||
reinterpret_cast<S>(q2);
|
||||
reinterpret_cast<Q>(s);
|
||||
reinterpret_cast<Q2>(s);
|
||||
reinterpret_cast<T>(s); // { dg-error "casts away qualifiers" }
|
||||
reinterpret_cast<S>(t);
|
||||
reinterpret_cast<T>(q); // { dg-error "casts away qualifiers" }
|
||||
reinterpret_cast<Q>(t);
|
||||
}
|
29
gcc/testsuite/g++.dg/conversion/ref2.C
Normal file
29
gcc/testsuite/g++.dg/conversion/ref2.C
Normal file
@ -0,0 +1,29 @@
|
||||
// PR c++/88128 - Implement DR 330: Qualification conversions and pointers to
|
||||
// arrays of pointers.
|
||||
|
||||
int *ar[4];
|
||||
/* if at some level k the P2 is more cv-qualified than P1, then there
|
||||
must be a const at every single level (other than level zero) of P2
|
||||
up until k. */
|
||||
const int *(&arp)[4] = ar; // { dg-error "discards qualifiers" }
|
||||
const int *const(&arp2)[4] = ar;
|
||||
int *const(&arp3)[4] = ar;
|
||||
int *(&arp4)[4] = ar;
|
||||
|
||||
const int *br[4];
|
||||
const int *(&brp)[4] = br;
|
||||
const int *const(&brp2)[4] = br;
|
||||
int *const(&brp3)[4] = br; // { dg-error "discards qualifiers" }
|
||||
int *(&brp4)[4] = br; // { dg-error "discards qualifiers" }
|
||||
|
||||
int *c[2][3];
|
||||
int const *const (&cp1)[3] = *c;
|
||||
int const *(&cp2)[3] = *c; // { dg-error "discards qualifiers" }
|
||||
int *const (&cp3)[3] = *c;
|
||||
int *(&cp4)[3] = *c;
|
||||
|
||||
double *const (*d)[3];
|
||||
double const *const (&e)[3] = *d;
|
||||
|
||||
int *(*f)[3];
|
||||
const int *const (&g)[3] = *f;
|
4
gcc/testsuite/g++.dg/conversion/ref3.C
Normal file
4
gcc/testsuite/g++.dg/conversion/ref3.C
Normal file
@ -0,0 +1,4 @@
|
||||
int a[2];
|
||||
const int (&rc)[2] = a;
|
||||
volatile int (&rv)[2] = a;
|
||||
const volatile int (&rcv)[2] = a;
|
@ -6,5 +6,6 @@ void composite (int const (&) [3]);
|
||||
|
||||
int main ()
|
||||
{
|
||||
composite({0,1}); // { dg-error "ambiguous" }
|
||||
// Not ambiguous since CWG 1307.
|
||||
composite({0,1});
|
||||
}
|
||||
|
21
gcc/testsuite/g++.dg/cpp0x/initlist-array7.C
Normal file
21
gcc/testsuite/g++.dg/cpp0x/initlist-array7.C
Normal file
@ -0,0 +1,21 @@
|
||||
// PR c++/69531 - DR 1307, Overload resolution based on size of array init-list.
|
||||
// { dg-do run { target c++11 } }
|
||||
|
||||
int f(int const(&)[2]) { return 1; }
|
||||
int f(int const(&)[3]) { return 2; }
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (f({}) != 1)
|
||||
__builtin_abort ();
|
||||
|
||||
if (f({1}) != 1)
|
||||
__builtin_abort ();
|
||||
|
||||
if (f({1, 2}) != 1)
|
||||
__builtin_abort ();
|
||||
|
||||
if (f({1, 2, 3}) != 2)
|
||||
__builtin_abort ();
|
||||
}
|
35
gcc/testsuite/g++.dg/cpp0x/initlist-array8.C
Normal file
35
gcc/testsuite/g++.dg/cpp0x/initlist-array8.C
Normal file
@ -0,0 +1,35 @@
|
||||
// PR c++/69531 - DR 1307, Overload resolution based on size of array init-list.
|
||||
// { dg-do run { target c++2a } }
|
||||
|
||||
int f(int (&)[1][1]) { return 1; }
|
||||
int f(int (&)[1][2]) { return 2; }
|
||||
|
||||
int g(int (&&)[2][1]) { return 1; }
|
||||
int g(int (&&)[2][2]) { return 2; }
|
||||
|
||||
int h(int (&&)[][1]) { return 1; }
|
||||
int h(int (&&)[][2]) { return 2; }
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
int arr1[1][1];
|
||||
int arr2[1][2];
|
||||
|
||||
if (f(arr1) != 1)
|
||||
__builtin_abort ();
|
||||
if (f(arr2) != 2)
|
||||
__builtin_abort ();
|
||||
|
||||
if (g({ { 1, 2 }, { 3 } }) != 2)
|
||||
__builtin_abort ();
|
||||
|
||||
if (g({ { 1, 2 }, { 3, 4 } }) != 2)
|
||||
__builtin_abort ();
|
||||
|
||||
if (h({ { 1, 2 }, { 3 } }) != 2)
|
||||
__builtin_abort ();
|
||||
|
||||
if (h({ { 1, 2 }, { 3, 4 } }) != 2)
|
||||
__builtin_abort ();
|
||||
}
|
33
gcc/testsuite/g++.dg/cpp2a/array-conv1.C
Normal file
33
gcc/testsuite/g++.dg/cpp2a/array-conv1.C
Normal file
@ -0,0 +1,33 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do compile { target c++17 } }
|
||||
// { dg-options "-Wpedantic" }
|
||||
// C++17, because that has CWG 393.
|
||||
|
||||
void f(int(&)[]);
|
||||
void fp(int(*)[]);
|
||||
void f2(int(&)[][10]);
|
||||
void fp2(int(*)[][10]);
|
||||
int arr[10];
|
||||
int arr2[10][10];
|
||||
|
||||
void
|
||||
g ()
|
||||
{
|
||||
f (arr); // { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
|
||||
fp (&arr); // { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
|
||||
f2 (arr2);// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
|
||||
fp2 (&arr2);// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
|
||||
}
|
||||
|
||||
int(&r1)[] = arr;// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
|
||||
int(&r2)[10] = arr;
|
||||
int(&r3)[][10] = arr2;// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
|
||||
/* Note that
|
||||
int (&r)[10][] = arr2;
|
||||
is invalid. */
|
||||
int(&r4)[10][10] = arr2;
|
||||
|
||||
int(*p1)[] = &arr;// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
|
||||
int(*p2)[10] = &arr;
|
||||
int(*p3)[][10] = &arr2;// { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
|
||||
int(*p4)[10][10] = &arr2;
|
22
gcc/testsuite/g++.dg/cpp2a/array-conv10.C
Normal file
22
gcc/testsuite/g++.dg/cpp2a/array-conv10.C
Normal file
@ -0,0 +1,22 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do compile { target c++17 } }
|
||||
// { dg-options "-Wpedantic" }
|
||||
|
||||
// The other direction: converting from int[] to int(&)[3] is forbidden.
|
||||
|
||||
extern int a[];
|
||||
extern int (*b)[];
|
||||
extern int (&c)[];
|
||||
int (&y)[] = a;
|
||||
int (&x)[3] = y; // { dg-error "cannot bind reference" }
|
||||
int (&z)[3] = a; // { dg-error "cannot bind reference" }
|
||||
|
||||
void f(int (*)[3]);
|
||||
void f2(int (&)[3]);
|
||||
|
||||
void
|
||||
test ()
|
||||
{
|
||||
f(b); // { dg-error "cannot convert" }
|
||||
f2(c); // { dg-error "cannot bind reference" }
|
||||
}
|
23
gcc/testsuite/g++.dg/cpp2a/array-conv11.C
Normal file
23
gcc/testsuite/g++.dg/cpp2a/array-conv11.C
Normal file
@ -0,0 +1,23 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do compile { target c++2a } }
|
||||
// { dg-options "-Wpedantic" }
|
||||
|
||||
// Test flexible array member. Here we're binding int[] to int[]. This worked
|
||||
// even before P0388R4.
|
||||
|
||||
typedef int T[];
|
||||
extern T arr;
|
||||
T &t1 = arr;
|
||||
|
||||
struct S {
|
||||
int i;
|
||||
int a[]; // { dg-warning "flexible array member" }
|
||||
};
|
||||
|
||||
void f (int (&)[]);
|
||||
|
||||
void
|
||||
test (S s)
|
||||
{
|
||||
f (s.a);
|
||||
}
|
12
gcc/testsuite/g++.dg/cpp2a/array-conv12.C
Normal file
12
gcc/testsuite/g++.dg/cpp2a/array-conv12.C
Normal file
@ -0,0 +1,12 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do compile { target c++2a } }
|
||||
// { dg-options "-Wpedantic" }
|
||||
|
||||
int arr[1] = { 42 };
|
||||
int(&r)[]{arr};
|
||||
int(&r2)[] = {arr};
|
||||
int(&&r3)[]{};
|
||||
int(&&r4)[]{42};
|
||||
int(&&r5)[] = {};
|
||||
int(&&r6)[] = {42};
|
||||
int(&r7)[](arr); // { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } }
|
17
gcc/testsuite/g++.dg/cpp2a/array-conv13.C
Normal file
17
gcc/testsuite/g++.dg/cpp2a/array-conv13.C
Normal file
@ -0,0 +1,17 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
template <typename T> void foo(T);
|
||||
|
||||
template <typename F, typename T, typename = decltype(foo<T>(F()))>
|
||||
void test(int) { }
|
||||
|
||||
// No other overload, so if the above fails because of the conversion,
|
||||
// we fail.
|
||||
|
||||
void
|
||||
fn ()
|
||||
{
|
||||
test<int(*)[2], int(*)[]>(0);
|
||||
test<int(*)[], int(*)[]>(0);
|
||||
}
|
17
gcc/testsuite/g++.dg/cpp2a/array-conv14.C
Normal file
17
gcc/testsuite/g++.dg/cpp2a/array-conv14.C
Normal file
@ -0,0 +1,17 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
void f(const int(*)[]);
|
||||
void fb(const int(*)[3]);
|
||||
void f2(const int(&)[]);
|
||||
void fb2(const int(&)[3]);
|
||||
|
||||
void
|
||||
g ()
|
||||
{
|
||||
int arr[3];
|
||||
f(&arr);
|
||||
fb(&arr);
|
||||
f2(arr);
|
||||
fb2(arr);
|
||||
}
|
23
gcc/testsuite/g++.dg/cpp2a/array-conv15.C
Normal file
23
gcc/testsuite/g++.dg/cpp2a/array-conv15.C
Normal file
@ -0,0 +1,23 @@
|
||||
// PR c++/69531 - DR 1307, Overload resolution based on size of array init-list.
|
||||
// { dg-do run { target c++2a } }
|
||||
|
||||
int f(int, int const(&)[2]) { return 1; }
|
||||
int f(double, int const(&)[2]) { return 2; }
|
||||
|
||||
int f2(int, int const(&)[1]) { return 1; }
|
||||
int f2(int, int const(&)[2]) { return 2; }
|
||||
|
||||
int f3(int, int const(&)[]) { return 1; }
|
||||
int f3(double, int const(&)[]) { return 2; }
|
||||
|
||||
int main ()
|
||||
{
|
||||
if (f (1, {1}) != 1)
|
||||
__builtin_abort ();
|
||||
|
||||
if (f2 (1, {1}) != 1)
|
||||
__builtin_abort ();
|
||||
|
||||
if (f3 (1, {1}) != 1)
|
||||
__builtin_abort ();
|
||||
}
|
16
gcc/testsuite/g++.dg/cpp2a/array-conv16.C
Normal file
16
gcc/testsuite/g++.dg/cpp2a/array-conv16.C
Normal file
@ -0,0 +1,16 @@
|
||||
// PR c++/91364 - P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
using P = int *(*)[3];
|
||||
using S = const int *const (*)[];
|
||||
using Q = const int *const (*)[3];
|
||||
using Qi = const int *[3];
|
||||
using Q2 = Qi const *;
|
||||
|
||||
void
|
||||
f (P p, S s, Q q, Q2 q2)
|
||||
{
|
||||
s = p;
|
||||
s = q;
|
||||
s = q2;
|
||||
}
|
39
gcc/testsuite/g++.dg/cpp2a/array-conv17.C
Normal file
39
gcc/testsuite/g++.dg/cpp2a/array-conv17.C
Normal file
@ -0,0 +1,39 @@
|
||||
// PR c++/91364 - P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
// As conversion/qual1.C, but with [].
|
||||
|
||||
int *a[4];
|
||||
const int *const(*ap1)[] = &a;
|
||||
/* if at some level k the P2 is more cv-qualified than P1, then there
|
||||
must be a const at every single level (other than level zero) of P2
|
||||
up until k. */
|
||||
const int *(*ap2)[] = &a; // { dg-error "cannot convert" }
|
||||
int *const(*ap3)[] = &a;
|
||||
int *(*ap4)[] = &a;
|
||||
int *(*const ap5)[] = &a;
|
||||
const int *const(*const ap6)[] = &a;
|
||||
int *const(*const ap7)[] = &a;
|
||||
int *(*const ap8)[] = &a;
|
||||
|
||||
const int *b[4];
|
||||
const int *const(*bp1)[] = &b;
|
||||
const int *(*bp2)[] = &b;
|
||||
int *const(*bp3)[] = &b; // { dg-error "cannot convert" }
|
||||
int *(*bp4)[] = &b; // { dg-error "cannot convert" }
|
||||
int *(*const bp5)[] = &b; // { dg-error "cannot convert" }
|
||||
const int *const(*const bp6)[] = &b;
|
||||
int *const(*const bp7)[] = &b; // { dg-error "cannot convert" }
|
||||
int *(*const bp8)[] = &b; // { dg-error "cannot convert" }
|
||||
|
||||
int *c[2][3];
|
||||
int const *const (*cp1)[] = c;
|
||||
int const *(*cp2)[] = c; // { dg-error "cannot convert" }
|
||||
int const *const (*const cp3)[] = c;
|
||||
int *const (*cp4)[] = c;
|
||||
int *(*cp5)[] = c;
|
||||
|
||||
double *const (*d)[3];
|
||||
double const *const (*e)[] = d;
|
||||
int *(*f)[3];
|
||||
const int *const (*g)[] = f;
|
26
gcc/testsuite/g++.dg/cpp2a/array-conv2.C
Normal file
26
gcc/testsuite/g++.dg/cpp2a/array-conv2.C
Normal file
@ -0,0 +1,26 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
struct A {
|
||||
A();
|
||||
A(const A(&)[2]);
|
||||
};
|
||||
|
||||
using T = A[];
|
||||
using U = A[2];
|
||||
|
||||
// t binds directly to U{} now. Before it bound indirectly to a temporary
|
||||
// A{U{}}. ??? But we don't do it now; see reference_binding and the
|
||||
// BRACE_ENCLOSED_INITIALIZER_P block.
|
||||
A (&&t)[] = {U{}};
|
||||
|
||||
U u{};
|
||||
|
||||
T &
|
||||
foo ()
|
||||
{
|
||||
// This didn't compile before P0388R4: invalid initialization of non-const
|
||||
// reference of type 'A (&)[]' from an rvalue of type
|
||||
// '<brace-enclosed initializer list>'.
|
||||
return {u};
|
||||
}
|
26
gcc/testsuite/g++.dg/cpp2a/array-conv3.C
Normal file
26
gcc/testsuite/g++.dg/cpp2a/array-conv3.C
Normal file
@ -0,0 +1,26 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do run { target c++2a } }
|
||||
|
||||
// Ranking of reference initialization conversions
|
||||
|
||||
int f(int(&)[]) { return 1; } // (1)
|
||||
int f(int(&)[1]) { return 2; } // (2)
|
||||
|
||||
int h(int(*)[]) { return 1; } // (a)
|
||||
int h(int(*)[1]) { return 2; } // (b)
|
||||
|
||||
// From P0388R4:
|
||||
// (2) and (b) should clearly be better than (1) and (a), respectively,
|
||||
// as the former overloads are more restricted.
|
||||
// (a) should be worse than (b), which is implied by (a) necessitating
|
||||
// a qualification conversion in that case.
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
int arr[1];
|
||||
if (f(arr) != 2)
|
||||
__builtin_abort ();
|
||||
if (h(&arr) != 2)
|
||||
__builtin_abort ();
|
||||
}
|
24
gcc/testsuite/g++.dg/cpp2a/array-conv4.C
Normal file
24
gcc/testsuite/g++.dg/cpp2a/array-conv4.C
Normal file
@ -0,0 +1,24 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
// Ranking of reference initialization conversions
|
||||
|
||||
void f(int(&)[]) {} // (1)
|
||||
//void f(int(&)[1]) { } // (2)
|
||||
void f(int*) { } // (3)
|
||||
|
||||
//void f2(int(&)[]) { } // (1)
|
||||
void f2(int(&)[1]) { } // (2)
|
||||
void f2(int*) { } // (3)
|
||||
|
||||
// From P0388R4:
|
||||
// (3) should be equal to (1) (as it is to (2))
|
||||
// Check that we get "ambiguous overload" errors.
|
||||
|
||||
void
|
||||
doit ()
|
||||
{
|
||||
int arr[1];
|
||||
f(arr); // { dg-error "ambiguous" }
|
||||
f2(arr); // { dg-error "ambiguous" }
|
||||
}
|
24
gcc/testsuite/g++.dg/cpp2a/array-conv5.C
Normal file
24
gcc/testsuite/g++.dg/cpp2a/array-conv5.C
Normal file
@ -0,0 +1,24 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do run { target c++2a } }
|
||||
|
||||
// Ranking of list-initialization sequences
|
||||
int b(int (&&)[] ) { return 1; } // #1
|
||||
int b(long (&&)[] ) { return 2; } // #2
|
||||
int b(int (&&)[1]) { return 3; } // #3
|
||||
int b(long (&&)[1]) { return 4; } // #4
|
||||
int b(int (&&)[2]) { return 5; } // #5
|
||||
|
||||
/* Here,
|
||||
-- #1, #3 and #5 should rank better than both #2 and #4, as no promotion
|
||||
is necessitated.
|
||||
-- #1 should rank worse than #3, being far less specialized.
|
||||
-- #1 should rank better than #5, as the latter requires a larger array
|
||||
temporary. (#3 also ranks better than #5 for the same reason--cf. core
|
||||
issue 1307). */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (b({1}) != 3)
|
||||
__builtin_abort ();
|
||||
}
|
28
gcc/testsuite/g++.dg/cpp2a/array-conv6.C
Normal file
28
gcc/testsuite/g++.dg/cpp2a/array-conv6.C
Normal file
@ -0,0 +1,28 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do run { target c++2a } }
|
||||
|
||||
// Ranking of reference initialization conversions
|
||||
|
||||
int f1(const int(&)[]) { return 1; }
|
||||
int f1(const int(&)[1]) { return 2; }
|
||||
|
||||
int f2(const int(&)[]) { return 1; }
|
||||
int f2(int(&)[1]) { return 2; }
|
||||
|
||||
int f3(int(&)[]) { return 1; }
|
||||
int f3(const int(&)[1]) { return 2; }
|
||||
|
||||
const int arr[1] = { 42 };
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (f1(arr) != 2)
|
||||
__builtin_abort ();
|
||||
|
||||
if (f2(arr) != 1)
|
||||
__builtin_abort ();
|
||||
|
||||
if (f3(arr) != 2)
|
||||
__builtin_abort ();
|
||||
}
|
34
gcc/testsuite/g++.dg/cpp2a/array-conv7.C
Normal file
34
gcc/testsuite/g++.dg/cpp2a/array-conv7.C
Normal file
@ -0,0 +1,34 @@
|
||||
// PR c++/69531 - DR 1307, Overload resolution based on size of array init-list.
|
||||
// { dg-do run { target c++2a } }
|
||||
|
||||
int f(int const(&)[]) { return 1; }
|
||||
int f(int const(&)[2]) { return 2; }
|
||||
|
||||
int f2(int const(&)[]) { return 1; }
|
||||
int f2(int const(&)[1]) { return 2; }
|
||||
|
||||
int f3(int const(&)[]) { return 1; }
|
||||
int f3(int const(&)[1]) { return 2; }
|
||||
int f3(int const(&)[2]) { return 3; }
|
||||
|
||||
int main ()
|
||||
{
|
||||
if (f ({}) != 1)
|
||||
__builtin_abort ();
|
||||
if (f ({1}) != 1)
|
||||
__builtin_abort ();
|
||||
if (f ({1, 2}) != 2)
|
||||
__builtin_abort ();
|
||||
|
||||
if (f2 ({}) != 1)
|
||||
__builtin_abort ();
|
||||
if (f2 ({1}) != 2)
|
||||
__builtin_abort ();
|
||||
|
||||
if (f3 ({}) != 1)
|
||||
__builtin_abort ();
|
||||
if (f3 ({1}) != 2)
|
||||
__builtin_abort ();
|
||||
if (f3 ({1, 2}) != 3)
|
||||
__builtin_abort ();
|
||||
}
|
26
gcc/testsuite/g++.dg/cpp2a/array-conv8.C
Normal file
26
gcc/testsuite/g++.dg/cpp2a/array-conv8.C
Normal file
@ -0,0 +1,26 @@
|
||||
// PR c++/69531 - DR 1307, Overload resolution based on size of array init-list.
|
||||
// { dg-do run { target c++2a } }
|
||||
// Example from [over.ics.rank].
|
||||
|
||||
int f(int (&&)[] ) { return 1; } // #1
|
||||
int f(double (&&)[] ) { return 2; } // #2
|
||||
int f(int (&&)[2]) { return 3; } // #3
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
// Calls #1: Better than #2 due to conversion, better than #3 due to bounds.
|
||||
if (f({1}) != 1)
|
||||
__builtin_abort ();
|
||||
// Calls #2: Identity conversion is better than floating-integral conversion.
|
||||
if (f({1.0}) != 2)
|
||||
__builtin_abort ();
|
||||
// Calls #2: Identity conversion is better than floating-integral conversion.
|
||||
if (f({1.0, 2.0}) != 2)
|
||||
__builtin_abort ();
|
||||
// Calls #3: Converting to array of known bound is better than to unknown
|
||||
// bound, and an identity conversion is better than floating-integral
|
||||
// conversion.
|
||||
if (f({1, 2}) != 3)
|
||||
__builtin_abort ();
|
||||
}
|
27
gcc/testsuite/g++.dg/cpp2a/array-conv9.C
Normal file
27
gcc/testsuite/g++.dg/cpp2a/array-conv9.C
Normal file
@ -0,0 +1,27 @@
|
||||
// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound.
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
int arr[1];
|
||||
extern int arr2[];
|
||||
|
||||
void
|
||||
test ()
|
||||
{
|
||||
int (&r)[1] = const_cast<int(&)[1]>(arr);
|
||||
int (&r2)[] = const_cast<int(&)[]>(arr); // { dg-error "invalid" }
|
||||
int (&r3)[1] = (int(&)[1]) arr;
|
||||
int (&r4)[] = (int(&)[]) arr;
|
||||
int (&r5)[1] = static_cast<int(&)[1]>(arr);
|
||||
int (&r6)[] = static_cast<int(&)[]>(arr);
|
||||
|
||||
// Try c_cast_p.
|
||||
int(*p1)[] = (int(*)[]) &arr;
|
||||
int(*p2)[1] = (int(*)[]) &arr; // { dg-error "cannot convert" }
|
||||
int(*p3)[] = (int(*)[1]) &arr;
|
||||
int(*p4)[] = (int(*)[1]) &arr2;
|
||||
int(*p5)[] = (int(*)[]) (int(*)[1]) &arr;
|
||||
int(*p6)[] = (int(*)[1]) (int(*)[]) &arr;
|
||||
int(*p7)[] = static_cast<int(*)[]>(&arr);
|
||||
int(*p8)[] = static_cast<int(*)[1]>(&arr);
|
||||
int(*p9)[] = static_cast<int(*)[1]>(&arr2); // { dg-error "invalid" }
|
||||
}
|
@ -20,7 +20,7 @@ void function_0 ()
|
||||
{
|
||||
// we miss the first two because typeck.c (comp_array_types) deems
|
||||
// it okay if one of the sizes is null
|
||||
ptr_to_array_of_ints = ptr_to_array_of_3_ints; // { dg-error "" }
|
||||
ptr_to_array_of_ints = ptr_to_array_of_3_ints; // { dg-error "conversions to arrays" "" { target c++17_down } }
|
||||
ptr_to_array_of_3_ints = ptr_to_array_of_ints; // { dg-error "" }
|
||||
|
||||
ptr_to_array_of_3_ints = ptr_to_array_of_5_ints; // { dg-error "" }
|
||||
|
@ -1,3 +1,11 @@
|
||||
2019-10-09 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/91364 - P0388R4: Permit conversions to arrays of unknown bound.
|
||||
PR c++/69531 - DR 1307: Differently bounded array parameters.
|
||||
PR c++/88128 - DR 330: Qual convs and pointers to arrays of pointers.
|
||||
* testsuite/23_containers/span/lwg3255.cc: Adjust test to match the
|
||||
post-P0388R4 behavior.
|
||||
|
||||
2019-10-09 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
PR libstdc++/91057
|
||||
|
@ -28,8 +28,7 @@ using std::is_constructible_v;
|
||||
|
||||
// LWG 3255 span's array constructor is too strict
|
||||
|
||||
// FIXME: remove '!' from next line when P0388R4 is implemented:
|
||||
static_assert( ! is_constructible_v<span<const int* const>, array<int*, 2>> );
|
||||
static_assert( is_constructible_v<span<const int* const>, array<int*, 2>> );
|
||||
static_assert( is_constructible_v<span<const int>, array<const int, 4>> );
|
||||
|
||||
static_assert( is_constructible_v<span<int, 1>, int(&)[1]> );
|
||||
|
Loading…
Reference in New Issue
Block a user