Re: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-10 Thread Jonathan Wakely

On 09/10/19 16:29 -0400, Marek Polacek wrote:

On Wed, Oct 09, 2019 at 11:01:39AM +0100, Jonathan Wakely wrote:

On 07/10/19 14:56 -0400, Jason Merrill wrote:
> On 10/7/19 1:42 PM, Marek Polacek wrote:
> > @@ -7401,8 +7432,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, "binding reference of type %qH to %qI "
> > + "discards array bounds", totype, extype);
>
> If we're converting to T[N], that would be adding, not discarding, array
> bounds?

I don't think the diagnostic would be very good if we say "adds array
bounds" though. How about being consistent with the existing error for
similar cases?

a.cc:4:17: error: invalid initialization of reference of type ‘int (&)[3]’ from 
expression of type ‘int []’
  int ()[3] = a;
^


In my latest patch the error message reads "cannot bind reference of type T to U due 
to different array bounds".
It'd be trivial to adjust it if anyone hates that.


Works for me.



Re: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-09 Thread Jason Merrill

On 10/9/19 4:26 PM, Marek Polacek wrote:

On Tue, Oct 08, 2019 at 01:50:17PM -0400, Jason Merrill wrote:

That sounds like a bug in grok_reference_init; it isn't properly
implementing

"Otherwise, if the initializer list has a single element of type E and
either T is not a reference type or its
referenced type is reference-related to E, the object or reference is
initialized from that element"


Can that be fixed in a follow up?


Sure.


I'll open a PR.


@@ -9888,6 +9900,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 +9933,16 @@ 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)
+   /* P0388R4 allows a conversion from int[N] to int[] but not the
+  other way round.  */
+   is_comp_array = comp_array_types (to, from, bounds_first,
+ /*tlq_match=*/false);


This seems to stop iterating when we first see an array, but 7.3.5
[conv.qual] seems to allow conversion to unknown bounds at multiple levels,
and even qualification conversion of an array of pointers, e.g.

int *ar[4];
const int *()[] = ar;


(Should be const int *const ()[] = ar; I believe.)

Yup, this is us lacking DR 330 which I'd been meaning to fix separately, but the
following patch implements that DR too.

Changes from the previous patch are:
* comp_array_types uses similar_type_p when needed, not same_type_ignoring_...;
* comp_ptr_ttypes_const and comp_ptr_ttypes_real will now look through
   arrays.  Fixed a bug whereby we'd accepted a conversion even if it involed
   converting arrays of different bounds;
* a bunch of new tests (qual1.C, qual2.C, qual3.C, ref2.C, ref3.C) to cover
   CWG 330;
* more tests to cover CWG 330 and P0388R4: array-conv16.C, array-conv17.C
* 23_containers/span/lwg3255.cc specifically mentions P0388R4 in a FIXME, so
   trivially adjusted.


@@ -10043,8 +10064,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, cb, /*tlq_match=*/false);
+
 if (!TYPE_PTR_P (to))
return (is_opaque_pointer
+   || is_comp_array
|| same_type_ignoring_top_level_qualifiers_p (to, from));


Likewise.


Fixed too.

Bootstrapped/regtested on x86_64-linux, built Boost and cmcstl2.

Ok for trunk?


OK, thanks.


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.

* 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.
* 

Re: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-09 Thread Marek Polacek
On Wed, Oct 09, 2019 at 11:01:39AM +0100, Jonathan Wakely wrote:
> On 07/10/19 14:56 -0400, Jason Merrill wrote:
> > On 10/7/19 1:42 PM, Marek Polacek wrote:
> > > @@ -7401,8 +7432,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, "binding reference of type %qH to %qI "
> > > + "discards array bounds", totype, extype);
> > 
> > If we're converting to T[N], that would be adding, not discarding, array
> > bounds?
> 
> I don't think the diagnostic would be very good if we say "adds array
> bounds" though. How about being consistent with the existing error for
> similar cases?
> 
> a.cc:4:17: error: invalid initialization of reference of type ‘int (&)[3]’ 
> from expression of type ‘int []’
>   int ()[3] = a;
> ^

