From 89e0a492af5bec8ffa2ec5d99c4858df50d22c16 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 9 Oct 2019 20:58:00 +0000 Subject: [PATCH] Implement C++20 P0388R4, DR 1307, and DR 330. This patch implements P0388R4, Permit conversions to arrays of unknown bound, . 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 --- gcc/cp/ChangeLog | 29 ++++ gcc/cp/call.c | 160 +++++++++++++++++- gcc/cp/cp-tree.h | 6 +- gcc/cp/typeck.c | 66 +++++--- gcc/testsuite/ChangeLog | 32 ++++ gcc/testsuite/g++.dg/conversion/qual1.C | 51 ++++++ gcc/testsuite/g++.dg/conversion/qual2.C | 14 ++ gcc/testsuite/g++.dg/conversion/qual3.C | 53 ++++++ gcc/testsuite/g++.dg/conversion/ref2.C | 29 ++++ gcc/testsuite/g++.dg/conversion/ref3.C | 4 + gcc/testsuite/g++.dg/cpp0x/initlist-array3.C | 3 +- gcc/testsuite/g++.dg/cpp0x/initlist-array7.C | 21 +++ gcc/testsuite/g++.dg/cpp0x/initlist-array8.C | 35 ++++ gcc/testsuite/g++.dg/cpp2a/array-conv1.C | 33 ++++ gcc/testsuite/g++.dg/cpp2a/array-conv10.C | 22 +++ gcc/testsuite/g++.dg/cpp2a/array-conv11.C | 23 +++ gcc/testsuite/g++.dg/cpp2a/array-conv12.C | 12 ++ gcc/testsuite/g++.dg/cpp2a/array-conv13.C | 17 ++ gcc/testsuite/g++.dg/cpp2a/array-conv14.C | 17 ++ gcc/testsuite/g++.dg/cpp2a/array-conv15.C | 23 +++ gcc/testsuite/g++.dg/cpp2a/array-conv16.C | 16 ++ gcc/testsuite/g++.dg/cpp2a/array-conv17.C | 39 +++++ gcc/testsuite/g++.dg/cpp2a/array-conv2.C | 26 +++ gcc/testsuite/g++.dg/cpp2a/array-conv3.C | 26 +++ gcc/testsuite/g++.dg/cpp2a/array-conv4.C | 24 +++ gcc/testsuite/g++.dg/cpp2a/array-conv5.C | 24 +++ gcc/testsuite/g++.dg/cpp2a/array-conv6.C | 28 +++ gcc/testsuite/g++.dg/cpp2a/array-conv7.C | 34 ++++ gcc/testsuite/g++.dg/cpp2a/array-conv8.C | 26 +++ gcc/testsuite/g++.dg/cpp2a/array-conv9.C | 27 +++ .../g++.old-deja/g++.bugs/900321_01.C | 2 +- libstdc++-v3/ChangeLog | 8 + .../testsuite/23_containers/span/lwg3255.cc | 3 +- 33 files changed, 902 insertions(+), 31 deletions(-) create mode 100644 gcc/testsuite/g++.dg/conversion/qual1.C create mode 100644 gcc/testsuite/g++.dg/conversion/qual2.C create mode 100644 gcc/testsuite/g++.dg/conversion/qual3.C create mode 100644 gcc/testsuite/g++.dg/conversion/ref2.C create mode 100644 gcc/testsuite/g++.dg/conversion/ref3.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-array7.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-array8.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv10.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv11.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv12.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv13.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv14.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv15.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv16.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv17.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv3.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv4.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv5.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv6.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv7.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv8.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/array-conv9.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4eb182947d2..e47e8ca6ddc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,32 @@ +2019-10-09 Marek Polacek + + 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 PR c++/92032 - DR 1601: Promotion of enum with fixed underlying type. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 33ec6a2dcc0..55d2abaaddd 100644 --- a/gcc/cp/call.c +++ b/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, 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) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9ff617be2d4..c1301a451df 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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, diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index ba334e7d5cb..a67dd4b155a 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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)); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f1e3a99233f..5ee2a814831 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,35 @@ +2019-10-09 Marek Polacek + + 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 PR c++/92032 - DR 1601: Promotion of enum with fixed underlying type. diff --git a/gcc/testsuite/g++.dg/conversion/qual1.C b/gcc/testsuite/g++.dg/conversion/qual1.C new file mode 100644 index 00000000000..5022da9da47 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/qual1.C @@ -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; +} diff --git a/gcc/testsuite/g++.dg/conversion/qual2.C b/gcc/testsuite/g++.dg/conversion/qual2.C new file mode 100644 index 00000000000..8a063a03e79 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/qual2.C @@ -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" } diff --git a/gcc/testsuite/g++.dg/conversion/qual3.C b/gcc/testsuite/g++.dg/conversion/qual3.C new file mode 100644 index 00000000000..4b466d9ea5d --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/qual3.C @@ -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

