From patchwork Fri Oct 4 22:42:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 1172075 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-510324-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="xlvzuoOT"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46lPyX5XfRz9sPJ for ; Sat, 5 Oct 2019 08:42:26 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=UcOZURALtNKpG48T6kd91RFKMKiBYJGFCHaAUTSLmwZGpSnINAE9j l+in+5I7Utecm/DypyuUE674ZMr32xZuDSRNUR4KfOxVLCxlPQhNprGVONVvYhdu DWkIRRuev4xr7S6TdV4R17wqnUhHz/dOCcghnToyiUtKKwekUhd6vc= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=uN6O6dhY4MPc66hsQ0JB5ADn1FQ=; b=xlvzuoOTqWP75Vr27Qzv RBuBCMFCiSX4WH2w8TolD/T9agVY1kxxe0fReKqktwmStAazkFSQ1vFtq8zQH4P+ SdgliIIUUD86tQgc0+DtpwTL4RZsRPps/jBS+yfs5KDfi/yUvjmaNh3eCZ+TNbyw oX4DjVxwBrxxFwPFfiYLzU0= Received: (qmail 56788 invoked by alias); 4 Oct 2019 22:42:17 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 56771 invoked by uid 89); 4 Oct 2019 22:42:16 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-22.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=Boost, KIN, ranking, Per X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 04 Oct 2019 22:42:12 +0000 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CB16183F3C for ; Fri, 4 Oct 2019 22:42:10 +0000 (UTC) Received: from redhat.com (ovpn-120-188.rdu2.redhat.com [10.10.120.188]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DA3155D6C8; Fri, 4 Oct 2019 22:42:09 +0000 (UTC) Date: Fri, 4 Oct 2019 18:42:07 -0400 From: Marek Polacek To: GCC Patches , Jason Merrill , Jonathan Wakely Subject: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531) Message-ID: <20191004224207.GU2954@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.12.1 (2019-06-15) 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. Considering "int[]" and "int[2]" similar types has interesting impact, as observed in the libstdc++ testsuite. Arrays are always a bit convoluted because you can have multidimensional arrays, though here it wasn't so bad, because only the first dimension can be blank. But there are flexible array members which are also boundless. One thing I know of this patch doesn't attempt to handle is using U = A[2]; A (&&t)[] = {U{}}; // should bind to U{} now for which see reference_binding. It didn't seem like too big a deal though. Successfully built Boost and cmcstl2. Bootstrapped/regtested on x86_64-linux, ok for trunk? Jon, are you OK with the libstdc++ changes? 2019-10-04 Marek Polacek PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound. PR c++/69531 - Implement CWG 1307: Differently bounded array parameters. * call.c (build_array_conv): Build ck_identity at the beginning of the conversion. (standard_conversion): Pass false to comp_ptr_ttypes_const. (maybe_warn_array_conv): New. (convert_like_real): Call it. (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. * typeck.c (similar_type_p): Handle ARRAY_TYPE. (build_const_cast_1): Pass false to comp_ptr_ttypes_const. (comp_ptr_ttypes_real): Use comp_array_types. (comp_ptr_ttypes_const): New bool parameter. Use comp_array_types. * 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-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. * g++.old-deja/g++.bugs/900520_02.C: Likewise. * g++.old-deja/g++.other/typeck1.C: Likewise. * testsuite/20_util/shared_ptr/cons/array.cc: Adjust static_assert. * testsuite/experimental/memory/shared_ptr/cons/copy_ctor_neg.cc: Remove dg-error. * testsuite/experimental/memory/shared_ptr/cons/unique_ptr_ctor.cc: Adjust static_assert. * testsuite/experimental/memory/shared_ptr/cons/weak_ptr_ctor.cc: Likewise. diff --git gcc/gcc/cp/call.c gcc/gcc/cp/call.c index 56dcbd391c1..7002a9ba57f 100644 --- gcc/gcc/cp/call.c +++ gcc/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... */ @@ -1078,7 +1081,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; } @@ -1378,7 +1381,9 @@ 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, + /*allow_redeclaration=*/false)) /* In a C-style cast, we ignore CV-qualification because we are allowed to perform a static_cast followed by a const_cast. */ @@ -1670,7 +1675,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; @@ -6982,6 +6994,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) + return; + + if (conv_binds_to_array_of_unknown_bound (c) + ^ (TYPE_DOMAIN (type) == NULL_TREE)) + 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 @@ -7410,6 +7443,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. @@ -7493,7 +7528,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: @@ -10083,6 +10121,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: @@ -10196,6 +10278,37 @@ 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. */ + else if (conv_binds_to_array_of_unknown_bound (t1)) + return -1; + else if (conv_binds_to_array_of_unknown_bound (t2)) + return 1; + else + /* They can't both bind to array of unknown bound. */ + gcc_unreachable (); + } else { /* For ambiguous or aggregate conversions, use the target type as @@ -10491,6 +10604,26 @@ 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. */ + if (conv_binds_to_array_of_unknown_bound (ref_conv1)) + return -1; + else if (conv_binds_to_array_of_unknown_bound (ref_conv2)) + 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 gcc/gcc/cp/cp-tree.h gcc/gcc/cp/cp-tree.h index be1a44e4373..f812c235c11 100644 --- gcc/gcc/cp/cp-tree.h +++ gcc/gcc/cp/cp-tree.h @@ -7456,7 +7456,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, bool); 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 gcc/gcc/cp/typeck.c gcc/gcc/cp/typeck.c index d549450a605..e821f5dfdaf 100644 --- gcc/gcc/cp/typeck.c +++ gcc/gcc/cp/typeck.c @@ -1549,10 +1549,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, /*allow_redeclaration=*/true); return false; } @@ -7858,7 +7858,8 @@ 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, + /*allow_redeclaration=*/false)) { if (valid_p) { @@ -9888,6 +9889,7 @@ comp_ptr_ttypes_real (tree to, tree from, int constp) { bool to_more_cv_qualified = false; bool is_opaque_pointer = false; + bool is_comp_array = false; for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from)) { @@ -9920,9 +9922,14 @@ 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 (TREE_CODE (to) == ARRAY_TYPE) + is_comp_array = comp_array_types (to, from, + /*allow_redeclaration=*/true); + if (!TYPE_PTR_P (to) && !TYPE_PTRDATAMEM_P (to)) return ((constp >= 0 || to_more_cv_qualified) && (is_opaque_pointer + || is_comp_array || same_type_ignoring_top_level_qualifiers_p (to, from))); } } @@ -10023,12 +10030,13 @@ 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. ALLOW_REDECLARATION is true if [] can match [size]. */ bool -comp_ptr_ttypes_const (tree to, tree from) +comp_ptr_ttypes_const (tree to, tree from, bool allow_redeclaration) { bool is_opaque_pointer = false; + bool is_comp_array = false; for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from)) { @@ -10043,8 +10051,12 @@ comp_ptr_ttypes_const (tree to, tree from) if (VECTOR_TYPE_P (to)) is_opaque_pointer = vector_targets_convertible_p (to, from); + if (TREE_CODE (to) == ARRAY_TYPE) + is_comp_array = comp_array_types (to, from, allow_redeclaration); + if (!TYPE_PTR_P (to)) return (is_opaque_pointer + || is_comp_array || same_type_ignoring_top_level_qualifiers_p (to, from)); } } diff --git gcc/gcc/testsuite/g++.dg/cpp0x/initlist-array3.C gcc/gcc/testsuite/g++.dg/cpp0x/initlist-array3.C index 1a94f4ed55b..4140cd92d7b 100644 --- gcc/gcc/testsuite/g++.dg/cpp0x/initlist-array3.C +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp0x/initlist-array7.C gcc/gcc/testsuite/g++.dg/cpp0x/initlist-array7.C new file mode 100644 index 00000000000..7a689c6675f --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp0x/initlist-array8.C gcc/gcc/testsuite/g++.dg/cpp0x/initlist-array8.C new file mode 100644 index 00000000000..ac2774e06b4 --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv1.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv1.C new file mode 100644 index 00000000000..e90b340b0d6 --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv10.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv10.C new file mode 100644 index 00000000000..f009e1e66b5 --- /dev/null +++ gcc/gcc/testsuite/g++.dg/cpp2a/array-conv10.C @@ -0,0 +1,21 @@ +// 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]. + +extern int a[]; +extern int (*b)[]; +extern int (&c)[]; +int (&y)[] = a; +int (&x)[3] = y; // { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } } + +void f(int (*)[3]); +void f2(int (&)[3]); + +void +test () +{ + f(b); // { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } } + f2(c); // { dg-warning "conversions to arrays of unknown bound are only available" "" { target c++17_down } } +} diff --git gcc/gcc/testsuite/g++.dg/cpp2a/array-conv11.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv11.C new file mode 100644 index 00000000000..a072b29191d --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv12.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv12.C new file mode 100644 index 00000000000..1156ea32df5 --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv13.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv13.C new file mode 100644 index 00000000000..9908b7e9118 --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv2.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv2.C new file mode 100644 index 00000000000..5245d830f1f --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv3.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv3.C new file mode 100644 index 00000000000..3d92b401247 --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv4.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv4.C new file mode 100644 index 00000000000..979c69b0555 --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv5.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv5.C new file mode 100644 index 00000000000..34678f5cead --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv6.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv6.C new file mode 100644 index 00000000000..c2389c82273 --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv7.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv7.C new file mode 100644 index 00000000000..07c709ff10f --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv8.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv8.C new file mode 100644 index 00000000000..635c7679a21 --- /dev/null +++ gcc/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 gcc/gcc/testsuite/g++.dg/cpp2a/array-conv9.C gcc/gcc/testsuite/g++.dg/cpp2a/array-conv9.C new file mode 100644 index 00000000000..e56e4a3e54e --- /dev/null +++ gcc/gcc/testsuite/g++.dg/cpp2a/array-conv9.C @@ -0,0 +1,11 @@ +// PR c++/91364 - Implement P0388R4: Permit conversions to arrays of unknown bound. +// { dg-do compile { target c++2a } } + +int arr[1]; + +void +test () +{ + int (&r)[1] = const_cast(arr); + int (&r2)[] = const_cast(arr); // { dg-error "invalid" } +} diff --git gcc/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C gcc/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C index 6b52783c09b..3575f1f5a4d 100644 --- gcc/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C +++ gcc/gcc/testsuite/g++.old-deja/g++.bugs/900321_01.C @@ -20,8 +20,8 @@ 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_3_ints = ptr_to_array_of_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 "conversions to arrays" "" { target c++17_down } } ptr_to_array_of_3_ints = ptr_to_array_of_5_ints; // { dg-error "" } ptr_to_array_of_5_ints = ptr_to_array_of_3_ints; // { dg-error "" } diff --git gcc/gcc/testsuite/g++.old-deja/g++.bugs/900520_02.C gcc/gcc/testsuite/g++.old-deja/g++.bugs/900520_02.C index 69e0440c120..7d0541d936f 100644 --- gcc/gcc/testsuite/g++.old-deja/g++.bugs/900520_02.C +++ gcc/gcc/testsuite/g++.old-deja/g++.bugs/900520_02.C @@ -9,17 +9,17 @@ typedef int u_array[]; typedef b_array &b_array_ref; typedef u_array &u_array_ref; -void take_b_array_ref (b_array_ref arg) { } // { dg-message "" } passed to here +void take_b_array_ref (b_array_ref arg) { } extern u_array u_array_gbl_obj; u_array_ref u_array_ref_gbl_obj0 = u_array_gbl_obj; -b_array_ref b_array_ref_gbl_obj0 = u_array_ref_gbl_obj0; // { dg-error "" } invalid declaration +b_array_ref b_array_ref_gbl_obj0 = u_array_ref_gbl_obj0; // { dg-error "conversions to arrays" "" { target c++17_down } } void test_passing () { - take_b_array_ref (u_array_ref_gbl_obj0); // { dg-error "" } invalid call + take_b_array_ref (u_array_ref_gbl_obj0); // { dg-error "conversions to arrays" "" { target c++17_down } } } b_array u_array_gbl_obj; diff --git gcc/gcc/testsuite/g++.old-deja/g++.other/typeck1.C gcc/gcc/testsuite/g++.old-deja/g++.other/typeck1.C index d520667b63d..bb4db80e214 100644 --- gcc/gcc/testsuite/g++.old-deja/g++.other/typeck1.C +++ gcc/gcc/testsuite/g++.old-deja/g++.other/typeck1.C @@ -13,5 +13,5 @@ extern int m[7]; // OK void f(int (*j)[3]) { extern int (*k)[]; - f(k); // { dg-error "" } passing wrong type + f(k); // { dg-error "conversions to arrays" "" { target c++17_down } } } diff --git gcc/libstdc++-v3/testsuite/20_util/shared_ptr/cons/array.cc gcc/libstdc++-v3/testsuite/20_util/shared_ptr/cons/array.cc index ef51e2c63bc..2d05b1d0cb8 100644 --- gcc/libstdc++-v3/testsuite/20_util/shared_ptr/cons/array.cc +++ gcc/libstdc++-v3/testsuite/20_util/shared_ptr/cons/array.cc @@ -35,7 +35,9 @@ static_assert( check() ); static_assert( check() ); static_assert( check() ); static_assert( check() ); -static_assert( check() ); +// This is fine since P0388R4: we can form a conversion from +// int[] to int[2]. +static_assert( !check() ); static_assert( check() ); static_assert( check() ); diff --git gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/copy_ctor_neg.cc gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/copy_ctor_neg.cc index 89f7fc9bb12..bcc26d3766b 100644 --- gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/copy_ctor_neg.cc +++ gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/copy_ctor_neg.cc @@ -40,7 +40,7 @@ void test02() { std::experimental::shared_ptr a(new A[3]); - std::experimental::shared_ptr spa(a); // { dg-error "no matching" } + std::experimental::shared_ptr spa(a); } int diff --git gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/unique_ptr_ctor.cc gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/unique_ptr_ctor.cc index be23571e0ef..570f82377e3 100644 --- gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/unique_ptr_ctor.cc +++ gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/unique_ptr_ctor.cc @@ -49,7 +49,8 @@ static_assert( !constructible< A, A[] >(), "A -> A[] not compatible" ); static_assert( !constructible< A, A[1] >(), "A -> A[1] not compatible" ); static_assert( !constructible< A[], A >(), "A[] -> A not compatible" ); static_assert( constructible< A[], A[] >(), "A[] -> A[] compatible" ); -static_assert( !constructible< A[], A[1] >(), "A[] -> A[1] not compatible" ); +// Changed in P0388R4. +static_assert( constructible< A[], A[1] >(), "A[] -> A[1] not compatible" ); static_assert( constructible< B, A >(), "B -> A compatible" ); static_assert( !constructible< B, A[] >(), "B -> A[] not compatible" ); diff --git gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/weak_ptr_ctor.cc gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/weak_ptr_ctor.cc index 08df647d77e..bbe47e487a7 100644 --- gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/weak_ptr_ctor.cc +++ gcc/libstdc++-v3/testsuite/experimental/memory/shared_ptr/cons/weak_ptr_ctor.cc @@ -42,7 +42,8 @@ static_assert( !constructible< A, A[] >(), "A -> A[] not compatible" ); static_assert( !constructible< A, A[1] >(), "A -> A[1] not compatible" ); static_assert( !constructible< A[], A >(), "A[] -> A not compatible" ); static_assert( constructible< A[], A[] >(), "A[] -> A[] compatible" ); -static_assert( !constructible< A[], A[1] >(), "A[] -> A[1] not compatible" ); +// Changed in P0388R4. +static_assert( constructible< A[], A[1] >(), "A[] -> A[1] not compatible" ); static_assert( !constructible< A[1], A >(), "A[1] -> A not compatible" ); static_assert( constructible< A[1], A[] >(), "A[1] -> A[] compatible" ); static_assert( constructible< A[1], A[1] >(), "A[1] -> A[1] compatible" );