In my latest patch the error message reads "cannot bind reference of type T to 
U due to different array bounds".
It'd be trivial to adjust it if anyone hates that.

Marek


Re: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-09 Thread Marek Polacek
On Tue, Oct 08, 2019 at 01:50:17PM -0400, Jason Merrill wrote:
> > > That sounds like a bug in grok_reference_init; it isn't properly
> > > implementing
> > > 
> > > "Otherwise, if the initializer list has a single element of type E and
> > > either T is not a reference type or its
> > > referenced type is reference-related to E, the object or reference is
> > > initialized from that element"
> > 
> > Can that be fixed in a follow up?
> 
> Sure.

I'll open a PR.

> > @@ -9888,6 +9900,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 +9933,16 @@ 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)
> > +   /* P0388R4 allows a conversion from int[N] to int[] but not the
> > +  other way round.  */
> > +   is_comp_array = comp_array_types (to, from, bounds_first,
> > + /*tlq_match=*/false);
> 
> This seems to stop iterating when we first see an array, but 7.3.5
> [conv.qual] seems to allow conversion to unknown bounds at multiple levels,
> and even qualification conversion of an array of pointers, e.g.
> 
> int *ar[4];
> const int *()[] = ar;

(Should be const int *const ()[] = ar; I believe.)

Yup, this is us lacking DR 330 which I'd been meaning to fix separately, but the
following patch implements that DR too.

Changes from the previous patch are:
* comp_array_types uses similar_type_p when needed, not same_type_ignoring_...;
* comp_ptr_ttypes_const and comp_ptr_ttypes_real will now look through
  arrays.  Fixed a bug whereby we'd accepted a conversion even if it involed
  converting arrays of different bounds;
* a bunch of new tests (qual1.C, qual2.C, qual3.C, ref2.C, ref3.C) to cover
  CWG 330;
* more tests to cover CWG 330 and P0388R4: array-conv16.C, array-conv17.C
* 23_containers/span/lwg3255.cc specifically mentions P0388R4 in a FIXME, so
  trivially adjusted.

> > @@ -10043,8 +10064,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, cb, /*tlq_match=*/false);
> > +
> > if (!TYPE_PTR_P (to))
> > return (is_opaque_pointer
> > +   || is_comp_array
> > || same_type_ignoring_top_level_qualifiers_p (to, from));
> 
> Likewise.

Fixed too.

Bootstrapped/regtested on x86_64-linux, built Boost and cmcstl2.

Ok for trunk?

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.

* 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.
* 

Re: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-09 Thread Jonathan Wakely

On 07/10/19 14:56 -0400, Jason Merrill wrote:

On 10/7/19 1:42 PM, Marek Polacek wrote:

@@ -7401,8 +7432,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, "binding reference of type %qH to %qI "
+   "discards array bounds", totype, extype);


If we're converting to T[N], that would be adding, not discarding, 
array bounds?


I don't think the diagnostic would be very good if we say "adds array
bounds" though. How about being consistent with the existing error for
similar cases?

a.cc:4:17: error: invalid initialization of reference of type ‘int (&)[3]’ from 
expression of type ‘int []’
  int ()[3] = a;
^



Re: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-08 Thread Jason Merrill

On 10/7/19 7:26 PM, Marek Polacek wrote:

On Mon, Oct 07, 2019 at 02:56:10PM -0400, Jason Merrill wrote:

@@ -1378,7 +1381,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_none))
/* In a C-style cast, we ignore CV-qualification because we
   are allowed to perform a static_cast followed by a
   const_cast.  */


Hmm, I'd expect bounds_either for a C-style cast.


Makes sense, it's just that const_cast shouldn't drop the bounds.