(q); + const_cast

(q2); + const_cast(p); + const_cast(p); + const_cast(p); // { dg-error "invalid .const_cast." } + const_cast

(s); // { dg-error "invalid .const_cast." } + const_cast(q); // { dg-error "invalid .const_cast." } + const_cast(q2); // { dg-error "invalid .const_cast." } + const_cast(s); // { dg-error "invalid .const_cast." } + const_cast(s); // { dg-error "invalid .const_cast." } + const_cast(s); + const_cast(t); + const_cast(q); // { dg-error "invalid .const_cast." } + const_cast(t); // { dg-error "invalid .const_cast." } + + // Test reinterpret_cast. + reinterpret_cast

(q); // { dg-error "casts away qualifiers" } + reinterpret_cast

(q2); // { dg-error "casts away qualifiers" } + reinterpret_cast(p); + reinterpret_cast(p); + reinterpret_cast(p); + reinterpret_cast

(s); // { dg-error "casts away qualifiers" } + reinterpret_cast(q); + reinterpret_cast(q2); + reinterpret_cast(s); + reinterpret_cast(s); + reinterpret_cast(s); // { dg-error "casts away qualifiers" } + reinterpret_cast(t); + reinterpret_cast(q); // { dg-error "casts away qualifiers" } + reinterpret_cast(t); +} diff --git a/gcc/testsuite/g++.dg/conversion/ref2.C b/gcc/testsuite/g++.dg/conversion/ref2.C new file mode 100644 index 00000000000..418e711946f --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/ref2.C @@ -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; diff --git a/gcc/testsuite/g++.dg/conversion/ref3.C b/gcc/testsuite/g++.dg/conversion/ref3.C new file mode 100644 index 00000000000..ca5326ce8e8 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/ref3.C @@ -0,0 +1,4 @@ +int a[2]; +const int (&rc)[2] = a; +volatile int (&rv)[2] = a; +const volatile int (&rcv)[2] = a; diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array3.C b/gcc/testsuite/g++.dg/cpp0x/initlist-array3.C index 1a94f4ed55b..4140cd92d7b 100644 --- a/gcc/testsuite/g++.dg/cpp0x/initlist-array3.C +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array3.C @@ -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}); } diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array7.C b/gcc/testsuite/g++.dg/cpp0x/initlist-array7.C new file mode 100644 index 00000000000..7a689c6675f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array7.C @@ -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 (); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array8.C b/gcc/testsuite/g++.dg/cpp0x/initlist-array8.C new file mode 100644 index 00000000000..ac2774e06b4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array8.C @@ -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 (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv1.C b/gcc/testsuite/g++.dg/cpp2a/array-conv1.C new file mode 100644 index 00000000000..e90b340b0d6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv1.C @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv10.C b/gcc/testsuite/g++.dg/cpp2a/array-conv10.C new file mode 100644 index 00000000000..1ee1a771f63 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv10.C @@ -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" } +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv11.C b/gcc/testsuite/g++.dg/cpp2a/array-conv11.C new file mode 100644 index 00000000000..a072b29191d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv11.C @@ -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); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv12.C b/gcc/testsuite/g++.dg/cpp2a/array-conv12.C new file mode 100644 index 00000000000..1156ea32df5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv12.C @@ -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 } } diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv13.C b/gcc/testsuite/g++.dg/cpp2a/array-conv13.C new file mode 100644 index 00000000000..9908b7e9118 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv13.C @@ -0,0 +1,17 @@ +// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound. +// { dg-do compile { target c++2a } } + +template void foo(T); + +template (F()))> +void test(int) { } + +// No other overload, so if the above fails because of the conversion, +// we fail. + +void +fn () +{ + test(0); + test(0); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv14.C b/gcc/testsuite/g++.dg/cpp2a/array-conv14.C new file mode 100644 index 00000000000..793e85d7b1c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv14.C @@ -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); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv15.C b/gcc/testsuite/g++.dg/cpp2a/array-conv15.C new file mode 100644 index 00000000000..033a74683a7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv15.C @@ -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 (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv16.C b/gcc/testsuite/g++.dg/cpp2a/array-conv16.C new file mode 100644 index 00000000000..bfb39d1c12c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv16.C @@ -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; +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv17.C b/gcc/testsuite/g++.dg/cpp2a/array-conv17.C new file mode 100644 index 00000000000..3313ed466fb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv17.C @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv2.C b/gcc/testsuite/g++.dg/cpp2a/array-conv2.C new file mode 100644 index 00000000000..5245d830f1f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv2.C @@ -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 + // ''. + return {u}; +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv3.C b/gcc/testsuite/g++.dg/cpp2a/array-conv3.C new file mode 100644 index 00000000000..3d92b401247 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv3.C @@ -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 (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv4.C b/gcc/testsuite/g++.dg/cpp2a/array-conv4.C new file mode 100644 index 00000000000..979c69b0555 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv4.C @@ -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" } +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv5.C b/gcc/testsuite/g++.dg/cpp2a/array-conv5.C new file mode 100644 index 00000000000..34678f5cead --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv5.C @@ -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 (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv6.C b/gcc/testsuite/g++.dg/cpp2a/array-conv6.C new file mode 100644 index 00000000000..c2389c82273 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv6.C @@ -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 (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv7.C b/gcc/testsuite/g++.dg/cpp2a/array-conv7.C new file mode 100644 index 00000000000..07c709ff10f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv7.C @@ -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 (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv8.C b/gcc/testsuite/g++.dg/cpp2a/array-conv8.C new file mode 100644 index 00000000000..635c7679a21 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv8.C @@ -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 (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/array-conv9.C b/gcc/testsuite/g++.dg/cpp2a/array-conv9.C new file mode 100644 index 00000000000..82f615db2e7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/array-conv9.C @@ -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(arr); + int (&r2)[] = const_cast(arr); // { dg-error "invalid" } + int (&r3)[1] = (int(&)[1]) arr; + int (&r4)[] = (int(&)[]) arr; + int (&r5)[1] = static_cast(arr); + int (&r6)[] = static_cast(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(&arr); + int(*p8)[] = static_cast(&arr); + int(*p9)[] = static_cast(&arr2); // { dg-error "invalid" } +} diff --git a/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C b/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C index 6b52783c09b..c3b1ab56282 100644 --- a/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C +++ b/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C @@ -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 "" } diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 045fbe3e918..8b7443c17e8 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,11 @@ +2019-10-09 Marek Polacek + + 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 PR libstdc++/91057 diff --git a/libstdc++-v3/testsuite/23_containers/span/lwg3255.cc b/libstdc++-v3/testsuite/23_containers/span/lwg3255.cc index 638c88101f9..bab7da3bf19 100644 --- a/libstdc++-v3/testsuite/23_containers/span/lwg3255.cc +++ b/libstdc++-v3/testsuite/23_containers/span/lwg3255.cc @@ -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, array> ); +static_assert( is_constructible_v, array> ); static_assert( is_constructible_v, array> ); static_assert( is_constructible_v, int(&)[1]> ); -- 2.30.2