@@ -1670,7 +1673,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 (&)[] = {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.  */


That sounds like a bug in grok_reference_init; it isn't properly
implementing

"Otherwise, if the initializer list has a single element of type E and
either T is not a reference type or its
referenced type is reference-related to E, the object or reference is
initialized from that element"


Can that be fixed in a follow up?


Sure.


 if (CONSTRUCTOR_NELTS (expr) == 1)
{
  tree elt = CONSTRUCTOR_ELT (expr, 0)->value;
@@ -6982,6 +6992,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
@@ -7401,8 +7432,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, "binding reference of type %qH to %qI "
+   "discards array bounds", totype, extype);


If we're converting to T[N], that would be adding, not discarding, array
bounds?


True, I've reworded the error mesage.


+   else
+ error_at (loc, "binding reference of type %qH to %qI "
+   "discards qualifiers", totype, extype);
+ }
else
  gcc_unreachable ();
maybe_print_user_conv_context (convs);
@@ -7410,6 +7453,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 +7538,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, 

Re: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-07 Thread Marek Polacek
On Mon, Oct 07, 2019 at 02:56:10PM -0400, Jason Merrill wrote:
> > @@ -1378,7 +1381,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_none))
> > /* In a C-style cast, we ignore CV-qualification because we
> >are allowed to perform a static_cast followed by a
> >const_cast.  */
> 
> Hmm, I'd expect bounds_either for a C-style cast.

Makes sense, it's just that const_cast shouldn't drop the bounds.

> > @@ -1670,7 +1673,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 (&)[] = {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.  */
> 
> That sounds like a bug in grok_reference_init; it isn't properly
> implementing
> 
> "Otherwise, if the initializer list has a single element of type E and
> either T is not a reference type or its
> referenced type is reference-related to E, the object or reference is
> initialized from that element"

Can that be fixed in a follow up?

> > if (CONSTRUCTOR_NELTS (expr) == 1)
> > {
> >   tree elt = CONSTRUCTOR_ELT (expr, 0)->value;
> > @@ -6982,6 +6992,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
> > @@ -7401,8 +7432,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, "binding reference of type %qH to %qI "
> > +   "discards array bounds", totype, extype);
> 
> If we're converting to T[N], that would be adding, not discarding, array
> bounds?

True, I've reworded the error mesage.

> > +   else
> > + error_at (loc, "binding reference of type %qH to %qI "
> > +   "discards qualifiers", totype, extype);
> > + }
> > else
> >   gcc_unreachable ();
> > maybe_print_user_conv_context (convs);
> > @@ -7410,6 +7453,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 +7538,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)
> 

Re: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-07 Thread Jason Merrill

On 10/7/19 1:42 PM, Marek Polacek wrote:

On Sun, Oct 06, 2019 at 03:39:25PM +, Tam S. B. wrote:

Hi, sorry for chiming in.


Hi, no worries, comments are welcome!


IIUC P0388R4 does not allow implicit conversion from `T(*)[]` to `T(*)[N]`. Per 
[conv.qual]/3,


A prvalue of type `T1` can be converted to type `T2` if the cv-combined type of 
`T1` and `T2` is `T2`.


When T1 is `T(*)[]` and T2 is `T(*)[N]`, the "cv-combined type" is `T(*)[]`, 
which is not the same as T2 = `T(*)[N]`, so conversion should not be permitted.

That is to say, either `comp_ptr_ttypes_real` should not use 
`comp_array_types`, or `comp_array_types` should be extended to handle this 
case correctly.


Indeed, I must've glossed over that.  Fixed by introducing compare_bounds_t,
which says how we should compare arrays when one of them is [].

similar_type_p still must say "yes" for T(*)[] and T(*)[N] though.


Also, does this patch permit conversion from `T(*)[N]` to `const T(*)[]`? I 
think [conv.qual] allows this conversion, but IIUC `comp_array_types` will 
return false in this case, as it uses `same_type_p`.


It does now, array-conv14.C tests it.

Thanks for looking and catching these problems!

Bootstrapped/regtested on x86_64-linux, built Boost and cmcstl2.

Ok for trunk?

2019-10-07  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 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): Use comp_array_types.
(comp_ptr_ttypes_const): New compare_bounds_t 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-conv14.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.

diff --git gcc/gcc/cp/call.c gcc/gcc/cp/call.c
index 56dcbd391c1..1a9c296a812 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;
  }
  
@@ 

Re: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-07 Thread Marek Polacek
On Sun, Oct 06, 2019 at 03:39:25PM +, Tam S. B. wrote:
> Hi, sorry for chiming in.

Hi, no worries, comments are welcome!

> IIUC P0388R4 does not allow implicit conversion from `T(*)[]` to `T(*)[N]`. 
> Per [conv.qual]/3, 
> 
> > A prvalue of type `T1` can be converted to type `T2` if the cv-combined 
> > type of `T1` and `T2` is `T2`.
> 
> When T1 is `T(*)[]` and T2 is `T(*)[N]`, the "cv-combined type" is `T(*)[]`, 
> which is not the same as T2 = `T(*)[N]`, so conversion should not be 
> permitted.
> 
> That is to say, either `comp_ptr_ttypes_real` should not use 
> `comp_array_types`, or `comp_array_types` should be extended to handle this 
> case correctly.

Indeed, I must've glossed over that.  Fixed by introducing compare_bounds_t,
which says how we should compare arrays when one of them is [].

similar_type_p still must say "yes" for T(*)[] and T(*)[N] though.

> Also, does this patch permit conversion from `T(*)[N]` to `const T(*)[]`? I 
> think [conv.qual] allows this conversion, but IIUC `comp_array_types` will 
> return false in this case, as it uses `same_type_p`.

It does now, array-conv14.C tests it.

Thanks for looking and catching these problems!

Bootstrapped/regtested on x86_64-linux, built Boost and cmcstl2.

Ok for trunk?

2019-10-07  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 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): Use comp_array_types.
(comp_ptr_ttypes_const): New compare_bounds_t 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-conv14.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.

diff --git gcc/gcc/cp/call.c gcc/gcc/cp/call.c
index 56dcbd391c1..1a9c296a812 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,7 @@ 

Re: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-07 Thread Jason Merrill

On 10/6/19 11:39 AM, Tam S. B. wrote:

Hi, sorry for chiming in.

IIUC P0388R4 does not allow implicit conversion from `T(*)[]` to `T(*)[N]`. Per 
[conv.qual]/3,


A prvalue of type `T1` can be converted to type `T2` if the cv-combined type of 
`T1` and `T2` is `T2`.


When T1 is `T(*)[]` and T2 is `T(*)[N]`, the "cv-combined type" is `T(*)[]`, 
which is not the same as T2 = `T(*)[N]`, so conversion should not be permitted.

That is to say, either `comp_ptr_ttypes_real` should not use 
`comp_array_types`, or `comp_array_types` should be extended to handle this 
case correctly.

Also, does this patch permit conversion from `T(*)[N]` to `const T(*)[]`? I 
think [conv.qual] allows this conversion, but IIUC `comp_array_types` will 
return false in this case, as it uses `same_type_p`.


Agreed.

Jason



Re: C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-06 Thread Tam S. B.
Hi, sorry for chiming in.

IIUC P0388R4 does not allow implicit conversion from `T(*)[]` to `T(*)[N]`. Per 
[conv.qual]/3, 

> A prvalue of type `T1` can be converted to type `T2` if the cv-combined type 
> of `T1` and `T2` is `T2`.

When T1 is `T(*)[]` and T2 is `T(*)[N]`, the "cv-combined type" is `T(*)[]`, 
which is not the same as T2 = `T(*)[N]`, so conversion should not be permitted.

That is to say, either `comp_ptr_ttypes_real` should not use 
`comp_array_types`, or `comp_array_types` should be extended to handle this 
case correctly.

Also, does this patch permit conversion from `T(*)[N]` to `const T(*)[]`? I 
think [conv.qual] allows this conversion, but IIUC `comp_array_types` will 
return false in this case, as it uses `same_type_p`.

Thanks.



C++ PATCH for C++20 P0388R4 (conversions to arrays of unknown bounds) and CWG 1307 (c++/91364, c++/69531)

2019-10-04 Thread Marek Polacek
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()[] = 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 (&)[] = {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;
+