diff mbox series

C++ PATCH for c++/57891, narrowing conversions in non-type template arguments

Message ID 20180627165343.GC4896@redhat.com
State New
Headers show
Series C++ PATCH for c++/57891, narrowing conversions in non-type template arguments | expand

Commit Message

Marek Polacek June 27, 2018, 4:53 p.m. UTC
This PR complains about us accepting invalid code like

  template<unsigned int> struct A {};
  A<-1> a;

Where we should detect the narrowing: [temp.arg.nontype] says
"A template-argument for a non-type template-parameter shall be a converted
constant expression ([expr.const]) of the type of the template-parameter."
and a converted constant expression can contain only
- integral conversions other than narrowing conversions,
- [...]."
It spurred e.g.
<https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
and has >=3 dups so it has some visibility.

I think build_converted_constant_expr needs to set check_narrowing.
check_narrowing also always mentions that it's in { } but that is no longer
true; in the future it will also apply to <=>.  We'd probably have to add a new
flag to struct conversion if wanted to distinguish between these.

This does not yet fix detecting narrowing in function templates (78244).

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-06-27  Marek Polacek  <polacek@redhat.com>

	PR c++/57891
	* call.c (build_converted_constant_expr): Set check_narrowing.
	* decl.c (compute_array_index_type): Add warning sentinel.  Use
	input_location.
	* pt.c (convert_nontype_argument): Return NULL_TREE if any errors
	were reported.
	* typeck2.c (check_narrowing): Don't mention { } in diagnostic.

	* g++.dg/cpp0x/Wnarrowing6.C: New test.
	* g++.dg/cpp0x/Wnarrowing7.C: New test.
	* g++.dg/cpp0x/Wnarrowing8.C: New test.
	* g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
	* g++.dg/init/new43.C: Adjust dg-error.
	* g++.dg/other/fold1.C: Likewise.
	* g++.dg/parse/array-size2.C: Likewise.
	* g++.dg/other/vrp1.C: Add dg-error.
	* g++.dg/template/char1.C: Likewise.
	* g++.dg/ext/builtin12.C: Likewise.
	* g++.dg/template/dependent-name3.C: Adjust dg-error.

Comments

Jason Merrill June 27, 2018, 11:35 p.m. UTC | #1
On Wed, Jun 27, 2018 at 12:53 PM, Marek Polacek <polacek@redhat.com> wrote:
> This PR complains about us accepting invalid code like
>
>   template<unsigned int> struct A {};
>   A<-1> a;
>
> Where we should detect the narrowing: [temp.arg.nontype] says
> "A template-argument for a non-type template-parameter shall be a converted
> constant expression ([expr.const]) of the type of the template-parameter."
> and a converted constant expression can contain only
> - integral conversions other than narrowing conversions,
> - [...]."
> It spurred e.g.
> <https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
> and has >=3 dups so it has some visibility.
>
> I think build_converted_constant_expr needs to set check_narrowing.
> check_narrowing also always mentions that it's in { } but that is no longer
> true; in the future it will also apply to <=>.  We'd probably have to add a new
> flag to struct conversion if wanted to distinguish between these.
>
> This does not yet fix detecting narrowing in function templates (78244).
>
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
>
> 2018-06-27  Marek Polacek  <polacek@redhat.com>
>
>         PR c++/57891
>         * call.c (build_converted_constant_expr): Set check_narrowing.
>         * decl.c (compute_array_index_type): Add warning sentinel.  Use
>         input_location.
>         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
>         were reported.
>         * typeck2.c (check_narrowing): Don't mention { } in diagnostic.
>
>         * g++.dg/cpp0x/Wnarrowing6.C: New test.
>         * g++.dg/cpp0x/Wnarrowing7.C: New test.
>         * g++.dg/cpp0x/Wnarrowing8.C: New test.
>         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
>         * g++.dg/init/new43.C: Adjust dg-error.
>         * g++.dg/other/fold1.C: Likewise.
>         * g++.dg/parse/array-size2.C: Likewise.
>         * g++.dg/other/vrp1.C: Add dg-error.
>         * g++.dg/template/char1.C: Likewise.
>         * g++.dg/ext/builtin12.C: Likewise.
>         * g++.dg/template/dependent-name3.C: Adjust dg-error.
>
> diff --git gcc/cp/call.c gcc/cp/call.c
> index 209c1fd2f0e..956c7b149dc 100644
> --- gcc/cp/call.c
> +++ gcc/cp/call.c
> @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
>      }
>
>    if (conv)
> -    expr = convert_like (conv, expr, complain);
> +    {
> +      conv->check_narrowing = !processing_template_decl;

Why !processing_template_decl?  This needs a comment.

> +      expr = convert_like (conv, expr, complain);
> +    }
>    else
>      expr = error_mark_node;
>
> diff --git gcc/cp/pt.c gcc/cp/pt.c
> index 3780f3492aa..12d1a1e1cd3 100644
> --- gcc/cp/pt.c
> +++ gcc/cp/pt.c
> @@ -6669,9 +6669,10 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
>           /* C++17: A template-argument for a non-type template-parameter shall
>              be a converted constant expression (8.20) of the type of the
>              template-parameter.  */
> +         int errs = errorcount;
>           expr = build_converted_constant_expr (type, expr, complain);
>           if (expr == error_mark_node)
> -           return error_mark_node;
> +           return errorcount > errs ? NULL_TREE : error_mark_node;

I suspect that what you want here is to check (complain & tf_error)
rather than errorcount.  Otherwise it needs a comment.

Jason
Marek Polacek June 29, 2018, 7:58 p.m. UTC | #2
On Wed, Jun 27, 2018 at 07:35:15PM -0400, Jason Merrill wrote:
> On Wed, Jun 27, 2018 at 12:53 PM, Marek Polacek <polacek@redhat.com> wrote:
> > This PR complains about us accepting invalid code like
> >
> >   template<unsigned int> struct A {};
> >   A<-1> a;
> >
> > Where we should detect the narrowing: [temp.arg.nontype] says
> > "A template-argument for a non-type template-parameter shall be a converted
> > constant expression ([expr.const]) of the type of the template-parameter."
> > and a converted constant expression can contain only
> > - integral conversions other than narrowing conversions,
> > - [...]."
> > It spurred e.g.
> > <https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
> > and has >=3 dups so it has some visibility.
> >
> > I think build_converted_constant_expr needs to set check_narrowing.
> > check_narrowing also always mentions that it's in { } but that is no longer
> > true; in the future it will also apply to <=>.  We'd probably have to add a new
> > flag to struct conversion if wanted to distinguish between these.
> >
> > This does not yet fix detecting narrowing in function templates (78244).
> >
> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
> >
> > 2018-06-27  Marek Polacek  <polacek@redhat.com>
> >
> >         PR c++/57891
> >         * call.c (build_converted_constant_expr): Set check_narrowing.
> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
> >         input_location.
> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
> >         were reported.
> >         * typeck2.c (check_narrowing): Don't mention { } in diagnostic.
> >
> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
> >         * g++.dg/init/new43.C: Adjust dg-error.
> >         * g++.dg/other/fold1.C: Likewise.
> >         * g++.dg/parse/array-size2.C: Likewise.
> >         * g++.dg/other/vrp1.C: Add dg-error.
> >         * g++.dg/template/char1.C: Likewise.
> >         * g++.dg/ext/builtin12.C: Likewise.
> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
> >
> > diff --git gcc/cp/call.c gcc/cp/call.c
> > index 209c1fd2f0e..956c7b149dc 100644
> > --- gcc/cp/call.c
> > +++ gcc/cp/call.c
> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
> >      }
> >
> >    if (conv)
> > -    expr = convert_like (conv, expr, complain);
> > +    {
> > +      conv->check_narrowing = !processing_template_decl;
> 
> Why !processing_template_decl?  This needs a comment.

Otherwise we'd warn for e.g.

template<int N> struct S { char a[N]; };
S<1> s;

where compute_array_index_type will try to convert the size of the array (which
is a template_parm_index of type int when parsing the template) to size_type.
So I guess I can say that we need to wait for instantiation?

> > +      expr = convert_like (conv, expr, complain);
> > +    }
> >    else
> >      expr = error_mark_node;
> >
> > diff --git gcc/cp/pt.c gcc/cp/pt.c
> > index 3780f3492aa..12d1a1e1cd3 100644
> > --- gcc/cp/pt.c
> > +++ gcc/cp/pt.c
> > @@ -6669,9 +6669,10 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
> >           /* C++17: A template-argument for a non-type template-parameter shall
> >              be a converted constant expression (8.20) of the type of the
> >              template-parameter.  */
> > +         int errs = errorcount;
> >           expr = build_converted_constant_expr (type, expr, complain);
> >           if (expr == error_mark_node)
> > -           return error_mark_node;
> > +           return errorcount > errs ? NULL_TREE : error_mark_node;
> 
> I suspect that what you want here is to check (complain & tf_error)
> rather than errorcount.  Otherwise it needs a comment.

I added a comment.  Checking complain doesn't work becase that doesn't
say if we have really issued an error.  If we have not, and we return
NULL_TREE anyway, we hit this assert:

 8515   if (lost)
 8516     {
 8517       gcc_assert (!(complain & tf_error) || seen_error ());
 8518       return error_mark_node;
 8519     }

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-06-29  Marek Polacek  <polacek@redhat.com>

	PR c++/57891
	* call.c (build_converted_constant_expr): Set check_narrowing.
	* decl.c (compute_array_index_type): Add warning sentinel.  Use
	input_location.
	* pt.c (convert_nontype_argument): Return NULL_TREE if any errors
	were reported.
	* typeck2.c (check_narrowing): Don't mention { } in diagnostic.

	* g++.dg/cpp0x/Wnarrowing6.C: New test.
	* g++.dg/cpp0x/Wnarrowing7.C: New test.
	* g++.dg/cpp0x/Wnarrowing8.C: New test.
	* g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
	* g++.dg/init/new43.C: Adjust dg-error.
	* g++.dg/other/fold1.C: Likewise.
	* g++.dg/parse/array-size2.C: Likewise.
	* g++.dg/other/vrp1.C: Add dg-error.
	* g++.dg/template/char1.C: Likewise.
	* g++.dg/ext/builtin12.C: Likewise.
	* g++.dg/template/dependent-name3.C: Adjust dg-error.

diff --git gcc/cp/call.c gcc/cp/call.c
index 209c1fd2f0e..3e7988e0358 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -4152,7 +4152,12 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
     }
 
   if (conv)
-    expr = convert_like (conv, expr, complain);
+    {
+      /* Only check the narrowing at instantiation time, otherwise
+	 we'd emit bogus warnings for template trees.  */
+      conv->check_narrowing = !processing_template_decl;
+      expr = convert_like (conv, expr, complain);
+    }
   else
     expr = error_mark_node;
 
diff --git gcc/cp/decl.c gcc/cp/decl.c
index c04b9b7d457..8da63fa2aaa 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -9508,6 +9508,8 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
       else
 	{
 	  size = instantiate_non_dependent_expr_sfinae (size, complain);
+	  /* Don't warn about narrowing for VLAs.  */
+	  warning_sentinel s (warn_narrowing, !TREE_CONSTANT (osize));
 	  size = build_converted_constant_expr (size_type_node, size, complain);
 	  size = maybe_constant_value (size);
 
@@ -9556,7 +9558,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
     {
       tree folded = cp_fully_fold (size);
       if (TREE_CODE (folded) == INTEGER_CST)
-	pedwarn (location_of (size), OPT_Wpedantic,
+	pedwarn (input_location, OPT_Wpedantic,
 		 "size of array is not an integral constant-expression");
       /* Use the folded result for VLAs, too; it will have resolved
 	 SIZEOF_EXPR.  */
diff --git gcc/cp/pt.c gcc/cp/pt.c
index 3780f3492aa..25b71a75c5f 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 	  /* C++17: A template-argument for a non-type template-parameter shall
 	     be a converted constant expression (8.20) of the type of the
 	     template-parameter.  */
+	  int errs = errorcount;
 	  expr = build_converted_constant_expr (type, expr, complain);
 	  if (expr == error_mark_node)
-	    return error_mark_node;
+	    /* Make sure we return NULL_TREE only if we have really issued
+	       an error, as described above.  */
+	    return errorcount > errs ? NULL_TREE : error_mark_node;
 	  expr = maybe_constant_value (expr);
 	  expr = convert_from_reference (expr);
 	}
diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index 91aa5a62856..d82e3b608da 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -875,7 +875,8 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
 }
 
 
-/* Give diagnostic about narrowing conversions within { }.  */
+/* Give diagnostic about narrowing conversions within { }, or as part of
+   a converted constant expression.  */
 
 bool
 check_narrowing (tree type, tree init, tsubst_flags_t complain)
@@ -967,7 +968,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	{
 	  if (complain & tf_warning)
 	    warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
-			"from %qH to %qI inside { } is ill-formed in C++11",
+			"from %qH to %qI is ill-formed in C++11",
 			init, ftype, type);
 	  ok = true;
 	}
@@ -977,8 +978,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	    {
 	      if ((!almost_ok || pedantic)
 		  && pedwarn (loc, OPT_Wnarrowing,
-			      "narrowing conversion of %qE "
-			      "from %qH to %qI inside { }",
+			      "narrowing conversion of %qE from %qH to %qI",
 			      init, ftype, type)
 		  && almost_ok)
 		inform (loc, " the expression has a constant value but is not "
@@ -991,8 +991,8 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	  int savederrorcount = errorcount;
 	  global_dc->pedantic_errors = 1;
 	  pedwarn (loc, OPT_Wnarrowing,
-		   "narrowing conversion of %qE from %qH to %qI "
-		   "inside { }", init, ftype, type);
+		   "narrowing conversion of %qE from %qH to %qI ",
+		   init, ftype, type);
 	  if (errorcount == savederrorcount)
 	    ok = true;
 	  global_dc->pedantic_errors = flag_pedantic_errors;
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
index e69de29bb2d..989d277cd00 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
@@ -0,0 +1,8 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+template<unsigned int> struct A {};
+A<-1> a; // { dg-error "narrowing conversion" }
+
+template<signed char> struct B {};
+B<1000> b; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
index e69de29bb2d..099fdfb7d81 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
@@ -0,0 +1,9 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-narrowing" }
+
+template<unsigned int> struct A {};
+A<-1> a;
+
+template<signed char> struct B {};
+B<1000> b; // { dg-warning "overflow" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
index e69de29bb2d..39c924c9c6c 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
@@ -0,0 +1,6 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+struct X { constexpr operator int () { return 1000; } };
+template<signed char> struct C {};
+C<X{}> c; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
index 898102167de..dee5ed82301 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
@@ -43,4 +43,4 @@ extern template struct A3<int, 510>;
 
 // Use.
 A3<int, 1111> a31;
-A3<char, 9999> a32;		// { dg-warning "overflow" }
+A3<char, 9999> a32;		// { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/ext/builtin12.C gcc/testsuite/g++.dg/ext/builtin12.C
index 1d6bb75cd77..489b37777c4 100644
--- gcc/testsuite/g++.dg/ext/builtin12.C
+++ gcc/testsuite/g++.dg/ext/builtin12.C
@@ -5,6 +5,6 @@ template<bool> struct A {};
 
 constexpr int foo()
 {
-  A<__builtin_constant_p(0)> a{};
+  A<__builtin_constant_p(0)> a{}; // { dg-error "narrowing conversion" }
   return 0;
 }
diff --git gcc/testsuite/g++.dg/init/new43.C gcc/testsuite/g++.dg/init/new43.C
index 9b0866720fe..7ab2a36392e 100644
--- gcc/testsuite/g++.dg/init/new43.C
+++ gcc/testsuite/g++.dg/init/new43.C
@@ -31,35 +31,35 @@ void test_literal ()
 
     // Verify integer literal.
     p = new char [-1];           // { dg-error "size of array is negative" }
-    p = new char [2][-3];        // { dg-error "size of array is negative" }
+    p = new char [2][-3];        // { dg-error "size of array is negative|narrowing conversion" }
     p = new char [-4][5];        // { dg-error "size of array is negative" }
-    p = new char [-6][-7];       // { dg-error "size of array is negative" }
+    p = new char [-6][-7];       // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) char [-1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][-3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][-3];    // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) char [-4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [-6][-7];   // { dg-error "size of array is negative" }
+    p = new (p) char [-6][-7];   // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) A [-1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) A [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) A [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) B [-1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (&b) B [-1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (&b) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new char [1 - 2];         // { dg-error "size of array is negative" }
     p = new (p) char [2 - 3];     // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? -1 : -2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 - 3 * 2];    // { dg-error "size of array is negative" }
-    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constant_expression ()
@@ -79,35 +79,35 @@ void test_constant_expression ()
 
     // Verify constant expression.
     p = new char [i1];           // { dg-error "size of array is negative" }
-    p = new char [2][i3];        // { dg-error "size of array is negative" }
+    p = new char [2][i3];        // { dg-error "size of array is|narrowing conversion" }
     p = new char [i4][5];        // { dg-error "size of array is negative" }
-    p = new char [i6][i7];       // { dg-error "size of array is negative" }
+    p = new char [i6][i7];       // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) char [i1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][i3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][i3];    // { dg-error "size of array is|narrowing conversion" }
     p = new (p) char [i4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [i6][i7];   // { dg-error "size of array is negative" }
+    p = new (p) char [i6][i7];   // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) A [i1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (p) A [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) A [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) B [i1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (p) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) B [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new (&b) B [i1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (&b) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new short [i1 - 2];       // { dg-error "size of array is negative" }
     p = new (p) bool [i2 - 3];    // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? i1 : i2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 + i3 * 2];   // { dg-error "size of array is negative" }
-    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constexpr ()
diff --git gcc/testsuite/g++.dg/other/fold1.C gcc/testsuite/g++.dg/other/fold1.C
index 23d34546e0b..bf074038b04 100644
--- gcc/testsuite/g++.dg/other/fold1.C
+++ gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];		     // { dg-error "constant-expression" }
+    int x[i];		     // { dg-error "constant-expression|narrowing conversion" }
 };
diff --git gcc/testsuite/g++.dg/other/vrp1.C gcc/testsuite/g++.dg/other/vrp1.C
index 0a798c9954e..466a15b4cbb 100644
--- gcc/testsuite/g++.dg/other/vrp1.C
+++ gcc/testsuite/g++.dg/other/vrp1.C
@@ -9,4 +9,4 @@ long long mod (long long l, long long r)
     return 0LL;
   return l % r;
 }
-template long long mod<-0x8000000000000000LL> (long long, long long);
+template long long mod<-0x8000000000000000LL> (long long, long long); // { dg-error "template-id" "" { target { c++11 } } }
diff --git gcc/testsuite/g++.dg/parse/array-size2.C gcc/testsuite/g++.dg/parse/array-size2.C
index d0bc47fe746..997b95eed1a 100644
--- gcc/testsuite/g++.dg/parse/array-size2.C
+++ gcc/testsuite/g++.dg/parse/array-size2.C
@@ -14,7 +14,7 @@ extern void bar (char *, char *);
 void
 foo (void)
 {
-  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" }
+  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant|narrowing conversion" }
   char h[(__SIZE_TYPE__) &((struct S *) 8)->b];	      // { dg-error "constant" }
   bar (g, h);
 }
diff --git gcc/testsuite/g++.dg/template/char1.C gcc/testsuite/g++.dg/template/char1.C
index 51e72e7ad06..a6cffaaf024 100644
--- gcc/testsuite/g++.dg/template/char1.C
+++ gcc/testsuite/g++.dg/template/char1.C
@@ -1,4 +1,5 @@
 template <class CharType, CharType line_terminator = 0>
 class String {};
 
-String<signed char, 255> s;		// { dg-warning "overflow" }
+String<signed char, 255> s;		// { dg-error "narrowing conversion" "" { target c++11 } }
+// { dg-warning "overflow" "" { target c++98_only } .-1 }
diff --git gcc/testsuite/g++.dg/template/dependent-name3.C gcc/testsuite/g++.dg/template/dependent-name3.C
index bbe6fb66266..f9d14055a11 100644
--- gcc/testsuite/g++.dg/template/dependent-name3.C
+++ gcc/testsuite/g++.dg/template/dependent-name3.C
@@ -11,7 +11,7 @@ template<int I> struct A
 template<int N> struct B
 {
   int x[A<N>::zero];       // { dg-error "zero" }
-  int y[A<N>::minus_one];  // { dg-error "negative" }
+  int y[A<N>::minus_one];  // { dg-error "size of array|narrowing conversion" }
 };
 
 B<0> b;
Jason Merrill July 3, 2018, 4:40 p.m. UTC | #3
On Fri, Jun 29, 2018 at 3:58 PM, Marek Polacek <polacek@redhat.com> wrote:
> On Wed, Jun 27, 2018 at 07:35:15PM -0400, Jason Merrill wrote:
>> On Wed, Jun 27, 2018 at 12:53 PM, Marek Polacek <polacek@redhat.com> wrote:
>> > This PR complains about us accepting invalid code like
>> >
>> >   template<unsigned int> struct A {};
>> >   A<-1> a;
>> >
>> > Where we should detect the narrowing: [temp.arg.nontype] says
>> > "A template-argument for a non-type template-parameter shall be a converted
>> > constant expression ([expr.const]) of the type of the template-parameter."
>> > and a converted constant expression can contain only
>> > - integral conversions other than narrowing conversions,
>> > - [...]."
>> > It spurred e.g.
>> > <https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
>> > and has >=3 dups so it has some visibility.
>> >
>> > I think build_converted_constant_expr needs to set check_narrowing.
>> > check_narrowing also always mentions that it's in { } but that is no longer
>> > true; in the future it will also apply to <=>.  We'd probably have to add a new
>> > flag to struct conversion if wanted to distinguish between these.
>> >
>> > This does not yet fix detecting narrowing in function templates (78244).
>> >
>> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
>> >
>> > 2018-06-27  Marek Polacek  <polacek@redhat.com>
>> >
>> >         PR c++/57891
>> >         * call.c (build_converted_constant_expr): Set check_narrowing.
>> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
>> >         input_location.
>> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
>> >         were reported.
>> >         * typeck2.c (check_narrowing): Don't mention { } in diagnostic.
>> >
>> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
>> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
>> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
>> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
>> >         * g++.dg/init/new43.C: Adjust dg-error.
>> >         * g++.dg/other/fold1.C: Likewise.
>> >         * g++.dg/parse/array-size2.C: Likewise.
>> >         * g++.dg/other/vrp1.C: Add dg-error.
>> >         * g++.dg/template/char1.C: Likewise.
>> >         * g++.dg/ext/builtin12.C: Likewise.
>> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
>> >
>> > diff --git gcc/cp/call.c gcc/cp/call.c
>> > index 209c1fd2f0e..956c7b149dc 100644
>> > --- gcc/cp/call.c
>> > +++ gcc/cp/call.c
>> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
>> >      }
>> >
>> >    if (conv)
>> > -    expr = convert_like (conv, expr, complain);
>> > +    {
>> > +      conv->check_narrowing = !processing_template_decl;
>>
>> Why !processing_template_decl?  This needs a comment.
>
> Otherwise we'd warn for e.g.
>
> template<int N> struct S { char a[N]; };
> S<1> s;
>
> where compute_array_index_type will try to convert the size of the array (which
> is a template_parm_index of type int when parsing the template) to size_type.
> So I guess I can say that we need to wait for instantiation?

We certainly shouldn't give a narrowing diagnostic about a
value-dependent expression.  It probably makes sense to check that at
the top of check_narrowing, with all the other early exit conditions.
But if we do know the constant value in the template, it's good to
complain then rather than wait for instantiation.

Jason
Marek Polacek July 3, 2018, 6:58 p.m. UTC | #4
On Tue, Jul 03, 2018 at 12:40:51PM -0400, Jason Merrill wrote:
> On Fri, Jun 29, 2018 at 3:58 PM, Marek Polacek <polacek@redhat.com> wrote:
> > On Wed, Jun 27, 2018 at 07:35:15PM -0400, Jason Merrill wrote:
> >> On Wed, Jun 27, 2018 at 12:53 PM, Marek Polacek <polacek@redhat.com> wrote:
> >> > This PR complains about us accepting invalid code like
> >> >
> >> >   template<unsigned int> struct A {};
> >> >   A<-1> a;
> >> >
> >> > Where we should detect the narrowing: [temp.arg.nontype] says
> >> > "A template-argument for a non-type template-parameter shall be a converted
> >> > constant expression ([expr.const]) of the type of the template-parameter."
> >> > and a converted constant expression can contain only
> >> > - integral conversions other than narrowing conversions,
> >> > - [...]."
> >> > It spurred e.g.
> >> > <https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
> >> > and has >=3 dups so it has some visibility.
> >> >
> >> > I think build_converted_constant_expr needs to set check_narrowing.
> >> > check_narrowing also always mentions that it's in { } but that is no longer
> >> > true; in the future it will also apply to <=>.  We'd probably have to add a new
> >> > flag to struct conversion if wanted to distinguish between these.
> >> >
> >> > This does not yet fix detecting narrowing in function templates (78244).
> >> >
> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
> >> >
> >> > 2018-06-27  Marek Polacek  <polacek@redhat.com>
> >> >
> >> >         PR c++/57891
> >> >         * call.c (build_converted_constant_expr): Set check_narrowing.
> >> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
> >> >         input_location.
> >> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
> >> >         were reported.
> >> >         * typeck2.c (check_narrowing): Don't mention { } in diagnostic.
> >> >
> >> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
> >> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
> >> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
> >> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
> >> >         * g++.dg/init/new43.C: Adjust dg-error.
> >> >         * g++.dg/other/fold1.C: Likewise.
> >> >         * g++.dg/parse/array-size2.C: Likewise.
> >> >         * g++.dg/other/vrp1.C: Add dg-error.
> >> >         * g++.dg/template/char1.C: Likewise.
> >> >         * g++.dg/ext/builtin12.C: Likewise.
> >> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
> >> >
> >> > diff --git gcc/cp/call.c gcc/cp/call.c
> >> > index 209c1fd2f0e..956c7b149dc 100644
> >> > --- gcc/cp/call.c
> >> > +++ gcc/cp/call.c
> >> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
> >> >      }
> >> >
> >> >    if (conv)
> >> > -    expr = convert_like (conv, expr, complain);
> >> > +    {
> >> > +      conv->check_narrowing = !processing_template_decl;
> >>
> >> Why !processing_template_decl?  This needs a comment.
> >
> > Otherwise we'd warn for e.g.
> >
> > template<int N> struct S { char a[N]; };
> > S<1> s;
> >
> > where compute_array_index_type will try to convert the size of the array (which
> > is a template_parm_index of type int when parsing the template) to size_type.
> > So I guess I can say that we need to wait for instantiation?
> 
> We certainly shouldn't give a narrowing diagnostic about a
> value-dependent expression.  It probably makes sense to check that at
> the top of check_narrowing, with all the other early exit conditions.
> But if we do know the constant value in the template, it's good to
> complain then rather than wait for instantiation.

Makes sense; how about this then?  (Regtest/bootstrap running.)

2018-07-03  Marek Polacek  <polacek@redhat.com>

	PR c++/57891
	* call.c (build_converted_constant_expr): Set check_narrowing.
	* decl.c (compute_array_index_type): Add warning sentinel.  Use
	input_location.
	* pt.c (convert_nontype_argument): Return NULL_TREE if any errors
	were reported.
	* typeck2.c (check_narrowing): Don't warn for instantiation-dependent
	expressions or non-constants in a template.  Don't mention { } in
	diagnostic.

	* g++.dg/cpp0x/Wnarrowing6.C: New test.
	* g++.dg/cpp0x/Wnarrowing7.C: New test.
	* g++.dg/cpp0x/Wnarrowing8.C: New test.
	* g++.dg/cpp0x/Wnarrowing9.C: New test.
	* g++.dg/cpp0x/Wnarrowing10.C: New test.
	* g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
	* g++.dg/init/new43.C: Adjust dg-error.
	* g++.dg/other/fold1.C: Likewise.
	* g++.dg/parse/array-size2.C: Likewise.
	* g++.dg/other/vrp1.C: Add dg-error.
	* g++.dg/template/char1.C: Likewise.
	* g++.dg/ext/builtin12.C: Likewise.
	* g++.dg/template/dependent-name3.C: Adjust dg-error.

diff --git gcc/cp/call.c gcc/cp/call.c
index 209c1fd2f0e..4fb0fa8774b 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
     }
 
   if (conv)
-    expr = convert_like (conv, expr, complain);
+    {
+      conv->check_narrowing = true;
+      expr = convert_like (conv, expr, complain);
+    }
   else
     expr = error_mark_node;
 
diff --git gcc/cp/decl.c gcc/cp/decl.c
index c04b9b7d457..8da63fa2aaa 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -9508,6 +9508,8 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
       else
 	{
 	  size = instantiate_non_dependent_expr_sfinae (size, complain);
+	  /* Don't warn about narrowing for VLAs.  */
+	  warning_sentinel s (warn_narrowing, !TREE_CONSTANT (osize));
 	  size = build_converted_constant_expr (size_type_node, size, complain);
 	  size = maybe_constant_value (size);
 
@@ -9556,7 +9558,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
     {
       tree folded = cp_fully_fold (size);
       if (TREE_CODE (folded) == INTEGER_CST)
-	pedwarn (location_of (size), OPT_Wpedantic,
+	pedwarn (input_location, OPT_Wpedantic,
 		 "size of array is not an integral constant-expression");
       /* Use the folded result for VLAs, too; it will have resolved
 	 SIZEOF_EXPR.  */
diff --git gcc/cp/pt.c gcc/cp/pt.c
index 3780f3492aa..25b71a75c5f 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 	  /* C++17: A template-argument for a non-type template-parameter shall
 	     be a converted constant expression (8.20) of the type of the
 	     template-parameter.  */
+	  int errs = errorcount;
 	  expr = build_converted_constant_expr (type, expr, complain);
 	  if (expr == error_mark_node)
-	    return error_mark_node;
+	    /* Make sure we return NULL_TREE only if we have really issued
+	       an error, as described above.  */
+	    return errorcount > errs ? NULL_TREE : error_mark_node;
 	  expr = maybe_constant_value (expr);
 	  expr = convert_from_reference (expr);
 	}
diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index 91aa5a62856..4537ce377c7 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -875,7 +875,8 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
 }
 
 
-/* Give diagnostic about narrowing conversions within { }.  */
+/* Give diagnostic about narrowing conversions within { }, or as part of
+   a converted constant expression.  */
 
 bool
 check_narrowing (tree type, tree init, tsubst_flags_t complain)
@@ -886,7 +887,12 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 
   if (((!warn_narrowing || !(complain & tf_warning))
        && cxx_dialect == cxx98)
-      || !ARITHMETIC_TYPE_P (type))
+      || !ARITHMETIC_TYPE_P (type)
+      /* Don't emit bogus warnings with e.g. value-dependent trees.  */
+      || instantiation_dependent_expression_p (init)
+      /* If we're in a template and we know the constant value, we can
+	 warn.  Otherwise wait for instantiation.  */
+      || (processing_template_decl && !TREE_CONSTANT (init)))
     return ok;
 
   if (BRACE_ENCLOSED_INITIALIZER_P (init)
@@ -967,7 +973,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	{
 	  if (complain & tf_warning)
 	    warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
-			"from %qH to %qI inside { } is ill-formed in C++11",
+			"from %qH to %qI is ill-formed in C++11",
 			init, ftype, type);
 	  ok = true;
 	}
@@ -977,8 +983,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	    {
 	      if ((!almost_ok || pedantic)
 		  && pedwarn (loc, OPT_Wnarrowing,
-			      "narrowing conversion of %qE "
-			      "from %qH to %qI inside { }",
+			      "narrowing conversion of %qE from %qH to %qI",
 			      init, ftype, type)
 		  && almost_ok)
 		inform (loc, " the expression has a constant value but is not "
@@ -991,8 +996,8 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	  int savederrorcount = errorcount;
 	  global_dc->pedantic_errors = 1;
 	  pedwarn (loc, OPT_Wnarrowing,
-		   "narrowing conversion of %qE from %qH to %qI "
-		   "inside { }", init, ftype, type);
+		   "narrowing conversion of %qE from %qH to %qI ",
+		   init, ftype, type);
 	  if (errorcount == savederrorcount)
 	    ok = true;
 	  global_dc->pedantic_errors = flag_pedantic_errors;
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
index e69de29bb2d..8414b53e342 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
@@ -0,0 +1,5 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+template<int N, unsigned char M = N> struct S { char a[N]; };
+S<1000> s; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
index e69de29bb2d..989d277cd00 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
@@ -0,0 +1,8 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+template<unsigned int> struct A {};
+A<-1> a; // { dg-error "narrowing conversion" }
+
+template<signed char> struct B {};
+B<1000> b; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
index e69de29bb2d..099fdfb7d81 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
@@ -0,0 +1,9 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-narrowing" }
+
+template<unsigned int> struct A {};
+A<-1> a;
+
+template<signed char> struct B {};
+B<1000> b; // { dg-warning "overflow" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
index e69de29bb2d..39c924c9c6c 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
@@ -0,0 +1,6 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+struct X { constexpr operator int () { return 1000; } };
+template<signed char> struct C {};
+C<X{}> c; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
index e69de29bb2d..bc8a736ecb9 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
@@ -0,0 +1,6 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+// N is value-dependent, don't warn.
+template<int N> struct S { char a[N]; }; // { dg-bogus "narrowing conversion" }
+S<1> s;
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
index 898102167de..dee5ed82301 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
@@ -43,4 +43,4 @@ extern template struct A3<int, 510>;
 
 // Use.
 A3<int, 1111> a31;
-A3<char, 9999> a32;		// { dg-warning "overflow" }
+A3<char, 9999> a32;		// { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/ext/builtin12.C gcc/testsuite/g++.dg/ext/builtin12.C
index 1d6bb75cd77..489b37777c4 100644
--- gcc/testsuite/g++.dg/ext/builtin12.C
+++ gcc/testsuite/g++.dg/ext/builtin12.C
@@ -5,6 +5,6 @@ template<bool> struct A {};
 
 constexpr int foo()
 {
-  A<__builtin_constant_p(0)> a{};
+  A<__builtin_constant_p(0)> a{}; // { dg-error "narrowing conversion" }
   return 0;
 }
diff --git gcc/testsuite/g++.dg/init/new43.C gcc/testsuite/g++.dg/init/new43.C
index 9b0866720fe..7ab2a36392e 100644
--- gcc/testsuite/g++.dg/init/new43.C
+++ gcc/testsuite/g++.dg/init/new43.C
@@ -31,35 +31,35 @@ void test_literal ()
 
     // Verify integer literal.
     p = new char [-1];           // { dg-error "size of array is negative" }
-    p = new char [2][-3];        // { dg-error "size of array is negative" }
+    p = new char [2][-3];        // { dg-error "size of array is negative|narrowing conversion" }
     p = new char [-4][5];        // { dg-error "size of array is negative" }
-    p = new char [-6][-7];       // { dg-error "size of array is negative" }
+    p = new char [-6][-7];       // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) char [-1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][-3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][-3];    // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) char [-4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [-6][-7];   // { dg-error "size of array is negative" }
+    p = new (p) char [-6][-7];   // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) A [-1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) A [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) A [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) B [-1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (&b) B [-1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (&b) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new char [1 - 2];         // { dg-error "size of array is negative" }
     p = new (p) char [2 - 3];     // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? -1 : -2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 - 3 * 2];    // { dg-error "size of array is negative" }
-    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constant_expression ()
@@ -79,35 +79,35 @@ void test_constant_expression ()
 
     // Verify constant expression.
     p = new char [i1];           // { dg-error "size of array is negative" }
-    p = new char [2][i3];        // { dg-error "size of array is negative" }
+    p = new char [2][i3];        // { dg-error "size of array is|narrowing conversion" }
     p = new char [i4][5];        // { dg-error "size of array is negative" }
-    p = new char [i6][i7];       // { dg-error "size of array is negative" }
+    p = new char [i6][i7];       // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) char [i1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][i3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][i3];    // { dg-error "size of array is|narrowing conversion" }
     p = new (p) char [i4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [i6][i7];   // { dg-error "size of array is negative" }
+    p = new (p) char [i6][i7];   // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) A [i1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (p) A [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) A [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) B [i1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (p) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) B [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new (&b) B [i1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (&b) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new short [i1 - 2];       // { dg-error "size of array is negative" }
     p = new (p) bool [i2 - 3];    // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? i1 : i2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 + i3 * 2];   // { dg-error "size of array is negative" }
-    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constexpr ()
diff --git gcc/testsuite/g++.dg/other/fold1.C gcc/testsuite/g++.dg/other/fold1.C
index 23d34546e0b..bf074038b04 100644
--- gcc/testsuite/g++.dg/other/fold1.C
+++ gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];		     // { dg-error "constant-expression" }
+    int x[i];		     // { dg-error "constant-expression|narrowing conversion" }
 };
diff --git gcc/testsuite/g++.dg/other/vrp1.C gcc/testsuite/g++.dg/other/vrp1.C
index 0a798c9954e..466a15b4cbb 100644
--- gcc/testsuite/g++.dg/other/vrp1.C
+++ gcc/testsuite/g++.dg/other/vrp1.C
@@ -9,4 +9,4 @@ long long mod (long long l, long long r)
     return 0LL;
   return l % r;
 }
-template long long mod<-0x8000000000000000LL> (long long, long long);
+template long long mod<-0x8000000000000000LL> (long long, long long); // { dg-error "template-id" "" { target { c++11 } } }
diff --git gcc/testsuite/g++.dg/parse/array-size2.C gcc/testsuite/g++.dg/parse/array-size2.C
index d0bc47fe746..997b95eed1a 100644
--- gcc/testsuite/g++.dg/parse/array-size2.C
+++ gcc/testsuite/g++.dg/parse/array-size2.C
@@ -14,7 +14,7 @@ extern void bar (char *, char *);
 void
 foo (void)
 {
-  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" }
+  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant|narrowing conversion" }
   char h[(__SIZE_TYPE__) &((struct S *) 8)->b];	      // { dg-error "constant" }
   bar (g, h);
 }
diff --git gcc/testsuite/g++.dg/template/char1.C gcc/testsuite/g++.dg/template/char1.C
index 51e72e7ad06..a6cffaaf024 100644
--- gcc/testsuite/g++.dg/template/char1.C
+++ gcc/testsuite/g++.dg/template/char1.C
@@ -1,4 +1,5 @@
 template <class CharType, CharType line_terminator = 0>
 class String {};
 
-String<signed char, 255> s;		// { dg-warning "overflow" }
+String<signed char, 255> s;		// { dg-error "narrowing conversion" "" { target c++11 } }
+// { dg-warning "overflow" "" { target c++98_only } .-1 }
diff --git gcc/testsuite/g++.dg/template/dependent-name3.C gcc/testsuite/g++.dg/template/dependent-name3.C
index bbe6fb66266..f9d14055a11 100644
--- gcc/testsuite/g++.dg/template/dependent-name3.C
+++ gcc/testsuite/g++.dg/template/dependent-name3.C
@@ -11,7 +11,7 @@ template<int I> struct A
 template<int N> struct B
 {
   int x[A<N>::zero];       // { dg-error "zero" }
-  int y[A<N>::minus_one];  // { dg-error "negative" }
+  int y[A<N>::minus_one];  // { dg-error "size of array|narrowing conversion" }
 };
 
 B<0> b;
Jason Merrill July 3, 2018, 7:41 p.m. UTC | #5
On Tue, Jul 3, 2018 at 2:58 PM, Marek Polacek <polacek@redhat.com> wrote:
> On Tue, Jul 03, 2018 at 12:40:51PM -0400, Jason Merrill wrote:
>> On Fri, Jun 29, 2018 at 3:58 PM, Marek Polacek <polacek@redhat.com> wrote:
>> > On Wed, Jun 27, 2018 at 07:35:15PM -0400, Jason Merrill wrote:
>> >> On Wed, Jun 27, 2018 at 12:53 PM, Marek Polacek <polacek@redhat.com> wrote:
>> >> > This PR complains about us accepting invalid code like
>> >> >
>> >> >   template<unsigned int> struct A {};
>> >> >   A<-1> a;
>> >> >
>> >> > Where we should detect the narrowing: [temp.arg.nontype] says
>> >> > "A template-argument for a non-type template-parameter shall be a converted
>> >> > constant expression ([expr.const]) of the type of the template-parameter."
>> >> > and a converted constant expression can contain only
>> >> > - integral conversions other than narrowing conversions,
>> >> > - [...]."
>> >> > It spurred e.g.
>> >> > <https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
>> >> > and has >=3 dups so it has some visibility.
>> >> >
>> >> > I think build_converted_constant_expr needs to set check_narrowing.
>> >> > check_narrowing also always mentions that it's in { } but that is no longer
>> >> > true; in the future it will also apply to <=>.  We'd probably have to add a new
>> >> > flag to struct conversion if wanted to distinguish between these.
>> >> >
>> >> > This does not yet fix detecting narrowing in function templates (78244).
>> >> >
>> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
>> >> >
>> >> > 2018-06-27  Marek Polacek  <polacek@redhat.com>
>> >> >
>> >> >         PR c++/57891
>> >> >         * call.c (build_converted_constant_expr): Set check_narrowing.
>> >> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
>> >> >         input_location.
>> >> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
>> >> >         were reported.
>> >> >         * typeck2.c (check_narrowing): Don't mention { } in diagnostic.
>> >> >
>> >> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
>> >> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
>> >> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
>> >> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
>> >> >         * g++.dg/init/new43.C: Adjust dg-error.
>> >> >         * g++.dg/other/fold1.C: Likewise.
>> >> >         * g++.dg/parse/array-size2.C: Likewise.
>> >> >         * g++.dg/other/vrp1.C: Add dg-error.
>> >> >         * g++.dg/template/char1.C: Likewise.
>> >> >         * g++.dg/ext/builtin12.C: Likewise.
>> >> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
>> >> >
>> >> > diff --git gcc/cp/call.c gcc/cp/call.c
>> >> > index 209c1fd2f0e..956c7b149dc 100644
>> >> > --- gcc/cp/call.c
>> >> > +++ gcc/cp/call.c
>> >> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
>> >> >      }
>> >> >
>> >> >    if (conv)
>> >> > -    expr = convert_like (conv, expr, complain);
>> >> > +    {
>> >> > +      conv->check_narrowing = !processing_template_decl;
>> >>
>> >> Why !processing_template_decl?  This needs a comment.
>> >
>> > Otherwise we'd warn for e.g.
>> >
>> > template<int N> struct S { char a[N]; };
>> > S<1> s;
>> >
>> > where compute_array_index_type will try to convert the size of the array (which
>> > is a template_parm_index of type int when parsing the template) to size_type.
>> > So I guess I can say that we need to wait for instantiation?
>>
>> We certainly shouldn't give a narrowing diagnostic about a
>> value-dependent expression.  It probably makes sense to check that at
>> the top of check_narrowing, with all the other early exit conditions.
>> But if we do know the constant value in the template, it's good to
>> complain then rather than wait for instantiation.
>
> Makes sense; how about this then?  (Regtest/bootstrap running.)
>
> 2018-07-03  Marek Polacek  <polacek@redhat.com>
>
>         PR c++/57891
>         * call.c (build_converted_constant_expr): Set check_narrowing.
>         * decl.c (compute_array_index_type): Add warning sentinel.  Use
>         input_location.
>         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
>         were reported.
>         * typeck2.c (check_narrowing): Don't warn for instantiation-dependent
>         expressions or non-constants in a template.  Don't mention { } in
>         diagnostic.
>
>         * g++.dg/cpp0x/Wnarrowing6.C: New test.
>         * g++.dg/cpp0x/Wnarrowing7.C: New test.
>         * g++.dg/cpp0x/Wnarrowing8.C: New test.
>         * g++.dg/cpp0x/Wnarrowing9.C: New test.
>         * g++.dg/cpp0x/Wnarrowing10.C: New test.
>         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
>         * g++.dg/init/new43.C: Adjust dg-error.
>         * g++.dg/other/fold1.C: Likewise.
>         * g++.dg/parse/array-size2.C: Likewise.
>         * g++.dg/other/vrp1.C: Add dg-error.
>         * g++.dg/template/char1.C: Likewise.
>         * g++.dg/ext/builtin12.C: Likewise.
>         * g++.dg/template/dependent-name3.C: Adjust dg-error.
>
> diff --git gcc/cp/call.c gcc/cp/call.c
> index 209c1fd2f0e..4fb0fa8774b 100644
> --- gcc/cp/call.c
> +++ gcc/cp/call.c
> @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
>      }
>
>    if (conv)
> -    expr = convert_like (conv, expr, complain);
> +    {
> +      conv->check_narrowing = true;
> +      expr = convert_like (conv, expr, complain);
> +    }
>    else
>      expr = error_mark_node;
>
> diff --git gcc/cp/decl.c gcc/cp/decl.c
> index c04b9b7d457..8da63fa2aaa 100644
> --- gcc/cp/decl.c
> +++ gcc/cp/decl.c
> @@ -9508,6 +9508,8 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
>        else
>         {
>           size = instantiate_non_dependent_expr_sfinae (size, complain);
> +         /* Don't warn about narrowing for VLAs.  */
> +         warning_sentinel s (warn_narrowing, !TREE_CONSTANT (osize));
>           size = build_converted_constant_expr (size_type_node, size, complain);

Hmm, perhaps the underlying issue is that we only want
build_converted_constant_expr to check for narrowing of constant
values; if the value isn't constant, it isn't any kind of constant
expression.  So perhaps the checking needs to happen as part of
constexpr evaluation.

> @@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
>           /* C++17: A template-argument for a non-type template-parameter shall
>              be a converted constant expression (8.20) of the type of the
>              template-parameter.  */
> +         int errs = errorcount;
>           expr = build_converted_constant_expr (type, expr, complain);
>           if (expr == error_mark_node)
> -           return error_mark_node;
> +           /* Make sure we return NULL_TREE only if we have really issued
> +              an error, as described above.  */
> +           return errorcount > errs ? NULL_TREE : error_mark_node;

Is this still needed?

> +      /* If we're in a template and we know the constant value, we can
> +        warn.  Otherwise wait for instantiation.  */
> +      || (processing_template_decl && !TREE_CONSTANT (init)))

I don't think we want this condition.  If the value is non-constant
but also not dependent, it'll never be constant, so we can go ahead
and complain.

Jason
Jason Merrill July 3, 2018, 8:27 p.m. UTC | #6
On Tue, Jul 3, 2018 at 3:41 PM, Jason Merrill <jason@redhat.com> wrote:
> On Tue, Jul 3, 2018 at 2:58 PM, Marek Polacek <polacek@redhat.com> wrote:
>> On Tue, Jul 03, 2018 at 12:40:51PM -0400, Jason Merrill wrote:
>>> On Fri, Jun 29, 2018 at 3:58 PM, Marek Polacek <polacek@redhat.com> wrote:
>>> > On Wed, Jun 27, 2018 at 07:35:15PM -0400, Jason Merrill wrote:
>>> >> On Wed, Jun 27, 2018 at 12:53 PM, Marek Polacek <polacek@redhat.com> wrote:
>>> >> > This PR complains about us accepting invalid code like
>>> >> >
>>> >> >   template<unsigned int> struct A {};
>>> >> >   A<-1> a;
>>> >> >
>>> >> > Where we should detect the narrowing: [temp.arg.nontype] says
>>> >> > "A template-argument for a non-type template-parameter shall be a converted
>>> >> > constant expression ([expr.const]) of the type of the template-parameter."
>>> >> > and a converted constant expression can contain only
>>> >> > - integral conversions other than narrowing conversions,
>>> >> > - [...]."
>>> >> > It spurred e.g.
>>> >> > <https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
>>> >> > and has >=3 dups so it has some visibility.
>>> >> >
>>> >> > I think build_converted_constant_expr needs to set check_narrowing.
>>> >> > check_narrowing also always mentions that it's in { } but that is no longer
>>> >> > true; in the future it will also apply to <=>.  We'd probably have to add a new
>>> >> > flag to struct conversion if wanted to distinguish between these.
>>> >> >
>>> >> > This does not yet fix detecting narrowing in function templates (78244).
>>> >> >
>>> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
>>> >> >
>>> >> > 2018-06-27  Marek Polacek  <polacek@redhat.com>
>>> >> >
>>> >> >         PR c++/57891
>>> >> >         * call.c (build_converted_constant_expr): Set check_narrowing.
>>> >> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
>>> >> >         input_location.
>>> >> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
>>> >> >         were reported.
>>> >> >         * typeck2.c (check_narrowing): Don't mention { } in diagnostic.
>>> >> >
>>> >> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
>>> >> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
>>> >> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
>>> >> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
>>> >> >         * g++.dg/init/new43.C: Adjust dg-error.
>>> >> >         * g++.dg/other/fold1.C: Likewise.
>>> >> >         * g++.dg/parse/array-size2.C: Likewise.
>>> >> >         * g++.dg/other/vrp1.C: Add dg-error.
>>> >> >         * g++.dg/template/char1.C: Likewise.
>>> >> >         * g++.dg/ext/builtin12.C: Likewise.
>>> >> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
>>> >> >
>>> >> > diff --git gcc/cp/call.c gcc/cp/call.c
>>> >> > index 209c1fd2f0e..956c7b149dc 100644
>>> >> > --- gcc/cp/call.c
>>> >> > +++ gcc/cp/call.c
>>> >> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
>>> >> >      }
>>> >> >
>>> >> >    if (conv)
>>> >> > -    expr = convert_like (conv, expr, complain);
>>> >> > +    {
>>> >> > +      conv->check_narrowing = !processing_template_decl;
>>> >>
>>> >> Why !processing_template_decl?  This needs a comment.
>>> >
>>> > Otherwise we'd warn for e.g.
>>> >
>>> > template<int N> struct S { char a[N]; };
>>> > S<1> s;
>>> >
>>> > where compute_array_index_type will try to convert the size of the array (which
>>> > is a template_parm_index of type int when parsing the template) to size_type.
>>> > So I guess I can say that we need to wait for instantiation?
>>>
>>> We certainly shouldn't give a narrowing diagnostic about a
>>> value-dependent expression.  It probably makes sense to check that at
>>> the top of check_narrowing, with all the other early exit conditions.
>>> But if we do know the constant value in the template, it's good to
>>> complain then rather than wait for instantiation.
>>
>> Makes sense; how about this then?  (Regtest/bootstrap running.)
>>
>> 2018-07-03  Marek Polacek  <polacek@redhat.com>
>>
>>         PR c++/57891
>>         * call.c (build_converted_constant_expr): Set check_narrowing.
>>         * decl.c (compute_array_index_type): Add warning sentinel.  Use
>>         input_location.
>>         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
>>         were reported.
>>         * typeck2.c (check_narrowing): Don't warn for instantiation-dependent
>>         expressions or non-constants in a template.  Don't mention { } in
>>         diagnostic.
>>
>>         * g++.dg/cpp0x/Wnarrowing6.C: New test.
>>         * g++.dg/cpp0x/Wnarrowing7.C: New test.
>>         * g++.dg/cpp0x/Wnarrowing8.C: New test.
>>         * g++.dg/cpp0x/Wnarrowing9.C: New test.
>>         * g++.dg/cpp0x/Wnarrowing10.C: New test.
>>         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
>>         * g++.dg/init/new43.C: Adjust dg-error.
>>         * g++.dg/other/fold1.C: Likewise.
>>         * g++.dg/parse/array-size2.C: Likewise.
>>         * g++.dg/other/vrp1.C: Add dg-error.
>>         * g++.dg/template/char1.C: Likewise.
>>         * g++.dg/ext/builtin12.C: Likewise.
>>         * g++.dg/template/dependent-name3.C: Adjust dg-error.
>>
>> diff --git gcc/cp/call.c gcc/cp/call.c
>> index 209c1fd2f0e..4fb0fa8774b 100644
>> --- gcc/cp/call.c
>> +++ gcc/cp/call.c
>> @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
>>      }
>>
>>    if (conv)
>> -    expr = convert_like (conv, expr, complain);
>> +    {
>> +      conv->check_narrowing = true;
>> +      expr = convert_like (conv, expr, complain);
>> +    }
>>    else
>>      expr = error_mark_node;
>>
>> diff --git gcc/cp/decl.c gcc/cp/decl.c
>> index c04b9b7d457..8da63fa2aaa 100644
>> --- gcc/cp/decl.c
>> +++ gcc/cp/decl.c
>> @@ -9508,6 +9508,8 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
>>        else
>>         {
>>           size = instantiate_non_dependent_expr_sfinae (size, complain);
>> +         /* Don't warn about narrowing for VLAs.  */
>> +         warning_sentinel s (warn_narrowing, !TREE_CONSTANT (osize));
>>           size = build_converted_constant_expr (size_type_node, size, complain);
>
> Hmm, perhaps the underlying issue is that we only want
> build_converted_constant_expr to check for narrowing of constant
> values; if the value isn't constant, it isn't any kind of constant
> expression.  So perhaps the checking needs to happen as part of
> constexpr evaluation.

On the other hand, check_narrowing itself forces constexpr evaluation,
so this could be handled all in the conversion code; we just need to
tell check_narrowing to allow non-constant values in that case.

>> @@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
>>           /* C++17: A template-argument for a non-type template-parameter shall
>>              be a converted constant expression (8.20) of the type of the
>>              template-parameter.  */
>> +         int errs = errorcount;
>>           expr = build_converted_constant_expr (type, expr, complain);
>>           if (expr == error_mark_node)
>> -           return error_mark_node;
>> +           /* Make sure we return NULL_TREE only if we have really issued
>> +              an error, as described above.  */
>> +           return errorcount > errs ? NULL_TREE : error_mark_node;
>
> Is this still needed?

Earlier you wrote,

> Checking complain doesn't work because that doesn't
> say if we have really issued an error.  If we have not, and we return
> NULL_TREE anyway, we hit this assert:
>  8517       gcc_assert (!(complain & tf_error) || seen_error ());

If (complain & tf_error), we shouldn't see error_mark_node without an
error having been issued.  Why is build_converted_constant_expr
returning error_mark_node without giving an error when (complain &
tf_error)?

>> +      /* If we're in a template and we know the constant value, we can
>> +        warn.  Otherwise wait for instantiation.  */
>> +      || (processing_template_decl && !TREE_CONSTANT (init)))
>
> I don't think we want this condition.  If the value is non-constant
> but also not dependent, it'll never be constant, so we can go ahead
> and complain.
>
> Jason
Marek Polacek July 3, 2018, 8:35 p.m. UTC | #7
On Tue, Jul 03, 2018 at 03:41:43PM -0400, Jason Merrill wrote:
> On Tue, Jul 3, 2018 at 2:58 PM, Marek Polacek <polacek@redhat.com> wrote:
> > On Tue, Jul 03, 2018 at 12:40:51PM -0400, Jason Merrill wrote:
> >> On Fri, Jun 29, 2018 at 3:58 PM, Marek Polacek <polacek@redhat.com> wrote:
> >> > On Wed, Jun 27, 2018 at 07:35:15PM -0400, Jason Merrill wrote:
> >> >> On Wed, Jun 27, 2018 at 12:53 PM, Marek Polacek <polacek@redhat.com> wrote:
> >> >> > This PR complains about us accepting invalid code like
> >> >> >
> >> >> >   template<unsigned int> struct A {};
> >> >> >   A<-1> a;
> >> >> >
> >> >> > Where we should detect the narrowing: [temp.arg.nontype] says
> >> >> > "A template-argument for a non-type template-parameter shall be a converted
> >> >> > constant expression ([expr.const]) of the type of the template-parameter."
> >> >> > and a converted constant expression can contain only
> >> >> > - integral conversions other than narrowing conversions,
> >> >> > - [...]."
> >> >> > It spurred e.g.
> >> >> > <https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
> >> >> > and has >=3 dups so it has some visibility.
> >> >> >
> >> >> > I think build_converted_constant_expr needs to set check_narrowing.
> >> >> > check_narrowing also always mentions that it's in { } but that is no longer
> >> >> > true; in the future it will also apply to <=>.  We'd probably have to add a new
> >> >> > flag to struct conversion if wanted to distinguish between these.
> >> >> >
> >> >> > This does not yet fix detecting narrowing in function templates (78244).
> >> >> >
> >> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
> >> >> >
> >> >> > 2018-06-27  Marek Polacek  <polacek@redhat.com>
> >> >> >
> >> >> >         PR c++/57891
> >> >> >         * call.c (build_converted_constant_expr): Set check_narrowing.
> >> >> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
> >> >> >         input_location.
> >> >> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
> >> >> >         were reported.
> >> >> >         * typeck2.c (check_narrowing): Don't mention { } in diagnostic.
> >> >> >
> >> >> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
> >> >> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
> >> >> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
> >> >> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
> >> >> >         * g++.dg/init/new43.C: Adjust dg-error.
> >> >> >         * g++.dg/other/fold1.C: Likewise.
> >> >> >         * g++.dg/parse/array-size2.C: Likewise.
> >> >> >         * g++.dg/other/vrp1.C: Add dg-error.
> >> >> >         * g++.dg/template/char1.C: Likewise.
> >> >> >         * g++.dg/ext/builtin12.C: Likewise.
> >> >> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
> >> >> >
> >> >> > diff --git gcc/cp/call.c gcc/cp/call.c
> >> >> > index 209c1fd2f0e..956c7b149dc 100644
> >> >> > --- gcc/cp/call.c
> >> >> > +++ gcc/cp/call.c
> >> >> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
> >> >> >      }
> >> >> >
> >> >> >    if (conv)
> >> >> > -    expr = convert_like (conv, expr, complain);
> >> >> > +    {
> >> >> > +      conv->check_narrowing = !processing_template_decl;
> >> >>
> >> >> Why !processing_template_decl?  This needs a comment.
> >> >
> >> > Otherwise we'd warn for e.g.
> >> >
> >> > template<int N> struct S { char a[N]; };
> >> > S<1> s;
> >> >
> >> > where compute_array_index_type will try to convert the size of the array (which
> >> > is a template_parm_index of type int when parsing the template) to size_type.
> >> > So I guess I can say that we need to wait for instantiation?
> >>
> >> We certainly shouldn't give a narrowing diagnostic about a
> >> value-dependent expression.  It probably makes sense to check that at
> >> the top of check_narrowing, with all the other early exit conditions.
> >> But if we do know the constant value in the template, it's good to
> >> complain then rather than wait for instantiation.
> >
> > Makes sense; how about this then?  (Regtest/bootstrap running.)
> >
> > 2018-07-03  Marek Polacek  <polacek@redhat.com>
> >
> >         PR c++/57891
> >         * call.c (build_converted_constant_expr): Set check_narrowing.
> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
> >         input_location.
> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
> >         were reported.
> >         * typeck2.c (check_narrowing): Don't warn for instantiation-dependent
> >         expressions or non-constants in a template.  Don't mention { } in
> >         diagnostic.
> >
> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
> >         * g++.dg/cpp0x/Wnarrowing9.C: New test.
> >         * g++.dg/cpp0x/Wnarrowing10.C: New test.
> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
> >         * g++.dg/init/new43.C: Adjust dg-error.
> >         * g++.dg/other/fold1.C: Likewise.
> >         * g++.dg/parse/array-size2.C: Likewise.
> >         * g++.dg/other/vrp1.C: Add dg-error.
> >         * g++.dg/template/char1.C: Likewise.
> >         * g++.dg/ext/builtin12.C: Likewise.
> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
> >
> > diff --git gcc/cp/call.c gcc/cp/call.c
> > index 209c1fd2f0e..4fb0fa8774b 100644
> > --- gcc/cp/call.c
> > +++ gcc/cp/call.c
> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
> >      }
> >
> >    if (conv)
> > -    expr = convert_like (conv, expr, complain);
> > +    {
> > +      conv->check_narrowing = true;
> > +      expr = convert_like (conv, expr, complain);
> > +    }
> >    else
> >      expr = error_mark_node;
> >
> > diff --git gcc/cp/decl.c gcc/cp/decl.c
> > index c04b9b7d457..8da63fa2aaa 100644
> > --- gcc/cp/decl.c
> > +++ gcc/cp/decl.c
> > @@ -9508,6 +9508,8 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
> >        else
> >         {
> >           size = instantiate_non_dependent_expr_sfinae (size, complain);
> > +         /* Don't warn about narrowing for VLAs.  */
> > +         warning_sentinel s (warn_narrowing, !TREE_CONSTANT (osize));
> >           size = build_converted_constant_expr (size_type_node, size, complain);
> 
> Hmm, perhaps the underlying issue is that we only want
> build_converted_constant_expr to check for narrowing of constant
> values; if the value isn't constant, it isn't any kind of constant
> expression.  So perhaps the checking needs to happen as part of
> constexpr evaluation.

Not quite sure if I follow.  My very first attempt was to call check_narrowing
in build_converted_constant_expr but that then doesn't detect narrowing in
Wnarrowing8.C with user-defined conversion represented as a TARGET_EXPR that
is not TREE_CONSTANT.

I think I even tried putting check_narrowing to constexpr evaluation but
that was I think too late in that the expression had already been evaluated
and converted and the narrowing conversion was lost.

> > @@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
> >           /* C++17: A template-argument for a non-type template-parameter shall
> >              be a converted constant expression (8.20) of the type of the
> >              template-parameter.  */
> > +         int errs = errorcount;
> >           expr = build_converted_constant_expr (type, expr, complain);
> >           if (expr == error_mark_node)
> > -           return error_mark_node;
> > +           /* Make sure we return NULL_TREE only if we have really issued
> > +              an error, as described above.  */
> > +           return errorcount > errs ? NULL_TREE : error_mark_node;
> 
> Is this still needed?

With the current patch it is, to avoid redundant errors.

> > +      /* If we're in a template and we know the constant value, we can
> > +        warn.  Otherwise wait for instantiation.  */
> > +      || (processing_template_decl && !TREE_CONSTANT (init)))
> 
> I don't think we want this condition.  If the value is non-constant
> but also not dependent, it'll never be constant, so we can go ahead
> and complain.

That was because of constexpr-ex4.C with a VLA in a class template.
check_narrowing gets a VAR_DECL 'a' and fold_non_dependent_expr-ing it
fails with
error: no matching function for call to ‘A::operator int(const A*)’
I didn't think tweaking 'complain' was the way to go.

	Marek
Jason Merrill July 3, 2018, 8:47 p.m. UTC | #8
On Tue, Jul 3, 2018 at 4:35 PM, Marek Polacek <polacek@redhat.com> wrote:
> On Tue, Jul 03, 2018 at 03:41:43PM -0400, Jason Merrill wrote:
>> On Tue, Jul 3, 2018 at 2:58 PM, Marek Polacek <polacek@redhat.com> wrote:
>> > On Tue, Jul 03, 2018 at 12:40:51PM -0400, Jason Merrill wrote:
>> >> On Fri, Jun 29, 2018 at 3:58 PM, Marek Polacek <polacek@redhat.com> wrote:
>> >> > On Wed, Jun 27, 2018 at 07:35:15PM -0400, Jason Merrill wrote:
>> >> >> On Wed, Jun 27, 2018 at 12:53 PM, Marek Polacek <polacek@redhat.com> wrote:
>> >> >> > This PR complains about us accepting invalid code like
>> >> >> >
>> >> >> >   template<unsigned int> struct A {};
>> >> >> >   A<-1> a;
>> >> >> >
>> >> >> > Where we should detect the narrowing: [temp.arg.nontype] says
>> >> >> > "A template-argument for a non-type template-parameter shall be a converted
>> >> >> > constant expression ([expr.const]) of the type of the template-parameter."
>> >> >> > and a converted constant expression can contain only
>> >> >> > - integral conversions other than narrowing conversions,
>> >> >> > - [...]."
>> >> >> > It spurred e.g.
>> >> >> > <https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
>> >> >> > and has >=3 dups so it has some visibility.
>> >> >> >
>> >> >> > I think build_converted_constant_expr needs to set check_narrowing.
>> >> >> > check_narrowing also always mentions that it's in { } but that is no longer
>> >> >> > true; in the future it will also apply to <=>.  We'd probably have to add a new
>> >> >> > flag to struct conversion if wanted to distinguish between these.
>> >> >> >
>> >> >> > This does not yet fix detecting narrowing in function templates (78244).
>> >> >> >
>> >> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
>> >> >> >
>> >> >> > 2018-06-27  Marek Polacek  <polacek@redhat.com>
>> >> >> >
>> >> >> >         PR c++/57891
>> >> >> >         * call.c (build_converted_constant_expr): Set check_narrowing.
>> >> >> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
>> >> >> >         input_location.
>> >> >> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
>> >> >> >         were reported.
>> >> >> >         * typeck2.c (check_narrowing): Don't mention { } in diagnostic.
>> >> >> >
>> >> >> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
>> >> >> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
>> >> >> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
>> >> >> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
>> >> >> >         * g++.dg/init/new43.C: Adjust dg-error.
>> >> >> >         * g++.dg/other/fold1.C: Likewise.
>> >> >> >         * g++.dg/parse/array-size2.C: Likewise.
>> >> >> >         * g++.dg/other/vrp1.C: Add dg-error.
>> >> >> >         * g++.dg/template/char1.C: Likewise.
>> >> >> >         * g++.dg/ext/builtin12.C: Likewise.
>> >> >> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
>> >> >> >
>> >> >> > diff --git gcc/cp/call.c gcc/cp/call.c
>> >> >> > index 209c1fd2f0e..956c7b149dc 100644
>> >> >> > --- gcc/cp/call.c
>> >> >> > +++ gcc/cp/call.c
>> >> >> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
>> >> >> >      }
>> >> >> >
>> >> >> >    if (conv)
>> >> >> > -    expr = convert_like (conv, expr, complain);
>> >> >> > +    {
>> >> >> > +      conv->check_narrowing = !processing_template_decl;
>> >> >>
>> >> >> Why !processing_template_decl?  This needs a comment.
>> >> >
>> >> > Otherwise we'd warn for e.g.
>> >> >
>> >> > template<int N> struct S { char a[N]; };
>> >> > S<1> s;
>> >> >
>> >> > where compute_array_index_type will try to convert the size of the array (which
>> >> > is a template_parm_index of type int when parsing the template) to size_type.
>> >> > So I guess I can say that we need to wait for instantiation?
>> >>
>> >> We certainly shouldn't give a narrowing diagnostic about a
>> >> value-dependent expression.  It probably makes sense to check that at
>> >> the top of check_narrowing, with all the other early exit conditions.
>> >> But if we do know the constant value in the template, it's good to
>> >> complain then rather than wait for instantiation.
>> >
>> > Makes sense; how about this then?  (Regtest/bootstrap running.)
>> >
>> > 2018-07-03  Marek Polacek  <polacek@redhat.com>
>> >
>> >         PR c++/57891
>> >         * call.c (build_converted_constant_expr): Set check_narrowing.
>> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
>> >         input_location.
>> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
>> >         were reported.
>> >         * typeck2.c (check_narrowing): Don't warn for instantiation-dependent
>> >         expressions or non-constants in a template.  Don't mention { } in
>> >         diagnostic.
>> >
>> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
>> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
>> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
>> >         * g++.dg/cpp0x/Wnarrowing9.C: New test.
>> >         * g++.dg/cpp0x/Wnarrowing10.C: New test.
>> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
>> >         * g++.dg/init/new43.C: Adjust dg-error.
>> >         * g++.dg/other/fold1.C: Likewise.
>> >         * g++.dg/parse/array-size2.C: Likewise.
>> >         * g++.dg/other/vrp1.C: Add dg-error.
>> >         * g++.dg/template/char1.C: Likewise.
>> >         * g++.dg/ext/builtin12.C: Likewise.
>> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
>> >
>> > diff --git gcc/cp/call.c gcc/cp/call.c
>> > index 209c1fd2f0e..4fb0fa8774b 100644
>> > --- gcc/cp/call.c
>> > +++ gcc/cp/call.c
>> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
>> >      }
>> >
>> >    if (conv)
>> > -    expr = convert_like (conv, expr, complain);
>> > +    {
>> > +      conv->check_narrowing = true;
>> > +      expr = convert_like (conv, expr, complain);
>> > +    }
>> >    else
>> >      expr = error_mark_node;
>> >
>> > diff --git gcc/cp/decl.c gcc/cp/decl.c
>> > index c04b9b7d457..8da63fa2aaa 100644
>> > --- gcc/cp/decl.c
>> > +++ gcc/cp/decl.c
>> > @@ -9508,6 +9508,8 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
>> >        else
>> >         {
>> >           size = instantiate_non_dependent_expr_sfinae (size, complain);
>> > +         /* Don't warn about narrowing for VLAs.  */
>> > +         warning_sentinel s (warn_narrowing, !TREE_CONSTANT (osize));
>> >           size = build_converted_constant_expr (size_type_node, size, complain);
>>
>> Hmm, perhaps the underlying issue is that we only want
>> build_converted_constant_expr to check for narrowing of constant
>> values; if the value isn't constant, it isn't any kind of constant
>> expression.  So perhaps the checking needs to happen as part of
>> constexpr evaluation.
>
> Not quite sure if I follow.  My very first attempt was to call check_narrowing
> in build_converted_constant_expr but that then doesn't detect narrowing in
> Wnarrowing8.C with user-defined conversion represented as a TARGET_EXPR that
> is not TREE_CONSTANT.
>
> I think I even tried putting check_narrowing to constexpr evaluation but
> that was I think too late in that the expression had already been evaluated
> and converted and the narrowing conversion was lost.

See my email after that one.

>> > @@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
>> >           /* C++17: A template-argument for a non-type template-parameter shall
>> >              be a converted constant expression (8.20) of the type of the
>> >              template-parameter.  */
>> > +         int errs = errorcount;
>> >           expr = build_converted_constant_expr (type, expr, complain);
>> >           if (expr == error_mark_node)
>> > -           return error_mark_node;
>> > +           /* Make sure we return NULL_TREE only if we have really issued
>> > +              an error, as described above.  */
>> > +           return errorcount > errs ? NULL_TREE : error_mark_node;
>>
>> Is this still needed?
>
> With the current patch it is, to avoid redundant errors.

Likewise.

>> > +      /* If we're in a template and we know the constant value, we can
>> > +        warn.  Otherwise wait for instantiation.  */
>> > +      || (processing_template_decl && !TREE_CONSTANT (init)))
>>
>> I don't think we want this condition.  If the value is non-constant
>> but also not dependent, it'll never be constant, so we can go ahead
>> and complain.
>
> That was because of constexpr-ex4.C with a VLA in a class template.
> check_narrowing gets a VAR_DECL 'a' and fold_non_dependent_expr-ing it
> fails with
> error: no matching function for call to ‘A::operator int(const A*)’
> I didn't think tweaking 'complain' was the way to go.

Hmm, that's surprising, I would expect that to work fine.  I guess
this would be OK as a workaround, but I'd like to understand why that
would give a wrong error like that.

Jason
Marek Polacek July 23, 2018, 8:49 p.m. UTC | #9
On Tue, Jul 03, 2018 at 04:27:33PM -0400, Jason Merrill wrote:
> On Tue, Jul 3, 2018 at 3:41 PM, Jason Merrill <jason@redhat.com> wrote:
> > On Tue, Jul 3, 2018 at 2:58 PM, Marek Polacek <polacek@redhat.com> wrote:
> >> On Tue, Jul 03, 2018 at 12:40:51PM -0400, Jason Merrill wrote:
> >>> On Fri, Jun 29, 2018 at 3:58 PM, Marek Polacek <polacek@redhat.com> wrote:
> >>> > On Wed, Jun 27, 2018 at 07:35:15PM -0400, Jason Merrill wrote:
> >>> >> On Wed, Jun 27, 2018 at 12:53 PM, Marek Polacek <polacek@redhat.com> wrote:
> >>> >> > This PR complains about us accepting invalid code like
> >>> >> >
> >>> >> >   template<unsigned int> struct A {};
> >>> >> >   A<-1> a;
> >>> >> >
> >>> >> > Where we should detect the narrowing: [temp.arg.nontype] says
> >>> >> > "A template-argument for a non-type template-parameter shall be a converted
> >>> >> > constant expression ([expr.const]) of the type of the template-parameter."
> >>> >> > and a converted constant expression can contain only
> >>> >> > - integral conversions other than narrowing conversions,
> >>> >> > - [...]."
> >>> >> > It spurred e.g.
> >>> >> > <https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
> >>> >> > and has >=3 dups so it has some visibility.
> >>> >> >
> >>> >> > I think build_converted_constant_expr needs to set check_narrowing.
> >>> >> > check_narrowing also always mentions that it's in { } but that is no longer
> >>> >> > true; in the future it will also apply to <=>.  We'd probably have to add a new
> >>> >> > flag to struct conversion if wanted to distinguish between these.
> >>> >> >
> >>> >> > This does not yet fix detecting narrowing in function templates (78244).
> >>> >> >
> >>> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
> >>> >> >
> >>> >> > 2018-06-27  Marek Polacek  <polacek@redhat.com>
> >>> >> >
> >>> >> >         PR c++/57891
> >>> >> >         * call.c (build_converted_constant_expr): Set check_narrowing.
> >>> >> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
> >>> >> >         input_location.
> >>> >> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
> >>> >> >         were reported.
> >>> >> >         * typeck2.c (check_narrowing): Don't mention { } in diagnostic.
> >>> >> >
> >>> >> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
> >>> >> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
> >>> >> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
> >>> >> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
> >>> >> >         * g++.dg/init/new43.C: Adjust dg-error.
> >>> >> >         * g++.dg/other/fold1.C: Likewise.
> >>> >> >         * g++.dg/parse/array-size2.C: Likewise.
> >>> >> >         * g++.dg/other/vrp1.C: Add dg-error.
> >>> >> >         * g++.dg/template/char1.C: Likewise.
> >>> >> >         * g++.dg/ext/builtin12.C: Likewise.
> >>> >> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
> >>> >> >
> >>> >> > diff --git gcc/cp/call.c gcc/cp/call.c
> >>> >> > index 209c1fd2f0e..956c7b149dc 100644
> >>> >> > --- gcc/cp/call.c
> >>> >> > +++ gcc/cp/call.c
> >>> >> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
> >>> >> >      }
> >>> >> >
> >>> >> >    if (conv)
> >>> >> > -    expr = convert_like (conv, expr, complain);
> >>> >> > +    {
> >>> >> > +      conv->check_narrowing = !processing_template_decl;
> >>> >>
> >>> >> Why !processing_template_decl?  This needs a comment.
> >>> >
> >>> > Otherwise we'd warn for e.g.
> >>> >
> >>> > template<int N> struct S { char a[N]; };
> >>> > S<1> s;
> >>> >
> >>> > where compute_array_index_type will try to convert the size of the array (which
> >>> > is a template_parm_index of type int when parsing the template) to size_type.
> >>> > So I guess I can say that we need to wait for instantiation?
> >>>
> >>> We certainly shouldn't give a narrowing diagnostic about a
> >>> value-dependent expression.  It probably makes sense to check that at
> >>> the top of check_narrowing, with all the other early exit conditions.
> >>> But if we do know the constant value in the template, it's good to
> >>> complain then rather than wait for instantiation.
> >>
> >> Makes sense; how about this then?  (Regtest/bootstrap running.)
> >>
> >> 2018-07-03  Marek Polacek  <polacek@redhat.com>
> >>
> >>         PR c++/57891
> >>         * call.c (build_converted_constant_expr): Set check_narrowing.
> >>         * decl.c (compute_array_index_type): Add warning sentinel.  Use
> >>         input_location.
> >>         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
> >>         were reported.
> >>         * typeck2.c (check_narrowing): Don't warn for instantiation-dependent
> >>         expressions or non-constants in a template.  Don't mention { } in
> >>         diagnostic.
> >>
> >>         * g++.dg/cpp0x/Wnarrowing6.C: New test.
> >>         * g++.dg/cpp0x/Wnarrowing7.C: New test.
> >>         * g++.dg/cpp0x/Wnarrowing8.C: New test.
> >>         * g++.dg/cpp0x/Wnarrowing9.C: New test.
> >>         * g++.dg/cpp0x/Wnarrowing10.C: New test.
> >>         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
> >>         * g++.dg/init/new43.C: Adjust dg-error.
> >>         * g++.dg/other/fold1.C: Likewise.
> >>         * g++.dg/parse/array-size2.C: Likewise.
> >>         * g++.dg/other/vrp1.C: Add dg-error.
> >>         * g++.dg/template/char1.C: Likewise.
> >>         * g++.dg/ext/builtin12.C: Likewise.
> >>         * g++.dg/template/dependent-name3.C: Adjust dg-error.
> >>
> >> diff --git gcc/cp/call.c gcc/cp/call.c
> >> index 209c1fd2f0e..4fb0fa8774b 100644
> >> --- gcc/cp/call.c
> >> +++ gcc/cp/call.c
> >> @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
> >>      }
> >>
> >>    if (conv)
> >> -    expr = convert_like (conv, expr, complain);
> >> +    {
> >> +      conv->check_narrowing = true;
> >> +      expr = convert_like (conv, expr, complain);
> >> +    }
> >>    else
> >>      expr = error_mark_node;
> >>
> >> diff --git gcc/cp/decl.c gcc/cp/decl.c
> >> index c04b9b7d457..8da63fa2aaa 100644
> >> --- gcc/cp/decl.c
> >> +++ gcc/cp/decl.c
> >> @@ -9508,6 +9508,8 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
> >>        else
> >>         {
> >>           size = instantiate_non_dependent_expr_sfinae (size, complain);
> >> +         /* Don't warn about narrowing for VLAs.  */
> >> +         warning_sentinel s (warn_narrowing, !TREE_CONSTANT (osize));
> >>           size = build_converted_constant_expr (size_type_node, size, complain);
> >
> > Hmm, perhaps the underlying issue is that we only want
> > build_converted_constant_expr to check for narrowing of constant
> > values; if the value isn't constant, it isn't any kind of constant
> > expression.  So perhaps the checking needs to happen as part of
> > constexpr evaluation.
> 
> On the other hand, check_narrowing itself forces constexpr evaluation,
> so this could be handled all in the conversion code; we just need to
> tell check_narrowing to allow non-constant values in that case.

OK -- see the patch below.  Now, I'm not crazy about adding another bit
to struct conversion, but reusing any of the other bits didn't seem
safe/possible.  Maybe it'll come in handy when dealing with this problem
for function templates.
 
> >> @@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
> >>           /* C++17: A template-argument for a non-type template-parameter shall
> >>              be a converted constant expression (8.20) of the type of the
> >>              template-parameter.  */
> >> +         int errs = errorcount;
> >>           expr = build_converted_constant_expr (type, expr, complain);
> >>           if (expr == error_mark_node)
> >> -           return error_mark_node;
> >> +           /* Make sure we return NULL_TREE only if we have really issued
> >> +              an error, as described above.  */
> >> +           return errorcount > errs ? NULL_TREE : error_mark_node;
> >
> > Is this still needed?
> 
> Earlier you wrote,
> 
> > Checking complain doesn't work because that doesn't
> > say if we have really issued an error.  If we have not, and we return
> > NULL_TREE anyway, we hit this assert:
> >  8517       gcc_assert (!(complain & tf_error) || seen_error ());
> 
> If (complain & tf_error), we shouldn't see error_mark_node without an
> error having been issued.  Why is build_converted_constant_expr
> returning error_mark_node without giving an error when (complain &
> tf_error)?

This can happen on invalid code; e.g. tests nontype13.C and crash87.C.
What happens there is that we're trying to convert a METHOD_TYPE to bool,
which doesn't work: in standard_conversion we go into the 
    else if (tcode == BOOLEAN_TYPE)
block, which returns NULL, implicit_conversion also then returns NULL, yet
no error has been issued.

> >> +      /* If we're in a template and we know the constant value, we can
> >> +        warn.  Otherwise wait for instantiation.  */
> >> +      || (processing_template_decl && !TREE_CONSTANT (init)))
> >
> > I don't think we want this condition.  If the value is non-constant
> > but also not dependent, it'll never be constant, so we can go ahead
> > and complain.

(This to be investigated later.)

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-07-23  Marek Polacek  <polacek@redhat.com>

	PR c++/57891
	* call.c (struct conversion): Add check_narrowing_const_only.
	(build_converted_constant_expr): Set check_narrowing and
	check_narrowing_const_only.
	(convert_like_real): Pass it to check_narrowing.
	* cp-tree.h (check_narrowing): Add a default parameter.
	* decl.c (compute_array_index_type): Use input_location.
	* pt.c (convert_nontype_argument): Return NULL_TREE if any errors
	were reported.
	* typeck2.c (check_narrowing): Don't warn for instantiation-dependent
	expressions or non-constants in a template.  Don't mention { } in
	diagnostic.  Only check narrowing for constants if CONST_ONLY.

	* g++.dg/cpp0x/Wnarrowing6.C: New test.
	* g++.dg/cpp0x/Wnarrowing7.C: New test.
	* g++.dg/cpp0x/Wnarrowing8.C: New test.
	* g++.dg/cpp0x/Wnarrowing9.C: New test.
	* g++.dg/cpp0x/Wnarrowing10.C: New test.
	* g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
	* g++.dg/init/new43.C: Adjust dg-error.
	* g++.dg/other/fold1.C: Likewise.
	* g++.dg/parse/array-size2.C: Likewise.
	* g++.dg/template/dependent-name3.C: Likewise.
	* g++.dg/other/vrp1.C: Add dg-error.
	* g++.dg/template/char1.C: Likewise.

diff --git gcc/cp/call.c gcc/cp/call.c
index 209c1fd2f0e..e612be91070 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -107,6 +107,9 @@ struct conversion {
      binding a reference directly or decaying to a pointer.  */
   BOOL_BITFIELD rvaluedness_matches_p: 1;
   BOOL_BITFIELD check_narrowing: 1;
+  /* Whether check_narrowing should only check TREE_CONSTANTs; used
+     in build_converted_constant_expr.  */
+  BOOL_BITFIELD check_narrowing_const_only: 1;
   /* The type of the expression resulting from the conversion.  */
   tree type;
   union {
@@ -4152,7 +4155,11 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
     }
 
   if (conv)
-    expr = convert_like (conv, expr, complain);
+    {
+      conv->check_narrowing = true;
+      conv->check_narrowing_const_only = true;
+      expr = convert_like (conv, expr, complain);
+    }
   else
     expr = error_mark_node;
 
@@ -7142,7 +7149,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
     }
 
   if (convs->check_narrowing
-      && !check_narrowing (totype, expr, complain))
+      && !check_narrowing (totype, expr, complain,
+			   convs->check_narrowing_const_only))
     return error_mark_node;
 
   warning_sentinel w (warn_zero_as_null_pointer_constant);
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index 0fac7e9892f..656ddbb2150 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -7354,7 +7354,8 @@ extern int abstract_virtuals_error_sfinae	(abstract_class_use, tree, tsubst_flag
 
 extern tree store_init_value			(tree, tree, vec<tree, va_gc>**, int);
 extern tree split_nonconstant_init		(tree, tree);
-extern bool check_narrowing			(tree, tree, tsubst_flags_t);
+extern bool check_narrowing			(tree, tree, tsubst_flags_t,
+						 bool = false);
 extern tree digest_init				(tree, tree, tsubst_flags_t);
 extern tree digest_init_flags			(tree, tree, int, tsubst_flags_t);
 extern tree digest_nsdmi_init		        (tree, tree, tsubst_flags_t);
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 3c1e2ef3698..265acf8984e 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -9581,7 +9581,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
     {
       tree folded = cp_fully_fold (size);
       if (TREE_CODE (folded) == INTEGER_CST)
-	pedwarn (location_of (size), OPT_Wpedantic,
+	pedwarn (input_location, OPT_Wpedantic,
 		 "size of array is not an integral constant-expression");
       /* Use the folded result for VLAs, too; it will have resolved
 	 SIZEOF_EXPR.  */
diff --git gcc/cp/pt.c gcc/cp/pt.c
index 27805040ddb..1c70ec6b182 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -6680,9 +6680,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 	  /* C++17: A template-argument for a non-type template-parameter shall
 	     be a converted constant expression (8.20) of the type of the
 	     template-parameter.  */
+	  int errs = errorcount;
 	  expr = build_converted_constant_expr (type, expr, complain);
 	  if (expr == error_mark_node)
-	    return error_mark_node;
+	    /* Make sure we return NULL_TREE only if we have really issued
+	       an error, as described above.  */
+	    return errorcount > errs ? NULL_TREE : error_mark_node;
 	  expr = maybe_constant_value (expr);
 	  expr = convert_from_reference (expr);
 	}
diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index 91aa5a62856..ba9c49b307e 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -875,10 +875,12 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
 }
 
 
-/* Give diagnostic about narrowing conversions within { }.  */
+/* Give diagnostic about narrowing conversions within { }, or as part of
+   a converted constant expression.  If CONST_ONLY, only check
+   constants.  */
 
 bool
-check_narrowing (tree type, tree init, tsubst_flags_t complain)
+check_narrowing (tree type, tree init, tsubst_flags_t complain, bool const_only)
 {
   tree ftype = unlowered_expr_type (init);
   bool ok = true;
@@ -886,7 +888,12 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 
   if (((!warn_narrowing || !(complain & tf_warning))
        && cxx_dialect == cxx98)
-      || !ARITHMETIC_TYPE_P (type))
+      || !ARITHMETIC_TYPE_P (type)
+      /* Don't emit bogus warnings with e.g. value-dependent trees.  */
+      || instantiation_dependent_expression_p (init)
+      /* If we're in a template and we know the constant value, we can
+	 warn.  Otherwise wait for instantiation.  */
+      || (processing_template_decl && !TREE_CONSTANT (init)))
     return ok;
 
   if (BRACE_ENCLOSED_INITIALIZER_P (init)
@@ -904,6 +911,10 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 
   init = fold_non_dependent_expr (init, complain);
 
+  /* If we were asked to only check constants, return early.  */
+  if (const_only && !TREE_CONSTANT (init))
+    return ok;
+
   if (TREE_CODE (type) == INTEGER_TYPE
       && TREE_CODE (ftype) == REAL_TYPE)
     ok = false;
@@ -967,7 +978,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	{
 	  if (complain & tf_warning)
 	    warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
-			"from %qH to %qI inside { } is ill-formed in C++11",
+			"from %qH to %qI is ill-formed in C++11",
 			init, ftype, type);
 	  ok = true;
 	}
@@ -977,8 +988,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	    {
 	      if ((!almost_ok || pedantic)
 		  && pedwarn (loc, OPT_Wnarrowing,
-			      "narrowing conversion of %qE "
-			      "from %qH to %qI inside { }",
+			      "narrowing conversion of %qE from %qH to %qI",
 			      init, ftype, type)
 		  && almost_ok)
 		inform (loc, " the expression has a constant value but is not "
@@ -991,8 +1001,8 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	  int savederrorcount = errorcount;
 	  global_dc->pedantic_errors = 1;
 	  pedwarn (loc, OPT_Wnarrowing,
-		   "narrowing conversion of %qE from %qH to %qI "
-		   "inside { }", init, ftype, type);
+		   "narrowing conversion of %qE from %qH to %qI ",
+		   init, ftype, type);
 	  if (errorcount == savederrorcount)
 	    ok = true;
 	  global_dc->pedantic_errors = flag_pedantic_errors;
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
index 898102167de..dee5ed82301 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
@@ -43,4 +43,4 @@ extern template struct A3<int, 510>;
 
 // Use.
 A3<int, 1111> a31;
-A3<char, 9999> a32;		// { dg-warning "overflow" }
+A3<char, 9999> a32;		// { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/init/new43.C gcc/testsuite/g++.dg/init/new43.C
index 9b0866720fe..495c2bb01f0 100644
--- gcc/testsuite/g++.dg/init/new43.C
+++ gcc/testsuite/g++.dg/init/new43.C
@@ -31,35 +31,35 @@ void test_literal ()
 
     // Verify integer literal.
     p = new char [-1];           // { dg-error "size of array is negative" }
-    p = new char [2][-3];        // { dg-error "size of array is negative" }
+    p = new char [2][-3];        // { dg-error "size of array is negative|narrowing conversion" }
     p = new char [-4][5];        // { dg-error "size of array is negative" }
-    p = new char [-6][-7];       // { dg-error "size of array is negative" }
+    p = new char [-6][-7];       // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) char [-1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][-3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][-3];    // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) char [-4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [-6][-7];   // { dg-error "size of array is negative" }
+    p = new (p) char [-6][-7];   // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) A [-1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) A [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) A [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) B [-1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (&b) B [-1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (&b) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new char [1 - 2];         // { dg-error "size of array is negative" }
     p = new (p) char [2 - 3];     // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? -1 : -2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 - 3 * 2];    // { dg-error "size of array is negative" }
-    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constant_expression ()
@@ -79,35 +79,35 @@ void test_constant_expression ()
 
     // Verify constant expression.
     p = new char [i1];           // { dg-error "size of array is negative" }
-    p = new char [2][i3];        // { dg-error "size of array is negative" }
+    p = new char [2][i3];        // { dg-error "size of array is|narrowing conversion" }
     p = new char [i4][5];        // { dg-error "size of array is negative" }
-    p = new char [i6][i7];       // { dg-error "size of array is negative" }
+    p = new char [i6][i7];       // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) char [i1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][i3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][i3];    // { dg-error "size of array is|narrowing conversion" }
     p = new (p) char [i4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [i6][i7];   // { dg-error "size of array is negative" }
+    p = new (p) char [i6][i7];   // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) A [i1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (p) A [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) A [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) B [i1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (p) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) B [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new (&b) B [i1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (&b) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new short [i1 - 2];       // { dg-error "size of array is negative" }
     p = new (p) bool [i2 - 3];    // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? i1 : i2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 + i3 * 2];   // { dg-error "size of array is negative" }
-    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constexpr ()
@@ -132,33 +132,33 @@ void test_constexpr ()
 
     // Verify constant expression.
     p = new char [s1];           // { dg-error "size of array is negative" }
-    p = new char [2][s3];        // { dg-error "size of array is negative" }
+    p = new char [2][s3];        // { dg-error "size of array is|narrowing conversion" }
     p = new char [s4][5];        // { dg-error "size of array is negative" }
-    p = new char [s6][s7];       // { dg-error "size of array is negative" }
+    p = new char [s6][s7];       // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) char [s1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][s3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][s3];    // { dg-error "size of array is|narrowing conversion" }
     p = new (p) char [s4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [s6][s7];   // { dg-error "size of array is negative" }
+    p = new (p) char [s6][s7];   // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) A [s1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][s3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][s3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (p) A [s4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [s6][s7];      // { dg-error "size of array is negative" }
+    p = new (p) A [s6][s7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) B [s1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][s3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][s3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (p) B [s4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [s6][s7];      // { dg-error "size of array is negative" }
+    p = new (p) B [s6][s7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new (&b) B [s1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][s3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][s3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (&b) B [s4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [s6][s7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [s6][s7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new int [s1 + s2];           // { dg-error "size of array is negative" }
     p = new (p) long [2 * s3];       // { dg-error "size of array is negative" }
     p = new A [s2 < s1 ? s1 : s2];   // { dg-error "size of array is negative" }
     p = new (p) B [s7 - s2 * 2];     // { dg-error "size of array is negative" }
-    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of array is negative" }
+    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of array is|narrowing conversion" }
 }
diff --git gcc/testsuite/g++.dg/other/fold1.C gcc/testsuite/g++.dg/other/fold1.C
index 23d34546e0b..bf074038b04 100644
--- gcc/testsuite/g++.dg/other/fold1.C
+++ gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];		     // { dg-error "constant-expression" }
+    int x[i];		     // { dg-error "constant-expression|narrowing conversion" }
 };
diff --git gcc/testsuite/g++.dg/other/vrp1.C gcc/testsuite/g++.dg/other/vrp1.C
index 0a798c9954e..466a15b4cbb 100644
--- gcc/testsuite/g++.dg/other/vrp1.C
+++ gcc/testsuite/g++.dg/other/vrp1.C
@@ -9,4 +9,4 @@ long long mod (long long l, long long r)
     return 0LL;
   return l % r;
 }
-template long long mod<-0x8000000000000000LL> (long long, long long);
+template long long mod<-0x8000000000000000LL> (long long, long long); // { dg-error "template-id" "" { target { c++11 } } }
diff --git gcc/testsuite/g++.dg/parse/array-size2.C gcc/testsuite/g++.dg/parse/array-size2.C
index d0bc47fe746..997b95eed1a 100644
--- gcc/testsuite/g++.dg/parse/array-size2.C
+++ gcc/testsuite/g++.dg/parse/array-size2.C
@@ -14,7 +14,7 @@ extern void bar (char *, char *);
 void
 foo (void)
 {
-  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" }
+  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant|narrowing conversion" }
   char h[(__SIZE_TYPE__) &((struct S *) 8)->b];	      // { dg-error "constant" }
   bar (g, h);
 }
diff --git gcc/testsuite/g++.dg/template/char1.C gcc/testsuite/g++.dg/template/char1.C
index 51e72e7ad06..a6cffaaf024 100644
--- gcc/testsuite/g++.dg/template/char1.C
+++ gcc/testsuite/g++.dg/template/char1.C
@@ -1,4 +1,5 @@
 template <class CharType, CharType line_terminator = 0>
 class String {};
 
-String<signed char, 255> s;		// { dg-warning "overflow" }
+String<signed char, 255> s;		// { dg-error "narrowing conversion" "" { target c++11 } }
+// { dg-warning "overflow" "" { target c++98_only } .-1 }
diff --git gcc/testsuite/g++.dg/template/dependent-name3.C gcc/testsuite/g++.dg/template/dependent-name3.C
index bbe6fb66266..f9d14055a11 100644
--- gcc/testsuite/g++.dg/template/dependent-name3.C
+++ gcc/testsuite/g++.dg/template/dependent-name3.C
@@ -11,7 +11,7 @@ template<int I> struct A
 template<int N> struct B
 {
   int x[A<N>::zero];       // { dg-error "zero" }
-  int y[A<N>::minus_one];  // { dg-error "negative" }
+  int y[A<N>::minus_one];  // { dg-error "size of array|narrowing conversion" }
 };
 
 B<0> b;

	Marek
Marek Polacek Aug. 1, 2018, 12:58 p.m. UTC | #10
Ping.

On Mon, Jul 23, 2018 at 04:49:12PM -0400, Marek Polacek wrote:
> On Tue, Jul 03, 2018 at 04:27:33PM -0400, Jason Merrill wrote:
> > On Tue, Jul 3, 2018 at 3:41 PM, Jason Merrill <jason@redhat.com> wrote:
> > > On Tue, Jul 3, 2018 at 2:58 PM, Marek Polacek <polacek@redhat.com> wrote:
> > >> On Tue, Jul 03, 2018 at 12:40:51PM -0400, Jason Merrill wrote:
> > >>> On Fri, Jun 29, 2018 at 3:58 PM, Marek Polacek <polacek@redhat.com> wrote:
> > >>> > On Wed, Jun 27, 2018 at 07:35:15PM -0400, Jason Merrill wrote:
> > >>> >> On Wed, Jun 27, 2018 at 12:53 PM, Marek Polacek <polacek@redhat.com> wrote:
> > >>> >> > This PR complains about us accepting invalid code like
> > >>> >> >
> > >>> >> >   template<unsigned int> struct A {};
> > >>> >> >   A<-1> a;
> > >>> >> >
> > >>> >> > Where we should detect the narrowing: [temp.arg.nontype] says
> > >>> >> > "A template-argument for a non-type template-parameter shall be a converted
> > >>> >> > constant expression ([expr.const]) of the type of the template-parameter."
> > >>> >> > and a converted constant expression can contain only
> > >>> >> > - integral conversions other than narrowing conversions,
> > >>> >> > - [...]."
> > >>> >> > It spurred e.g.
> > >>> >> > <https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
> > >>> >> > and has >=3 dups so it has some visibility.
> > >>> >> >
> > >>> >> > I think build_converted_constant_expr needs to set check_narrowing.
> > >>> >> > check_narrowing also always mentions that it's in { } but that is no longer
> > >>> >> > true; in the future it will also apply to <=>.  We'd probably have to add a new
> > >>> >> > flag to struct conversion if wanted to distinguish between these.
> > >>> >> >
> > >>> >> > This does not yet fix detecting narrowing in function templates (78244).
> > >>> >> >
> > >>> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
> > >>> >> >
> > >>> >> > 2018-06-27  Marek Polacek  <polacek@redhat.com>
> > >>> >> >
> > >>> >> >         PR c++/57891
> > >>> >> >         * call.c (build_converted_constant_expr): Set check_narrowing.
> > >>> >> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
> > >>> >> >         input_location.
> > >>> >> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
> > >>> >> >         were reported.
> > >>> >> >         * typeck2.c (check_narrowing): Don't mention { } in diagnostic.
> > >>> >> >
> > >>> >> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
> > >>> >> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
> > >>> >> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
> > >>> >> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
> > >>> >> >         * g++.dg/init/new43.C: Adjust dg-error.
> > >>> >> >         * g++.dg/other/fold1.C: Likewise.
> > >>> >> >         * g++.dg/parse/array-size2.C: Likewise.
> > >>> >> >         * g++.dg/other/vrp1.C: Add dg-error.
> > >>> >> >         * g++.dg/template/char1.C: Likewise.
> > >>> >> >         * g++.dg/ext/builtin12.C: Likewise.
> > >>> >> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
> > >>> >> >
> > >>> >> > diff --git gcc/cp/call.c gcc/cp/call.c
> > >>> >> > index 209c1fd2f0e..956c7b149dc 100644
> > >>> >> > --- gcc/cp/call.c
> > >>> >> > +++ gcc/cp/call.c
> > >>> >> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
> > >>> >> >      }
> > >>> >> >
> > >>> >> >    if (conv)
> > >>> >> > -    expr = convert_like (conv, expr, complain);
> > >>> >> > +    {
> > >>> >> > +      conv->check_narrowing = !processing_template_decl;
> > >>> >>
> > >>> >> Why !processing_template_decl?  This needs a comment.
> > >>> >
> > >>> > Otherwise we'd warn for e.g.
> > >>> >
> > >>> > template<int N> struct S { char a[N]; };
> > >>> > S<1> s;
> > >>> >
> > >>> > where compute_array_index_type will try to convert the size of the array (which
> > >>> > is a template_parm_index of type int when parsing the template) to size_type.
> > >>> > So I guess I can say that we need to wait for instantiation?
> > >>>
> > >>> We certainly shouldn't give a narrowing diagnostic about a
> > >>> value-dependent expression.  It probably makes sense to check that at
> > >>> the top of check_narrowing, with all the other early exit conditions.
> > >>> But if we do know the constant value in the template, it's good to
> > >>> complain then rather than wait for instantiation.
> > >>
> > >> Makes sense; how about this then?  (Regtest/bootstrap running.)
> > >>
> > >> 2018-07-03  Marek Polacek  <polacek@redhat.com>
> > >>
> > >>         PR c++/57891
> > >>         * call.c (build_converted_constant_expr): Set check_narrowing.
> > >>         * decl.c (compute_array_index_type): Add warning sentinel.  Use
> > >>         input_location.
> > >>         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
> > >>         were reported.
> > >>         * typeck2.c (check_narrowing): Don't warn for instantiation-dependent
> > >>         expressions or non-constants in a template.  Don't mention { } in
> > >>         diagnostic.
> > >>
> > >>         * g++.dg/cpp0x/Wnarrowing6.C: New test.
> > >>         * g++.dg/cpp0x/Wnarrowing7.C: New test.
> > >>         * g++.dg/cpp0x/Wnarrowing8.C: New test.
> > >>         * g++.dg/cpp0x/Wnarrowing9.C: New test.
> > >>         * g++.dg/cpp0x/Wnarrowing10.C: New test.
> > >>         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
> > >>         * g++.dg/init/new43.C: Adjust dg-error.
> > >>         * g++.dg/other/fold1.C: Likewise.
> > >>         * g++.dg/parse/array-size2.C: Likewise.
> > >>         * g++.dg/other/vrp1.C: Add dg-error.
> > >>         * g++.dg/template/char1.C: Likewise.
> > >>         * g++.dg/ext/builtin12.C: Likewise.
> > >>         * g++.dg/template/dependent-name3.C: Adjust dg-error.
> > >>
> > >> diff --git gcc/cp/call.c gcc/cp/call.c
> > >> index 209c1fd2f0e..4fb0fa8774b 100644
> > >> --- gcc/cp/call.c
> > >> +++ gcc/cp/call.c
> > >> @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
> > >>      }
> > >>
> > >>    if (conv)
> > >> -    expr = convert_like (conv, expr, complain);
> > >> +    {
> > >> +      conv->check_narrowing = true;
> > >> +      expr = convert_like (conv, expr, complain);
> > >> +    }
> > >>    else
> > >>      expr = error_mark_node;
> > >>
> > >> diff --git gcc/cp/decl.c gcc/cp/decl.c
> > >> index c04b9b7d457..8da63fa2aaa 100644
> > >> --- gcc/cp/decl.c
> > >> +++ gcc/cp/decl.c
> > >> @@ -9508,6 +9508,8 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
> > >>        else
> > >>         {
> > >>           size = instantiate_non_dependent_expr_sfinae (size, complain);
> > >> +         /* Don't warn about narrowing for VLAs.  */
> > >> +         warning_sentinel s (warn_narrowing, !TREE_CONSTANT (osize));
> > >>           size = build_converted_constant_expr (size_type_node, size, complain);
> > >
> > > Hmm, perhaps the underlying issue is that we only want
> > > build_converted_constant_expr to check for narrowing of constant
> > > values; if the value isn't constant, it isn't any kind of constant
> > > expression.  So perhaps the checking needs to happen as part of
> > > constexpr evaluation.
> > 
> > On the other hand, check_narrowing itself forces constexpr evaluation,
> > so this could be handled all in the conversion code; we just need to
> > tell check_narrowing to allow non-constant values in that case.
> 
> OK -- see the patch below.  Now, I'm not crazy about adding another bit
> to struct conversion, but reusing any of the other bits didn't seem
> safe/possible.  Maybe it'll come in handy when dealing with this problem
> for function templates.
>  
> > >> @@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
> > >>           /* C++17: A template-argument for a non-type template-parameter shall
> > >>              be a converted constant expression (8.20) of the type of the
> > >>              template-parameter.  */
> > >> +         int errs = errorcount;
> > >>           expr = build_converted_constant_expr (type, expr, complain);
> > >>           if (expr == error_mark_node)
> > >> -           return error_mark_node;
> > >> +           /* Make sure we return NULL_TREE only if we have really issued
> > >> +              an error, as described above.  */
> > >> +           return errorcount > errs ? NULL_TREE : error_mark_node;
> > >
> > > Is this still needed?
> > 
> > Earlier you wrote,
> > 
> > > Checking complain doesn't work because that doesn't
> > > say if we have really issued an error.  If we have not, and we return
> > > NULL_TREE anyway, we hit this assert:
> > >  8517       gcc_assert (!(complain & tf_error) || seen_error ());
> > 
> > If (complain & tf_error), we shouldn't see error_mark_node without an
> > error having been issued.  Why is build_converted_constant_expr
> > returning error_mark_node without giving an error when (complain &
> > tf_error)?
> 
> This can happen on invalid code; e.g. tests nontype13.C and crash87.C.
> What happens there is that we're trying to convert a METHOD_TYPE to bool,
> which doesn't work: in standard_conversion we go into the 
>     else if (tcode == BOOLEAN_TYPE)
> block, which returns NULL, implicit_conversion also then returns NULL, yet
> no error has been issued.
> 
> > >> +      /* If we're in a template and we know the constant value, we can
> > >> +        warn.  Otherwise wait for instantiation.  */
> > >> +      || (processing_template_decl && !TREE_CONSTANT (init)))
> > >
> > > I don't think we want this condition.  If the value is non-constant
> > > but also not dependent, it'll never be constant, so we can go ahead
> > > and complain.
> 
> (This to be investigated later.)
> 
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
> 
> 2018-07-23  Marek Polacek  <polacek@redhat.com>
> 
> 	PR c++/57891
> 	* call.c (struct conversion): Add check_narrowing_const_only.
> 	(build_converted_constant_expr): Set check_narrowing and
> 	check_narrowing_const_only.
> 	(convert_like_real): Pass it to check_narrowing.
> 	* cp-tree.h (check_narrowing): Add a default parameter.
> 	* decl.c (compute_array_index_type): Use input_location.
> 	* pt.c (convert_nontype_argument): Return NULL_TREE if any errors
> 	were reported.
> 	* typeck2.c (check_narrowing): Don't warn for instantiation-dependent
> 	expressions or non-constants in a template.  Don't mention { } in
> 	diagnostic.  Only check narrowing for constants if CONST_ONLY.
> 
> 	* g++.dg/cpp0x/Wnarrowing6.C: New test.
> 	* g++.dg/cpp0x/Wnarrowing7.C: New test.
> 	* g++.dg/cpp0x/Wnarrowing8.C: New test.
> 	* g++.dg/cpp0x/Wnarrowing9.C: New test.
> 	* g++.dg/cpp0x/Wnarrowing10.C: New test.
> 	* g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
> 	* g++.dg/init/new43.C: Adjust dg-error.
> 	* g++.dg/other/fold1.C: Likewise.
> 	* g++.dg/parse/array-size2.C: Likewise.
> 	* g++.dg/template/dependent-name3.C: Likewise.
> 	* g++.dg/other/vrp1.C: Add dg-error.
> 	* g++.dg/template/char1.C: Likewise.
> 
> diff --git gcc/cp/call.c gcc/cp/call.c
> index 209c1fd2f0e..e612be91070 100644
> --- gcc/cp/call.c
> +++ gcc/cp/call.c
> @@ -107,6 +107,9 @@ struct conversion {
>       binding a reference directly or decaying to a pointer.  */
>    BOOL_BITFIELD rvaluedness_matches_p: 1;
>    BOOL_BITFIELD check_narrowing: 1;
> +  /* Whether check_narrowing should only check TREE_CONSTANTs; used
> +     in build_converted_constant_expr.  */
> +  BOOL_BITFIELD check_narrowing_const_only: 1;
>    /* The type of the expression resulting from the conversion.  */
>    tree type;
>    union {
> @@ -4152,7 +4155,11 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
>      }
>  
>    if (conv)
> -    expr = convert_like (conv, expr, complain);
> +    {
> +      conv->check_narrowing = true;
> +      conv->check_narrowing_const_only = true;
> +      expr = convert_like (conv, expr, complain);
> +    }
>    else
>      expr = error_mark_node;
>  
> @@ -7142,7 +7149,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
>      }
>  
>    if (convs->check_narrowing
> -      && !check_narrowing (totype, expr, complain))
> +      && !check_narrowing (totype, expr, complain,
> +			   convs->check_narrowing_const_only))
>      return error_mark_node;
>  
>    warning_sentinel w (warn_zero_as_null_pointer_constant);
> diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
> index 0fac7e9892f..656ddbb2150 100644
> --- gcc/cp/cp-tree.h
> +++ gcc/cp/cp-tree.h
> @@ -7354,7 +7354,8 @@ extern int abstract_virtuals_error_sfinae	(abstract_class_use, tree, tsubst_flag
>  
>  extern tree store_init_value			(tree, tree, vec<tree, va_gc>**, int);
>  extern tree split_nonconstant_init		(tree, tree);
> -extern bool check_narrowing			(tree, tree, tsubst_flags_t);
> +extern bool check_narrowing			(tree, tree, tsubst_flags_t,
> +						 bool = false);
>  extern tree digest_init				(tree, tree, tsubst_flags_t);
>  extern tree digest_init_flags			(tree, tree, int, tsubst_flags_t);
>  extern tree digest_nsdmi_init		        (tree, tree, tsubst_flags_t);
> diff --git gcc/cp/decl.c gcc/cp/decl.c
> index 3c1e2ef3698..265acf8984e 100644
> --- gcc/cp/decl.c
> +++ gcc/cp/decl.c
> @@ -9581,7 +9581,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
>      {
>        tree folded = cp_fully_fold (size);
>        if (TREE_CODE (folded) == INTEGER_CST)
> -	pedwarn (location_of (size), OPT_Wpedantic,
> +	pedwarn (input_location, OPT_Wpedantic,
>  		 "size of array is not an integral constant-expression");
>        /* Use the folded result for VLAs, too; it will have resolved
>  	 SIZEOF_EXPR.  */
> diff --git gcc/cp/pt.c gcc/cp/pt.c
> index 27805040ddb..1c70ec6b182 100644
> --- gcc/cp/pt.c
> +++ gcc/cp/pt.c
> @@ -6680,9 +6680,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
>  	  /* C++17: A template-argument for a non-type template-parameter shall
>  	     be a converted constant expression (8.20) of the type of the
>  	     template-parameter.  */
> +	  int errs = errorcount;
>  	  expr = build_converted_constant_expr (type, expr, complain);
>  	  if (expr == error_mark_node)
> -	    return error_mark_node;
> +	    /* Make sure we return NULL_TREE only if we have really issued
> +	       an error, as described above.  */
> +	    return errorcount > errs ? NULL_TREE : error_mark_node;
>  	  expr = maybe_constant_value (expr);
>  	  expr = convert_from_reference (expr);
>  	}
> diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
> index 91aa5a62856..ba9c49b307e 100644
> --- gcc/cp/typeck2.c
> +++ gcc/cp/typeck2.c
> @@ -875,10 +875,12 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
>  }
>  
>  
> -/* Give diagnostic about narrowing conversions within { }.  */
> +/* Give diagnostic about narrowing conversions within { }, or as part of
> +   a converted constant expression.  If CONST_ONLY, only check
> +   constants.  */
>  
>  bool
> -check_narrowing (tree type, tree init, tsubst_flags_t complain)
> +check_narrowing (tree type, tree init, tsubst_flags_t complain, bool const_only)
>  {
>    tree ftype = unlowered_expr_type (init);
>    bool ok = true;
> @@ -886,7 +888,12 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
>  
>    if (((!warn_narrowing || !(complain & tf_warning))
>         && cxx_dialect == cxx98)
> -      || !ARITHMETIC_TYPE_P (type))
> +      || !ARITHMETIC_TYPE_P (type)
> +      /* Don't emit bogus warnings with e.g. value-dependent trees.  */
> +      || instantiation_dependent_expression_p (init)
> +      /* If we're in a template and we know the constant value, we can
> +	 warn.  Otherwise wait for instantiation.  */
> +      || (processing_template_decl && !TREE_CONSTANT (init)))
>      return ok;
>  
>    if (BRACE_ENCLOSED_INITIALIZER_P (init)
> @@ -904,6 +911,10 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
>  
>    init = fold_non_dependent_expr (init, complain);
>  
> +  /* If we were asked to only check constants, return early.  */
> +  if (const_only && !TREE_CONSTANT (init))
> +    return ok;
> +
>    if (TREE_CODE (type) == INTEGER_TYPE
>        && TREE_CODE (ftype) == REAL_TYPE)
>      ok = false;
> @@ -967,7 +978,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
>  	{
>  	  if (complain & tf_warning)
>  	    warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
> -			"from %qH to %qI inside { } is ill-formed in C++11",
> +			"from %qH to %qI is ill-formed in C++11",
>  			init, ftype, type);
>  	  ok = true;
>  	}
> @@ -977,8 +988,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
>  	    {
>  	      if ((!almost_ok || pedantic)
>  		  && pedwarn (loc, OPT_Wnarrowing,
> -			      "narrowing conversion of %qE "
> -			      "from %qH to %qI inside { }",
> +			      "narrowing conversion of %qE from %qH to %qI",
>  			      init, ftype, type)
>  		  && almost_ok)
>  		inform (loc, " the expression has a constant value but is not "
> @@ -991,8 +1001,8 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
>  	  int savederrorcount = errorcount;
>  	  global_dc->pedantic_errors = 1;
>  	  pedwarn (loc, OPT_Wnarrowing,
> -		   "narrowing conversion of %qE from %qH to %qI "
> -		   "inside { }", init, ftype, type);
> +		   "narrowing conversion of %qE from %qH to %qI ",
> +		   init, ftype, type);
>  	  if (errorcount == savederrorcount)
>  	    ok = true;
>  	  global_dc->pedantic_errors = flag_pedantic_errors;
> diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
> index 898102167de..dee5ed82301 100644
> --- gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
> +++ gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
> @@ -43,4 +43,4 @@ extern template struct A3<int, 510>;
>  
>  // Use.
>  A3<int, 1111> a31;
> -A3<char, 9999> a32;		// { dg-warning "overflow" }
> +A3<char, 9999> a32;		// { dg-error "narrowing conversion" }
> diff --git gcc/testsuite/g++.dg/init/new43.C gcc/testsuite/g++.dg/init/new43.C
> index 9b0866720fe..495c2bb01f0 100644
> --- gcc/testsuite/g++.dg/init/new43.C
> +++ gcc/testsuite/g++.dg/init/new43.C
> @@ -31,35 +31,35 @@ void test_literal ()
>  
>      // Verify integer literal.
>      p = new char [-1];           // { dg-error "size of array is negative" }
> -    p = new char [2][-3];        // { dg-error "size of array is negative" }
> +    p = new char [2][-3];        // { dg-error "size of array is negative|narrowing conversion" }
>      p = new char [-4][5];        // { dg-error "size of array is negative" }
> -    p = new char [-6][-7];       // { dg-error "size of array is negative" }
> +    p = new char [-6][-7];       // { dg-error "size of array is negative|narrowing conversion" }
>  
>      p = new (p) char [-1];       // { dg-error "size of array is negative" }
> -    p = new (p) char [2][-3];    // { dg-error "size of array is negative" }
> +    p = new (p) char [2][-3];    // { dg-error "size of array is negative|narrowing conversion" }
>      p = new (p) char [-4][5];    // { dg-error "size of array is negative" }
> -    p = new (p) char [-6][-7];   // { dg-error "size of array is negative" }
> +    p = new (p) char [-6][-7];   // { dg-error "size of array is negative|narrowing conversion" }
>  
>      p = new (p) A [-1];          // { dg-error "size of array is negative" }
> -    p = new (p) A [2][-3];       // { dg-error "size of array is negative" }
> +    p = new (p) A [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
>      p = new (p) A [-4][5];       // { dg-error "size of array is negative" }
> -    p = new (p) A [-6][-7];      // { dg-error "size of array is negative" }
> +    p = new (p) A [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
>  
>      p = new (p) B [-1];          // { dg-error "size of array is negative" }
> -    p = new (p) B [2][-3];       // { dg-error "size of array is negative" }
> +    p = new (p) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
>      p = new (p) B [-4][5];       // { dg-error "size of array is negative" }
> -    p = new (p) B [-6][-7];      // { dg-error "size of array is negative" }
> +    p = new (p) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
>  
>      p = new (&b) B [-1];          // { dg-error "size of array is negative" }
> -    p = new (&b) B [2][-3];       // { dg-error "size of array is negative" }
> +    p = new (&b) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
>      p = new (&b) B [-4][5];       // { dg-error "size of array is negative" }
> -    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative" }
> +    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
>  
>      p = new char [1 - 2];         // { dg-error "size of array is negative" }
>      p = new (p) char [2 - 3];     // { dg-error "size of array is negative" }
>      p = new A [2 < 1 ? -1 : -2];  // { dg-error "size of array is negative" }
>      p = new (p) B [2 - 3 * 2];    // { dg-error "size of array is negative" }
> -    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array is negative" }
> +    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
>  }
>  
>  void test_constant_expression ()
> @@ -79,35 +79,35 @@ void test_constant_expression ()
>  
>      // Verify constant expression.
>      p = new char [i1];           // { dg-error "size of array is negative" }
> -    p = new char [2][i3];        // { dg-error "size of array is negative" }
> +    p = new char [2][i3];        // { dg-error "size of array is|narrowing conversion" }
>      p = new char [i4][5];        // { dg-error "size of array is negative" }
> -    p = new char [i6][i7];       // { dg-error "size of array is negative" }
> +    p = new char [i6][i7];       // { dg-error "size of array is|narrowing conversion" }
>  
>      p = new (p) char [i1];       // { dg-error "size of array is negative" }
> -    p = new (p) char [2][i3];    // { dg-error "size of array is negative" }
> +    p = new (p) char [2][i3];    // { dg-error "size of array is|narrowing conversion" }
>      p = new (p) char [i4][5];    // { dg-error "size of array is negative" }
> -    p = new (p) char [i6][i7];   // { dg-error "size of array is negative" }
> +    p = new (p) char [i6][i7];   // { dg-error "size of array is|narrowing conversion" }
>  
>      p = new (p) A [i1];          // { dg-error "size of array is negative" }
> -    p = new (p) A [2][i3];       // { dg-error "size of array is negative" }
> +    p = new (p) A [2][i3];       // { dg-error "size of array is|narrowing conversion" }
>      p = new (p) A [i4][5];       // { dg-error "size of array is negative" }
> -    p = new (p) A [i6][i7];      // { dg-error "size of array is negative" }
> +    p = new (p) A [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
>  
>      p = new (p) B [i1];          // { dg-error "size of array is negative" }
> -    p = new (p) B [2][i3];       // { dg-error "size of array is negative" }
> +    p = new (p) B [2][i3];       // { dg-error "size of array is|narrowing conversion" }
>      p = new (p) B [i4][5];       // { dg-error "size of array is negative" }
> -    p = new (p) B [i6][i7];      // { dg-error "size of array is negative" }
> +    p = new (p) B [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
>  
>      p = new (&b) B [i1];          // { dg-error "size of array is negative" }
> -    p = new (&b) B [2][i3];       // { dg-error "size of array is negative" }
> +    p = new (&b) B [2][i3];       // { dg-error "size of array is|narrowing conversion" }
>      p = new (&b) B [i4][5];       // { dg-error "size of array is negative" }
> -    p = new (&b) B [i6][i7];      // { dg-error "size of array is negative" }
> +    p = new (&b) B [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
>  
>      p = new short [i1 - 2];       // { dg-error "size of array is negative" }
>      p = new (p) bool [i2 - 3];    // { dg-error "size of array is negative" }
>      p = new A [2 < 1 ? i1 : i2];  // { dg-error "size of array is negative" }
>      p = new (p) B [2 + i3 * 2];   // { dg-error "size of array is negative" }
> -    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array is negative" }
> +    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
>  }
>  
>  void test_constexpr ()
> @@ -132,33 +132,33 @@ void test_constexpr ()
>  
>      // Verify constant expression.
>      p = new char [s1];           // { dg-error "size of array is negative" }
> -    p = new char [2][s3];        // { dg-error "size of array is negative" }
> +    p = new char [2][s3];        // { dg-error "size of array is|narrowing conversion" }
>      p = new char [s4][5];        // { dg-error "size of array is negative" }
> -    p = new char [s6][s7];       // { dg-error "size of array is negative" }
> +    p = new char [s6][s7];       // { dg-error "size of array is|narrowing conversion" }
>  
>      p = new (p) char [s1];       // { dg-error "size of array is negative" }
> -    p = new (p) char [2][s3];    // { dg-error "size of array is negative" }
> +    p = new (p) char [2][s3];    // { dg-error "size of array is|narrowing conversion" }
>      p = new (p) char [s4][5];    // { dg-error "size of array is negative" }
> -    p = new (p) char [s6][s7];   // { dg-error "size of array is negative" }
> +    p = new (p) char [s6][s7];   // { dg-error "size of array is|narrowing conversion" }
>  
>      p = new (p) A [s1];          // { dg-error "size of array is negative" }
> -    p = new (p) A [2][s3];       // { dg-error "size of array is negative" }
> +    p = new (p) A [2][s3];       // { dg-error "size of array is|narrowing conversion" }
>      p = new (p) A [s4][5];       // { dg-error "size of array is negative" }
> -    p = new (p) A [s6][s7];      // { dg-error "size of array is negative" }
> +    p = new (p) A [s6][s7];      // { dg-error "size of array is|narrowing conversion" }
>  
>      p = new (p) B [s1];          // { dg-error "size of array is negative" }
> -    p = new (p) B [2][s3];       // { dg-error "size of array is negative" }
> +    p = new (p) B [2][s3];       // { dg-error "size of array is|narrowing conversion" }
>      p = new (p) B [s4][5];       // { dg-error "size of array is negative" }
> -    p = new (p) B [s6][s7];      // { dg-error "size of array is negative" }
> +    p = new (p) B [s6][s7];      // { dg-error "size of array is|narrowing conversion" }
>  
>      p = new (&b) B [s1];          // { dg-error "size of array is negative" }
> -    p = new (&b) B [2][s3];       // { dg-error "size of array is negative" }
> +    p = new (&b) B [2][s3];       // { dg-error "size of array is|narrowing conversion" }
>      p = new (&b) B [s4][5];       // { dg-error "size of array is negative" }
> -    p = new (&b) B [s6][s7];      // { dg-error "size of array is negative" }
> +    p = new (&b) B [s6][s7];      // { dg-error "size of array is|narrowing conversion" }
>  
>      p = new int [s1 + s2];           // { dg-error "size of array is negative" }
>      p = new (p) long [2 * s3];       // { dg-error "size of array is negative" }
>      p = new A [s2 < s1 ? s1 : s2];   // { dg-error "size of array is negative" }
>      p = new (p) B [s7 - s2 * 2];     // { dg-error "size of array is negative" }
> -    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of array is negative" }
> +    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of array is|narrowing conversion" }
>  }
> diff --git gcc/testsuite/g++.dg/other/fold1.C gcc/testsuite/g++.dg/other/fold1.C
> index 23d34546e0b..bf074038b04 100644
> --- gcc/testsuite/g++.dg/other/fold1.C
> +++ gcc/testsuite/g++.dg/other/fold1.C
> @@ -4,5 +4,5 @@
>  struct A
>  {
>      static const int i = i;  // { dg-error "not declared" }
> -    int x[i];		     // { dg-error "constant-expression" }
> +    int x[i];		     // { dg-error "constant-expression|narrowing conversion" }
>  };
> diff --git gcc/testsuite/g++.dg/other/vrp1.C gcc/testsuite/g++.dg/other/vrp1.C
> index 0a798c9954e..466a15b4cbb 100644
> --- gcc/testsuite/g++.dg/other/vrp1.C
> +++ gcc/testsuite/g++.dg/other/vrp1.C
> @@ -9,4 +9,4 @@ long long mod (long long l, long long r)
>      return 0LL;
>    return l % r;
>  }
> -template long long mod<-0x8000000000000000LL> (long long, long long);
> +template long long mod<-0x8000000000000000LL> (long long, long long); // { dg-error "template-id" "" { target { c++11 } } }
> diff --git gcc/testsuite/g++.dg/parse/array-size2.C gcc/testsuite/g++.dg/parse/array-size2.C
> index d0bc47fe746..997b95eed1a 100644
> --- gcc/testsuite/g++.dg/parse/array-size2.C
> +++ gcc/testsuite/g++.dg/parse/array-size2.C
> @@ -14,7 +14,7 @@ extern void bar (char *, char *);
>  void
>  foo (void)
>  {
> -  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" }
> +  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant|narrowing conversion" }
>    char h[(__SIZE_TYPE__) &((struct S *) 8)->b];	      // { dg-error "constant" }
>    bar (g, h);
>  }
> diff --git gcc/testsuite/g++.dg/template/char1.C gcc/testsuite/g++.dg/template/char1.C
> index 51e72e7ad06..a6cffaaf024 100644
> --- gcc/testsuite/g++.dg/template/char1.C
> +++ gcc/testsuite/g++.dg/template/char1.C
> @@ -1,4 +1,5 @@
>  template <class CharType, CharType line_terminator = 0>
>  class String {};
>  
> -String<signed char, 255> s;		// { dg-warning "overflow" }
> +String<signed char, 255> s;		// { dg-error "narrowing conversion" "" { target c++11 } }
> +// { dg-warning "overflow" "" { target c++98_only } .-1 }
> diff --git gcc/testsuite/g++.dg/template/dependent-name3.C gcc/testsuite/g++.dg/template/dependent-name3.C
> index bbe6fb66266..f9d14055a11 100644
> --- gcc/testsuite/g++.dg/template/dependent-name3.C
> +++ gcc/testsuite/g++.dg/template/dependent-name3.C
> @@ -11,7 +11,7 @@ template<int I> struct A
>  template<int N> struct B
>  {
>    int x[A<N>::zero];       // { dg-error "zero" }
> -  int y[A<N>::minus_one];  // { dg-error "negative" }
> +  int y[A<N>::minus_one];  // { dg-error "size of array|narrowing conversion" }
>  };
>  
>  B<0> b;
> 
> 	Marek

Marek
Jason Merrill Aug. 5, 2018, 2:02 p.m. UTC | #11
On Tue, Jul 24, 2018 at 6:49 AM, Marek Polacek <polacek@redhat.com> wrote:
> On Tue, Jul 03, 2018 at 04:27:33PM -0400, Jason Merrill wrote:
>> On Tue, Jul 3, 2018 at 3:41 PM, Jason Merrill <jason@redhat.com> wrote:
>> > On Tue, Jul 3, 2018 at 2:58 PM, Marek Polacek <polacek@redhat.com> wrote:
>> >> On Tue, Jul 03, 2018 at 12:40:51PM -0400, Jason Merrill wrote:
>> >>> On Fri, Jun 29, 2018 at 3:58 PM, Marek Polacek <polacek@redhat.com> wrote:
>> >>> > On Wed, Jun 27, 2018 at 07:35:15PM -0400, Jason Merrill wrote:
>> >>> >> On Wed, Jun 27, 2018 at 12:53 PM, Marek Polacek <polacek@redhat.com> wrote:
>> >>> >> > This PR complains about us accepting invalid code like
>> >>> >> >
>> >>> >> >   template<unsigned int> struct A {};
>> >>> >> >   A<-1> a;
>> >>> >> >
>> >>> >> > Where we should detect the narrowing: [temp.arg.nontype] says
>> >>> >> > "A template-argument for a non-type template-parameter shall be a converted
>> >>> >> > constant expression ([expr.const]) of the type of the template-parameter."
>> >>> >> > and a converted constant expression can contain only
>> >>> >> > - integral conversions other than narrowing conversions,
>> >>> >> > - [...]."
>> >>> >> > It spurred e.g.
>> >>> >> > <https://stackoverflow.com/questions/28184888/how-implicit-conversion-works-for-non-type-template-parameters>
>> >>> >> > and has >=3 dups so it has some visibility.
>> >>> >> >
>> >>> >> > I think build_converted_constant_expr needs to set check_narrowing.
>> >>> >> > check_narrowing also always mentions that it's in { } but that is no longer
>> >>> >> > true; in the future it will also apply to <=>.  We'd probably have to add a new
>> >>> >> > flag to struct conversion if wanted to distinguish between these.
>> >>> >> >
>> >>> >> > This does not yet fix detecting narrowing in function templates (78244).
>> >>> >> >
>> >>> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
>> >>> >> >
>> >>> >> > 2018-06-27  Marek Polacek  <polacek@redhat.com>
>> >>> >> >
>> >>> >> >         PR c++/57891
>> >>> >> >         * call.c (build_converted_constant_expr): Set check_narrowing.
>> >>> >> >         * decl.c (compute_array_index_type): Add warning sentinel.  Use
>> >>> >> >         input_location.
>> >>> >> >         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
>> >>> >> >         were reported.
>> >>> >> >         * typeck2.c (check_narrowing): Don't mention { } in diagnostic.
>> >>> >> >
>> >>> >> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
>> >>> >> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
>> >>> >> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
>> >>> >> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
>> >>> >> >         * g++.dg/init/new43.C: Adjust dg-error.
>> >>> >> >         * g++.dg/other/fold1.C: Likewise.
>> >>> >> >         * g++.dg/parse/array-size2.C: Likewise.
>> >>> >> >         * g++.dg/other/vrp1.C: Add dg-error.
>> >>> >> >         * g++.dg/template/char1.C: Likewise.
>> >>> >> >         * g++.dg/ext/builtin12.C: Likewise.
>> >>> >> >         * g++.dg/template/dependent-name3.C: Adjust dg-error.
>> >>> >> >
>> >>> >> > diff --git gcc/cp/call.c gcc/cp/call.c
>> >>> >> > index 209c1fd2f0e..956c7b149dc 100644
>> >>> >> > --- gcc/cp/call.c
>> >>> >> > +++ gcc/cp/call.c
>> >>> >> > @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
>> >>> >> >      }
>> >>> >> >
>> >>> >> >    if (conv)
>> >>> >> > -    expr = convert_like (conv, expr, complain);
>> >>> >> > +    {
>> >>> >> > +      conv->check_narrowing = !processing_template_decl;
>> >>> >>
>> >>> >> Why !processing_template_decl?  This needs a comment.
>> >>> >
>> >>> > Otherwise we'd warn for e.g.
>> >>> >
>> >>> > template<int N> struct S { char a[N]; };
>> >>> > S<1> s;
>> >>> >
>> >>> > where compute_array_index_type will try to convert the size of the array (which
>> >>> > is a template_parm_index of type int when parsing the template) to size_type.
>> >>> > So I guess I can say that we need to wait for instantiation?
>> >>>
>> >>> We certainly shouldn't give a narrowing diagnostic about a
>> >>> value-dependent expression.  It probably makes sense to check that at
>> >>> the top of check_narrowing, with all the other early exit conditions.
>> >>> But if we do know the constant value in the template, it's good to
>> >>> complain then rather than wait for instantiation.
>> >>
>> >> Makes sense; how about this then?  (Regtest/bootstrap running.)
>> >>
>> >> 2018-07-03  Marek Polacek  <polacek@redhat.com>
>> >>
>> >>         PR c++/57891
>> >>         * call.c (build_converted_constant_expr): Set check_narrowing.
>> >>         * decl.c (compute_array_index_type): Add warning sentinel.  Use
>> >>         input_location.
>> >>         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
>> >>         were reported.
>> >>         * typeck2.c (check_narrowing): Don't warn for instantiation-dependent
>> >>         expressions or non-constants in a template.  Don't mention { } in
>> >>         diagnostic.
>> >>
>> >>         * g++.dg/cpp0x/Wnarrowing6.C: New test.
>> >>         * g++.dg/cpp0x/Wnarrowing7.C: New test.
>> >>         * g++.dg/cpp0x/Wnarrowing8.C: New test.
>> >>         * g++.dg/cpp0x/Wnarrowing9.C: New test.
>> >>         * g++.dg/cpp0x/Wnarrowing10.C: New test.
>> >>         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
>> >>         * g++.dg/init/new43.C: Adjust dg-error.
>> >>         * g++.dg/other/fold1.C: Likewise.
>> >>         * g++.dg/parse/array-size2.C: Likewise.
>> >>         * g++.dg/other/vrp1.C: Add dg-error.
>> >>         * g++.dg/template/char1.C: Likewise.
>> >>         * g++.dg/ext/builtin12.C: Likewise.
>> >>         * g++.dg/template/dependent-name3.C: Adjust dg-error.
>> >>
>> >> diff --git gcc/cp/call.c gcc/cp/call.c
>> >> index 209c1fd2f0e..4fb0fa8774b 100644
>> >> --- gcc/cp/call.c
>> >> +++ gcc/cp/call.c
>> >> @@ -4152,7 +4152,10 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
>> >>      }
>> >>
>> >>    if (conv)
>> >> -    expr = convert_like (conv, expr, complain);
>> >> +    {
>> >> +      conv->check_narrowing = true;
>> >> +      expr = convert_like (conv, expr, complain);
>> >> +    }
>> >>    else
>> >>      expr = error_mark_node;
>> >>
>> >> diff --git gcc/cp/decl.c gcc/cp/decl.c
>> >> index c04b9b7d457..8da63fa2aaa 100644
>> >> --- gcc/cp/decl.c
>> >> +++ gcc/cp/decl.c
>> >> @@ -9508,6 +9508,8 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
>> >>        else
>> >>         {
>> >>           size = instantiate_non_dependent_expr_sfinae (size, complain);
>> >> +         /* Don't warn about narrowing for VLAs.  */
>> >> +         warning_sentinel s (warn_narrowing, !TREE_CONSTANT (osize));
>> >>           size = build_converted_constant_expr (size_type_node, size, complain);
>> >
>> > Hmm, perhaps the underlying issue is that we only want
>> > build_converted_constant_expr to check for narrowing of constant
>> > values; if the value isn't constant, it isn't any kind of constant
>> > expression.  So perhaps the checking needs to happen as part of
>> > constexpr evaluation.
>>
>> On the other hand, check_narrowing itself forces constexpr evaluation,
>> so this could be handled all in the conversion code; we just need to
>> tell check_narrowing to allow non-constant values in that case.

> OK -- see the patch below.  Now, I'm not crazy about adding another bit
> to struct conversion, but reusing any of the other bits didn't seem
> safe/possible.  Maybe it'll come in handy when dealing with this problem
> for function templates.

Looks good.

>> >> @@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
>> >>           /* C++17: A template-argument for a non-type template-parameter shall
>> >>              be a converted constant expression (8.20) of the type of the
>> >>              template-parameter.  */
>> >> +         int errs = errorcount;
>> >>           expr = build_converted_constant_expr (type, expr, complain);
>> >>           if (expr == error_mark_node)
>> >> -           return error_mark_node;
>> >> +           /* Make sure we return NULL_TREE only if we have really issued
>> >> +              an error, as described above.  */
>> >> +           return errorcount > errs ? NULL_TREE : error_mark_node;
>> >
>> > Is this still needed?
>>
>> Earlier you wrote,
>>
>> > Checking complain doesn't work because that doesn't
>> > say if we have really issued an error.  If we have not, and we return
>> > NULL_TREE anyway, we hit this assert:
>> >  8517       gcc_assert (!(complain & tf_error) || seen_error ());
>>
>> If (complain & tf_error), we shouldn't see error_mark_node without an
>> error having been issued.  Why is build_converted_constant_expr
>> returning error_mark_node without giving an error when (complain &
>> tf_error)?
>
> This can happen on invalid code; e.g. tests nontype13.C and crash87.C.
> What happens there is that we're trying to convert a METHOD_TYPE to bool,
> which doesn't work: in standard_conversion we go into the
>     else if (tcode == BOOLEAN_TYPE)
> block, which returns NULL, implicit_conversion also then returns NULL, yet
> no error has been issued.

Yes, that's normal.  The problem is in build_converted_constant_expr:

  if (conv)
    expr = convert_like (conv, expr, complain);
  else
    expr = error_mark_node;

Here when setting expr to error_mark_node I forgot to give an error if
(complain & tf_error).

>> >> +      /* If we're in a template and we know the constant value, we can
>> >> +        warn.  Otherwise wait for instantiation.  */
>> >> +      || (processing_template_decl && !TREE_CONSTANT (init)))
>> >
>> > I don't think we want this condition.  If the value is non-constant
>> > but also not dependent, it'll never be constant, so we can go ahead
>> > and complain.
>
> (This to be investigated later.)

Why later?

> Bootstrapped/regtested on x86_64-linux, ok for trunk?
>
> 2018-07-23  Marek Polacek  <polacek@redhat.com>
>
>         PR c++/57891
>         * call.c (struct conversion): Add check_narrowing_const_only.
>         (build_converted_constant_expr): Set check_narrowing and
>         check_narrowing_const_only.
>         (convert_like_real): Pass it to check_narrowing.
>         * cp-tree.h (check_narrowing): Add a default parameter.
>         * decl.c (compute_array_index_type): Use input_location.
>         * pt.c (convert_nontype_argument): Return NULL_TREE if any errors
>         were reported.
>         * typeck2.c (check_narrowing): Don't warn for instantiation-dependent
>         expressions or non-constants in a template.  Don't mention { } in
>         diagnostic.  Only check narrowing for constants if CONST_ONLY.
>
> --- gcc/cp/decl.c
> +++ gcc/cp/decl.c
> @@ -9581,7 +9581,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
>      {
>        tree folded = cp_fully_fold (size);
>        if (TREE_CODE (folded) == INTEGER_CST)
> -       pedwarn (location_of (size), OPT_Wpedantic,
> +       pedwarn (input_location, OPT_Wpedantic,

It should work to use location_of (osize) here.

Jason
Marek Polacek Aug. 9, 2018, 8:59 p.m. UTC | #12
On Mon, Aug 06, 2018 at 12:02:31AM +1000, Jason Merrill wrote:
> > OK -- see the patch below.  Now, I'm not crazy about adding another bit
> > to struct conversion, but reusing any of the other bits didn't seem
> > safe/possible.  Maybe it'll come in handy when dealing with this problem
> > for function templates.
> 
> Looks good.
> 
> >> >> @@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
> >> >>           /* C++17: A template-argument for a non-type template-parameter shall
> >> >>              be a converted constant expression (8.20) of the type of the
> >> >>              template-parameter.  */
> >> >> +         int errs = errorcount;
> >> >>           expr = build_converted_constant_expr (type, expr, complain);
> >> >>           if (expr == error_mark_node)
> >> >> -           return error_mark_node;
> >> >> +           /* Make sure we return NULL_TREE only if we have really issued
> >> >> +              an error, as described above.  */
> >> >> +           return errorcount > errs ? NULL_TREE : error_mark_node;
> >> >
> >> > Is this still needed?
> >>
> >> Earlier you wrote,
> >>
> >> > Checking complain doesn't work because that doesn't
> >> > say if we have really issued an error.  If we have not, and we return
> >> > NULL_TREE anyway, we hit this assert:
> >> >  8517       gcc_assert (!(complain & tf_error) || seen_error ());
> >>
> >> If (complain & tf_error), we shouldn't see error_mark_node without an
> >> error having been issued.  Why is build_converted_constant_expr
> >> returning error_mark_node without giving an error when (complain &
> >> tf_error)?
> >
> > This can happen on invalid code; e.g. tests nontype13.C and crash87.C.
> > What happens there is that we're trying to convert a METHOD_TYPE to bool,
> > which doesn't work: in standard_conversion we go into the
> >     else if (tcode == BOOLEAN_TYPE)
> > block, which returns NULL, implicit_conversion also then returns NULL, yet
> > no error has been issued.
> 
> Yes, that's normal.  The problem is in build_converted_constant_expr:
> 
>   if (conv)
>     expr = convert_like (conv, expr, complain);
>   else
>     expr = error_mark_node;
> 
> Here when setting expr to error_mark_node I forgot to give an error if
> (complain & tf_error).

Done.  A few testcases needed adjusting but nothing surprising.

> >> >> +      /* If we're in a template and we know the constant value, we can
> >> >> +        warn.  Otherwise wait for instantiation.  */
> >> >> +      || (processing_template_decl && !TREE_CONSTANT (init)))
> >> >
> >> > I don't think we want this condition.  If the value is non-constant
> >> > but also not dependent, it'll never be constant, so we can go ahead
> >> > and complain.
> >
> > (This to be investigated later.)
> 
> Why later?

So this was this wrong error:
https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00159.html
which was confusing.  But I noticed it's because we instantiate 'size' twice:
in compute_array_index_type:
  size = instantiate_non_dependent_expr_sfinae (size, complain);
  size = build_converted_constant_expr (size_type_node, size, complain);
  size = maybe_constant_value (size);
and then in check_narrowing:
  init = fold_non_dependent_expr (init, complain);

(in this case, size is a call to constexpr user-defined conversion).

But check_narrowing now returns early if instantiation_dependent_expression_p,
so I thought perhaps we could simply call maybe_constant_value which fixes this
problem and doesn't regress anything.  Does that seem like a sensible thing
to do?

> > --- gcc/cp/decl.c
> > +++ gcc/cp/decl.c
> > @@ -9581,7 +9581,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
> >      {
> >        tree folded = cp_fully_fold (size);
> >        if (TREE_CODE (folded) == INTEGER_CST)
> > -       pedwarn (location_of (size), OPT_Wpedantic,
> > +       pedwarn (input_location, OPT_Wpedantic,
> 
> It should work to use location_of (osize) here.

I dropped this hunk altogether.  Because location_of will use
DECL_SOURCE_LOCATION for DECLs, the error message will point to the declaration
itself, not the use.  I don't really care either way.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-08-09  Marek Polacek  <polacek@redhat.com>

	PR c++/57891
	* call.c (struct conversion): Add check_narrowing_const_only.
	(build_converted_constant_expr): Set check_narrowing and
	check_narrowing_const_only.  Give error if expr is error node.
	(convert_like_real): Pass it to check_narrowing.
	* cp-tree.h (check_narrowing): Add a default parameter.
	* pt.c (convert_nontype_argument): Return NULL_TREE if tf_error.
	* typeck2.c (check_narrowing): Don't warn for instantiation-dependent
	expressions.  Call maybe_constant_value instead of
	fold_non_dependent_expr.  Don't mention { } in diagnostic.  Only check
	narrowing for constants if CONST_ONLY.

	* g++.dg/cpp0x/Wnarrowing6.C: New test.
	* g++.dg/cpp0x/Wnarrowing7.C: New test.
	* g++.dg/cpp0x/Wnarrowing8.C: New test.
	* g++.dg/cpp0x/Wnarrowing9.C: New test.
	* g++.dg/cpp0x/Wnarrowing10.C: New test.

	* g++.dg/cpp0x/constexpr-47969.C: Adjust dg-error.
	* g++.dg/cpp0x/constexpr-ex2.C: Likewise.
	* g++.dg/cpp0x/constexpr-targ.C: Likewise.
	* g++.dg/cpp0x/scoped_enum2.C: Likewise.
	* g++.dg/ext/stmtexpr15.C: Likewise.
	* g++.dg/gomp/pr47963.C: Likewise.
	* g++.dg/init/new37.C: Likewise.
	* g++.dg/init/new43.C: Likewise.
	* g++.dg/other/fold1.C: Likewise.
	* g++.dg/parse/array-size2.C: Likewise.
	* g++.dg/template/dependent-name3.C: Likewise.
	* g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
	* g++.dg/other/vrp1.C: Likewise.
	* g++.dg/template/char1.C: Likewise.

diff --git gcc/cp/call.c gcc/cp/call.c
index 209c1fd2f0e..62654a9e407 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -107,6 +107,9 @@ struct conversion {
      binding a reference directly or decaying to a pointer.  */
   BOOL_BITFIELD rvaluedness_matches_p: 1;
   BOOL_BITFIELD check_narrowing: 1;
+  /* Whether check_narrowing should only check TREE_CONSTANTs; used
+     in build_converted_constant_expr.  */
+  BOOL_BITFIELD check_narrowing_const_only: 1;
   /* The type of the expression resulting from the conversion.  */
   tree type;
   union {
@@ -4152,9 +4155,18 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
     }
 
   if (conv)
-    expr = convert_like (conv, expr, complain);
+    {
+      conv->check_narrowing = true;
+      conv->check_narrowing_const_only = true;
+      expr = convert_like (conv, expr, complain);
+    }
   else
-    expr = error_mark_node;
+    {
+      if (complain & tf_error)
+	error_at (loc, "could not convert %qE from %qH to %qI", expr,
+		  TREE_TYPE (expr), type);
+      expr = error_mark_node;
+    }
 
   /* Free all the conversions we allocated.  */
   obstack_free (&conversion_obstack, p);
@@ -7142,7 +7154,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
     }
 
   if (convs->check_narrowing
-      && !check_narrowing (totype, expr, complain))
+      && !check_narrowing (totype, expr, complain,
+			   convs->check_narrowing_const_only))
     return error_mark_node;
 
   warning_sentinel w (warn_zero_as_null_pointer_constant);
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index 94a85b72d2b..9608cf5334b 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -7397,7 +7397,8 @@ extern int abstract_virtuals_error_sfinae	(abstract_class_use, tree, tsubst_flag
 
 extern tree store_init_value			(tree, tree, vec<tree, va_gc>**, int);
 extern tree split_nonconstant_init		(tree, tree);
-extern bool check_narrowing			(tree, tree, tsubst_flags_t);
+extern bool check_narrowing			(tree, tree, tsubst_flags_t,
+						 bool = false);
 extern tree digest_init				(tree, tree, tsubst_flags_t);
 extern tree digest_init_flags			(tree, tree, int, tsubst_flags_t);
 extern tree digest_nsdmi_init		        (tree, tree, tsubst_flags_t);
diff --git gcc/cp/pt.c gcc/cp/pt.c
index 7fcf5d6b2d3..cbb7b8ea853 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -6682,7 +6682,9 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 	     template-parameter.  */
 	  expr = build_converted_constant_expr (type, expr, complain);
 	  if (expr == error_mark_node)
-	    return error_mark_node;
+	    /* Make sure we return NULL_TREE only if we have really issued
+	       an error, as described above.  */
+	    return (complain & tf_error) ? NULL_TREE : error_mark_node;
 	  expr = maybe_constant_value (expr);
 	  expr = convert_from_reference (expr);
 	}
diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index 7763d53ee65..0b886df12f7 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -875,10 +875,12 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
 }
 
 
-/* Give diagnostic about narrowing conversions within { }.  */
+/* Give diagnostic about narrowing conversions within { }, or as part of
+   a converted constant expression.  If CONST_ONLY, only check
+   constants.  */
 
 bool
-check_narrowing (tree type, tree init, tsubst_flags_t complain)
+check_narrowing (tree type, tree init, tsubst_flags_t complain, bool const_only)
 {
   tree ftype = unlowered_expr_type (init);
   bool ok = true;
@@ -886,7 +888,9 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 
   if (((!warn_narrowing || !(complain & tf_warning))
        && cxx_dialect == cxx98)
-      || !ARITHMETIC_TYPE_P (type))
+      || !ARITHMETIC_TYPE_P (type)
+      /* Don't emit bogus warnings with e.g. value-dependent trees.  */
+      || instantiation_dependent_expression_p (init))
     return ok;
 
   if (BRACE_ENCLOSED_INITIALIZER_P (init)
@@ -902,7 +906,11 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
       return ok;
     }
 
-  init = fold_non_dependent_expr (init, complain);
+  init = maybe_constant_value (init);
+
+  /* If we were asked to only check constants, return early.  */
+  if (const_only && !TREE_CONSTANT (init))
+    return ok;
 
   if (TREE_CODE (type) == INTEGER_TYPE
       && TREE_CODE (ftype) == REAL_TYPE)
@@ -967,7 +975,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	{
 	  if (complain & tf_warning)
 	    warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
-			"from %qH to %qI inside { } is ill-formed in C++11",
+			"from %qH to %qI is ill-formed in C++11",
 			init, ftype, type);
 	  ok = true;
 	}
@@ -977,8 +985,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	    {
 	      if ((!almost_ok || pedantic)
 		  && pedwarn (loc, OPT_Wnarrowing,
-			      "narrowing conversion of %qE "
-			      "from %qH to %qI inside { }",
+			      "narrowing conversion of %qE from %qH to %qI",
 			      init, ftype, type)
 		  && almost_ok)
 		inform (loc, " the expression has a constant value but is not "
@@ -991,8 +998,8 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	  int savederrorcount = errorcount;
 	  global_dc->pedantic_errors = 1;
 	  pedwarn (loc, OPT_Wnarrowing,
-		   "narrowing conversion of %qE from %qH to %qI "
-		   "inside { }", init, ftype, type);
+		   "narrowing conversion of %qE from %qH to %qI ",
+		   init, ftype, type);
 	  if (errorcount == savederrorcount)
 	    ok = true;
 	  global_dc->pedantic_errors = flag_pedantic_errors;
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
index e69de29bb2d..8414b53e342 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
@@ -0,0 +1,5 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+template<int N, unsigned char M = N> struct S { char a[N]; };
+S<1000> s; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
index e69de29bb2d..989d277cd00 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
@@ -0,0 +1,8 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+template<unsigned int> struct A {};
+A<-1> a; // { dg-error "narrowing conversion" }
+
+template<signed char> struct B {};
+B<1000> b; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
index e69de29bb2d..099fdfb7d81 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
@@ -0,0 +1,9 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-narrowing" }
+
+template<unsigned int> struct A {};
+A<-1> a;
+
+template<signed char> struct B {};
+B<1000> b; // { dg-warning "overflow" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
index e69de29bb2d..39c924c9c6c 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
@@ -0,0 +1,6 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+struct X { constexpr operator int () { return 1000; } };
+template<signed char> struct C {};
+C<X{}> c; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
index e69de29bb2d..bc8a736ecb9 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
@@ -0,0 +1,6 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+// N is value-dependent, don't warn.
+template<int N> struct S { char a[N]; }; // { dg-bogus "narrowing conversion" }
+S<1> s;
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
index 933831b94de..201ee17b41b 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
@@ -8,4 +8,4 @@ struct A
 
 constexpr A a = A();
 
-int ar[a]; // { dg-error "has non-integral type" }
+int ar[a]; // { dg-error "could not convert|has non-integral type" }
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
index 898102167de..dee5ed82301 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
@@ -43,4 +43,4 @@ extern template struct A3<int, 510>;
 
 // Use.
 A3<int, 1111> a31;
-A3<char, 9999> a32;		// { dg-warning "overflow" }
+A3<char, 9999> a32;		// { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
index 34b557ce76e..ceae9cb75d3 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
@@ -18,5 +18,5 @@ constexpr A a = 42;
 
 X<a> x;	    // OK: unique conversion to int
 int ar[X<a>::i]; // also OK
-int ary[a]; // { dg-error "ambiguous|conversion|array" } ambiguous conversion
+int ary[a]; // { dg-error "could not convert|ambiguous|conversion|array" } ambiguous conversion
 
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
index 98bb502249a..0f1f113f92f 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
@@ -10,4 +10,4 @@ struct B
 { };
 
 constexpr A a { };
-B<a> b;			 // { dg-error "template argument|converted constant" }
+B<a> b;			 // { dg-error "template argument|converted constant|could not convert" }
diff --git gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
index bb8ad750bd0..456b0daedd1 100644
--- gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
+++ gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
@@ -4,8 +4,8 @@ enum class E { e = 10 };
 enum E2 { e2 = 10 };
 
 struct C {
-  int arr[E::e];    // { dg-error "non-integral type" }
+  int arr[E::e];    // { dg-error "could not convert|non-integral type" }
   int arr2[E2::e2]; // OK
-  int i: E::e;	    // { dg-error "non-integral type" }
+  int i: E::e;	    // { dg-error "could not convert|non-integral type" }
   int i2: E2::e2;   // OK
 };
diff --git gcc/testsuite/g++.dg/ext/stmtexpr15.C gcc/testsuite/g++.dg/ext/stmtexpr15.C
index 83a831cdd4c..1a60a0d3cad 100644
--- gcc/testsuite/g++.dg/ext/stmtexpr15.C
+++ gcc/testsuite/g++.dg/ext/stmtexpr15.C
@@ -3,5 +3,5 @@
 
 void foo()
 {
-  int x[({ return; })];		// { dg-error "non-integral" }
+  int x[({ return; })];		// { dg-error "could not convert|non-integral" }
 }
diff --git gcc/testsuite/g++.dg/gomp/pr47963.C gcc/testsuite/g++.dg/gomp/pr47963.C
index 5b0c60b80a4..6be4c0e18fb 100644
--- gcc/testsuite/g++.dg/gomp/pr47963.C
+++ gcc/testsuite/g++.dg/gomp/pr47963.C
@@ -5,7 +5,7 @@
 void
 foo (float n)
 {
-  int A[n][n];	// { dg-error "has non-integral type|converted constant expression" }
+  int A[n][n];	// { dg-error "could not convert|has non-integral type|converted constant expression" }
 #pragma omp parallel private(A)
   ;
 }
diff --git gcc/testsuite/g++.dg/init/new37.C gcc/testsuite/g++.dg/init/new37.C
index 9ecbfd7903d..2a42fda33dc 100644
--- gcc/testsuite/g++.dg/init/new37.C
+++ gcc/testsuite/g++.dg/init/new37.C
@@ -32,7 +32,7 @@ template <typename T>
 void *
 callnew_fail_3()
 {
-  return new T[2][T::n]; // { dg-error "size of array has non-integral type|converted constant expression" }
+  return new T[2][T::n]; // { dg-error "could not convert|size of array has non-integral type|converted constant expression" }
 }
 
 struct T1 {
diff --git gcc/testsuite/g++.dg/init/new43.C gcc/testsuite/g++.dg/init/new43.C
index 9b0866720fe..cbb6f2d9da8 100644
--- gcc/testsuite/g++.dg/init/new43.C
+++ gcc/testsuite/g++.dg/init/new43.C
@@ -31,35 +31,35 @@ void test_literal ()
 
     // Verify integer literal.
     p = new char [-1];           // { dg-error "size of array is negative" }
-    p = new char [2][-3];        // { dg-error "size of array is negative" }
+    p = new char [2][-3];        // { dg-error "size of array is negative|narrowing conversion" }
     p = new char [-4][5];        // { dg-error "size of array is negative" }
-    p = new char [-6][-7];       // { dg-error "size of array is negative" }
+    p = new char [-6][-7];       // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) char [-1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][-3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][-3];    // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) char [-4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [-6][-7];   // { dg-error "size of array is negative" }
+    p = new (p) char [-6][-7];   // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) A [-1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) A [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) A [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) B [-1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (&b) B [-1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (&b) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new char [1 - 2];         // { dg-error "size of array is negative" }
     p = new (p) char [2 - 3];     // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? -1 : -2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 - 3 * 2];    // { dg-error "size of array is negative" }
-    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constant_expression ()
@@ -71,43 +71,43 @@ void test_constant_expression ()
 
     static const signed char i1 = -1;
     static const signed short i2 = -2;
-    static const signed int i3 = -3;
+    static const signed int i3 = -3;	// { dg-error "size of array" "" { target c++11 } }
     static const signed long i4 = -4;
     static const signed long long i5 = -5;
     static const int i6 = -6;
-    static const int i7 = -7;
+    static const int i7 = -7;		// { dg-error "size of array" "" { target c++11 } }
 
     // Verify constant expression.
     p = new char [i1];           // { dg-error "size of array is negative" }
-    p = new char [2][i3];        // { dg-error "size of array is negative" }
+    p = new char [2][i3];        // { dg-error "size of array is negative|narrowing conversion" }
     p = new char [i4][5];        // { dg-error "size of array is negative" }
-    p = new char [i6][i7];       // { dg-error "size of array is negative" }
+    p = new char [i6][i7];       // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) char [i1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][i3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][i3];    // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) char [i4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [i6][i7];   // { dg-error "size of array is negative" }
+    p = new (p) char [i6][i7];   // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) A [i1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][i3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) A [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) A [i6][i7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) B [i1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][i3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) B [i6][i7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (&b) B [i1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][i3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (&b) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [i6][i7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new short [i1 - 2];       // { dg-error "size of array is negative" }
     p = new (p) bool [i2 - 3];    // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? i1 : i2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 + i3 * 2];   // { dg-error "size of array is negative" }
-    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constexpr ()
@@ -132,33 +132,33 @@ void test_constexpr ()
 
     // Verify constant expression.
     p = new char [s1];           // { dg-error "size of array is negative" }
-    p = new char [2][s3];        // { dg-error "size of array is negative" }
+    p = new char [2][s3];        // { dg-error "size of array|narrowing conversion" }
     p = new char [s4][5];        // { dg-error "size of array is negative" }
-    p = new char [s6][s7];       // { dg-error "size of array is negative" }
+    p = new char [s6][s7];       // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) char [s1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][s3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][s3];    // { dg-error "size of array|narrowing conversion" }
     p = new (p) char [s4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [s6][s7];   // { dg-error "size of array is negative" }
+    p = new (p) char [s6][s7];   // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) A [s1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][s3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][s3];       // { dg-error "size of array|narrowing conversion" }
     p = new (p) A [s4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [s6][s7];      // { dg-error "size of array is negative" }
+    p = new (p) A [s6][s7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) B [s1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][s3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][s3];       // { dg-error "size of array|narrowing conversion" }
     p = new (p) B [s4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [s6][s7];      // { dg-error "size of array is negative" }
+    p = new (p) B [s6][s7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new (&b) B [s1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][s3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][s3];       // { dg-error "size of array|narrowing conversion" }
     p = new (&b) B [s4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [s6][s7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [s6][s7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new int [s1 + s2];           // { dg-error "size of array is negative" }
     p = new (p) long [2 * s3];       // { dg-error "size of array is negative" }
     p = new A [s2 < s1 ? s1 : s2];   // { dg-error "size of array is negative" }
     p = new (p) B [s7 - s2 * 2];     // { dg-error "size of array is negative" }
-    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of array is negative" }
+    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of array|narrowing conversion" }
 }
diff --git gcc/testsuite/g++.dg/other/fold1.C gcc/testsuite/g++.dg/other/fold1.C
index 23d34546e0b..bf074038b04 100644
--- gcc/testsuite/g++.dg/other/fold1.C
+++ gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];		     // { dg-error "constant-expression" }
+    int x[i];		     // { dg-error "constant-expression|narrowing conversion" }
 };
diff --git gcc/testsuite/g++.dg/other/vrp1.C gcc/testsuite/g++.dg/other/vrp1.C
index 0a798c9954e..466a15b4cbb 100644
--- gcc/testsuite/g++.dg/other/vrp1.C
+++ gcc/testsuite/g++.dg/other/vrp1.C
@@ -9,4 +9,4 @@ long long mod (long long l, long long r)
     return 0LL;
   return l % r;
 }
-template long long mod<-0x8000000000000000LL> (long long, long long);
+template long long mod<-0x8000000000000000LL> (long long, long long); // { dg-error "template-id" "" { target { c++11 } } }
diff --git gcc/testsuite/g++.dg/parse/array-size2.C gcc/testsuite/g++.dg/parse/array-size2.C
index d0bc47fe746..997b95eed1a 100644
--- gcc/testsuite/g++.dg/parse/array-size2.C
+++ gcc/testsuite/g++.dg/parse/array-size2.C
@@ -14,7 +14,7 @@ extern void bar (char *, char *);
 void
 foo (void)
 {
-  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" }
+  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant|narrowing conversion" }
   char h[(__SIZE_TYPE__) &((struct S *) 8)->b];	      // { dg-error "constant" }
   bar (g, h);
 }
diff --git gcc/testsuite/g++.dg/template/char1.C gcc/testsuite/g++.dg/template/char1.C
index 51e72e7ad06..a6cffaaf024 100644
--- gcc/testsuite/g++.dg/template/char1.C
+++ gcc/testsuite/g++.dg/template/char1.C
@@ -1,4 +1,5 @@
 template <class CharType, CharType line_terminator = 0>
 class String {};
 
-String<signed char, 255> s;		// { dg-warning "overflow" }
+String<signed char, 255> s;		// { dg-error "narrowing conversion" "" { target c++11 } }
+// { dg-warning "overflow" "" { target c++98_only } .-1 }
diff --git gcc/testsuite/g++.dg/template/dependent-name3.C gcc/testsuite/g++.dg/template/dependent-name3.C
index bbe6fb66266..da62b187115 100644
--- gcc/testsuite/g++.dg/template/dependent-name3.C
+++ gcc/testsuite/g++.dg/template/dependent-name3.C
@@ -5,13 +5,13 @@
 template<int I> struct A
 {
   static const int zero = 0;
-  static const int minus_one = -1;
+  static const int minus_one = -1; // { dg-error "size of array" "" { target c++11} }
 };
 
 template<int N> struct B
 {
   int x[A<N>::zero];       // { dg-error "zero" }
-  int y[A<N>::minus_one];  // { dg-error "negative" }
+  int y[A<N>::minus_one];  // { dg-error "size of array|narrowing conversion" }
 };
 
 B<0> b;
Jason Merrill Aug. 11, 2018, 11:32 a.m. UTC | #13
On Fri, Aug 10, 2018 at 8:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> On Mon, Aug 06, 2018 at 12:02:31AM +1000, Jason Merrill wrote:
>> > OK -- see the patch below.  Now, I'm not crazy about adding another bit
>> > to struct conversion, but reusing any of the other bits didn't seem
>> > safe/possible.  Maybe it'll come in handy when dealing with this problem
>> > for function templates.
>>
>> Looks good.
>>
>> >> >> @@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
>> >> >>           /* C++17: A template-argument for a non-type template-parameter shall
>> >> >>              be a converted constant expression (8.20) of the type of the
>> >> >>              template-parameter.  */
>> >> >> +         int errs = errorcount;
>> >> >>           expr = build_converted_constant_expr (type, expr, complain);
>> >> >>           if (expr == error_mark_node)
>> >> >> -           return error_mark_node;
>> >> >> +           /* Make sure we return NULL_TREE only if we have really issued
>> >> >> +              an error, as described above.  */
>> >> >> +           return errorcount > errs ? NULL_TREE : error_mark_node;
>> >> >
>> >> > Is this still needed?
>> >>
>> >> Earlier you wrote,
>> >>
>> >> > Checking complain doesn't work because that doesn't
>> >> > say if we have really issued an error.  If we have not, and we return
>> >> > NULL_TREE anyway, we hit this assert:
>> >> >  8517       gcc_assert (!(complain & tf_error) || seen_error ());
>> >>
>> >> If (complain & tf_error), we shouldn't see error_mark_node without an
>> >> error having been issued.  Why is build_converted_constant_expr
>> >> returning error_mark_node without giving an error when (complain &
>> >> tf_error)?
>> >
>> > This can happen on invalid code; e.g. tests nontype13.C and crash87.C.
>> > What happens there is that we're trying to convert a METHOD_TYPE to bool,
>> > which doesn't work: in standard_conversion we go into the
>> >     else if (tcode == BOOLEAN_TYPE)
>> > block, which returns NULL, implicit_conversion also then returns NULL, yet
>> > no error has been issued.
>>
>> Yes, that's normal.  The problem is in build_converted_constant_expr:
>>
>>   if (conv)
>>     expr = convert_like (conv, expr, complain);
>>   else
>>     expr = error_mark_node;
>>
>> Here when setting expr to error_mark_node I forgot to give an error if
>> (complain & tf_error).
>
> Done.  A few testcases needed adjusting but nothing surprising.
>
>> >> >> +      /* If we're in a template and we know the constant value, we can
>> >> >> +        warn.  Otherwise wait for instantiation.  */
>> >> >> +      || (processing_template_decl && !TREE_CONSTANT (init)))
>> >> >
>> >> > I don't think we want this condition.  If the value is non-constant
>> >> > but also not dependent, it'll never be constant, so we can go ahead
>> >> > and complain.
>> >
>> > (This to be investigated later.)
>>
>> Why later?
>
> So this was this wrong error:
> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00159.html
> which was confusing.  But I noticed it's because we instantiate 'size' twice:
> in compute_array_index_type:
>   size = instantiate_non_dependent_expr_sfinae (size, complain);
>   size = build_converted_constant_expr (size_type_node, size, complain);
>   size = maybe_constant_value (size);
> and then in check_narrowing:
>   init = fold_non_dependent_expr (init, complain);
>
> (in this case, size is a call to constexpr user-defined conversion).
>
> But check_narrowing now returns early if instantiation_dependent_expression_p,
> so I thought perhaps we could simply call maybe_constant_value which fixes this
> problem and doesn't regress anything.  Does that seem like a sensible thing
> to do?

Hmm, that'll have problems if we pass an unfolded template expression
to check_narrowing, but probably we don't want to do that anyway.  So
yes, it seems reasonable.

>> > --- gcc/cp/decl.c
>> > +++ gcc/cp/decl.c
>> > @@ -9581,7 +9581,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
>> >      {
>> >        tree folded = cp_fully_fold (size);
>> >        if (TREE_CODE (folded) == INTEGER_CST)
>> > -       pedwarn (location_of (size), OPT_Wpedantic,
>> > +       pedwarn (input_location, OPT_Wpedantic,
>>
>> It should work to use location_of (osize) here.
>
> I dropped this hunk altogether.  Because location_of will use
> DECL_SOURCE_LOCATION for DECLs, the error message will point to the declaration
> itself, not the use.  I don't really care either way.

We want the message to point to the use, which location_of (osize)
will provide, since it should still have a location wrapper around a
DECL.

>           expr = build_converted_constant_expr (type, expr, complain);
>           if (expr == error_mark_node)
> -           return error_mark_node;
> +           /* Make sure we return NULL_TREE only if we have really issued
> +              an error, as described above.  */
> +           return (complain & tf_error) ? NULL_TREE : error_mark_node;

Now that you've fixed build_converted_constant_expr, we shouldn't need
this hunk.

Jason
Marek Polacek Aug. 11, 2018, 2:13 p.m. UTC | #14
On Sat, Aug 11, 2018 at 11:32:24PM +1200, Jason Merrill wrote:
> On Fri, Aug 10, 2018 at 8:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> > On Mon, Aug 06, 2018 at 12:02:31AM +1000, Jason Merrill wrote:
> >> > OK -- see the patch below.  Now, I'm not crazy about adding another bit
> >> > to struct conversion, but reusing any of the other bits didn't seem
> >> > safe/possible.  Maybe it'll come in handy when dealing with this problem
> >> > for function templates.
> >>
> >> Looks good.
> >>
> >> >> >> @@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
> >> >> >>           /* C++17: A template-argument for a non-type template-parameter shall
> >> >> >>              be a converted constant expression (8.20) of the type of the
> >> >> >>              template-parameter.  */
> >> >> >> +         int errs = errorcount;
> >> >> >>           expr = build_converted_constant_expr (type, expr, complain);
> >> >> >>           if (expr == error_mark_node)
> >> >> >> -           return error_mark_node;
> >> >> >> +           /* Make sure we return NULL_TREE only if we have really issued
> >> >> >> +              an error, as described above.  */
> >> >> >> +           return errorcount > errs ? NULL_TREE : error_mark_node;
> >> >> >
> >> >> > Is this still needed?
> >> >>
> >> >> Earlier you wrote,
> >> >>
> >> >> > Checking complain doesn't work because that doesn't
> >> >> > say if we have really issued an error.  If we have not, and we return
> >> >> > NULL_TREE anyway, we hit this assert:
> >> >> >  8517       gcc_assert (!(complain & tf_error) || seen_error ());
> >> >>
> >> >> If (complain & tf_error), we shouldn't see error_mark_node without an
> >> >> error having been issued.  Why is build_converted_constant_expr
> >> >> returning error_mark_node without giving an error when (complain &
> >> >> tf_error)?
> >> >
> >> > This can happen on invalid code; e.g. tests nontype13.C and crash87.C.
> >> > What happens there is that we're trying to convert a METHOD_TYPE to bool,
> >> > which doesn't work: in standard_conversion we go into the
> >> >     else if (tcode == BOOLEAN_TYPE)
> >> > block, which returns NULL, implicit_conversion also then returns NULL, yet
> >> > no error has been issued.
> >>
> >> Yes, that's normal.  The problem is in build_converted_constant_expr:
> >>
> >>   if (conv)
> >>     expr = convert_like (conv, expr, complain);
> >>   else
> >>     expr = error_mark_node;
> >>
> >> Here when setting expr to error_mark_node I forgot to give an error if
> >> (complain & tf_error).
> >
> > Done.  A few testcases needed adjusting but nothing surprising.
> >
> >> >> >> +      /* If we're in a template and we know the constant value, we can
> >> >> >> +        warn.  Otherwise wait for instantiation.  */
> >> >> >> +      || (processing_template_decl && !TREE_CONSTANT (init)))
> >> >> >
> >> >> > I don't think we want this condition.  If the value is non-constant
> >> >> > but also not dependent, it'll never be constant, so we can go ahead
> >> >> > and complain.
> >> >
> >> > (This to be investigated later.)
> >>
> >> Why later?
> >
> > So this was this wrong error:
> > https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00159.html
> > which was confusing.  But I noticed it's because we instantiate 'size' twice:
> > in compute_array_index_type:
> >   size = instantiate_non_dependent_expr_sfinae (size, complain);
> >   size = build_converted_constant_expr (size_type_node, size, complain);
> >   size = maybe_constant_value (size);
> > and then in check_narrowing:
> >   init = fold_non_dependent_expr (init, complain);
> >
> > (in this case, size is a call to constexpr user-defined conversion).
> >
> > But check_narrowing now returns early if instantiation_dependent_expression_p,
> > so I thought perhaps we could simply call maybe_constant_value which fixes this
> > problem and doesn't regress anything.  Does that seem like a sensible thing
> > to do?
> 
> Hmm, that'll have problems if we pass an unfolded template expression
> to check_narrowing, but probably we don't want to do that anyway.  So
> yes, it seems reasonable.
 
Ok.

> >> > --- gcc/cp/decl.c
> >> > +++ gcc/cp/decl.c
> >> > @@ -9581,7 +9581,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
> >> >      {
> >> >        tree folded = cp_fully_fold (size);
> >> >        if (TREE_CODE (folded) == INTEGER_CST)
> >> > -       pedwarn (location_of (size), OPT_Wpedantic,
> >> > +       pedwarn (input_location, OPT_Wpedantic,
> >>
> >> It should work to use location_of (osize) here.
> >
> > I dropped this hunk altogether.  Because location_of will use
> > DECL_SOURCE_LOCATION for DECLs, the error message will point to the declaration
> > itself, not the use.  I don't really care either way.
> 
> We want the message to point to the use, which location_of (osize)
> will provide, since it should still have a location wrapper around a
> DECL.

location_of (osize) is actually the same as location_of (size) so that didn't
change anything.  The code below uses input_location which is why I went with
it in the first place.  So, should I change this to input_location?

> >           expr = build_converted_constant_expr (type, expr, complain);
> >           if (expr == error_mark_node)
> > -           return error_mark_node;
> > +           /* Make sure we return NULL_TREE only if we have really issued
> > +              an error, as described above.  */
> > +           return (complain & tf_error) ? NULL_TREE : error_mark_node;
> 
> Now that you've fixed build_converted_constant_expr, we shouldn't need
> this hunk.

I think we should keep it; removing would violate the comment of the function
"If the conversion is unsuccessful, return NULL_TREE if we issued an error
message, or error_mark_node if we did not."
and it would also mean emitting redundant errors, which I'd like to avoid.

Seems like we only need to resolve the location thing now.  Thanks,

Marek
Jason Merrill Aug. 13, 2018, 10:14 a.m. UTC | #15
On Sun, Aug 12, 2018 at 2:13 AM, Marek Polacek <polacek@redhat.com> wrote:
> On Sat, Aug 11, 2018 at 11:32:24PM +1200, Jason Merrill wrote:
>> On Fri, Aug 10, 2018 at 8:59 AM, Marek Polacek <polacek@redhat.com> wrote:
>> > On Mon, Aug 06, 2018 at 12:02:31AM +1000, Jason Merrill wrote:
>> >> > OK -- see the patch below.  Now, I'm not crazy about adding another bit
>> >> > to struct conversion, but reusing any of the other bits didn't seem
>> >> > safe/possible.  Maybe it'll come in handy when dealing with this problem
>> >> > for function templates.
>> >>
>> >> Looks good.
>> >>
>> >> >> >> @@ -6669,9 +6669,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
>> >> >> >>           /* C++17: A template-argument for a non-type template-parameter shall
>> >> >> >>              be a converted constant expression (8.20) of the type of the
>> >> >> >>              template-parameter.  */
>> >> >> >> +         int errs = errorcount;
>> >> >> >>           expr = build_converted_constant_expr (type, expr, complain);
>> >> >> >>           if (expr == error_mark_node)
>> >> >> >> -           return error_mark_node;
>> >> >> >> +           /* Make sure we return NULL_TREE only if we have really issued
>> >> >> >> +              an error, as described above.  */
>> >> >> >> +           return errorcount > errs ? NULL_TREE : error_mark_node;
>> >> >> >
>> >> >> > Is this still needed?
>> >> >>
>> >> >> Earlier you wrote,
>> >> >>
>> >> >> > Checking complain doesn't work because that doesn't
>> >> >> > say if we have really issued an error.  If we have not, and we return
>> >> >> > NULL_TREE anyway, we hit this assert:
>> >> >> >  8517       gcc_assert (!(complain & tf_error) || seen_error ());
>> >> >>
>> >> >> If (complain & tf_error), we shouldn't see error_mark_node without an
>> >> >> error having been issued.  Why is build_converted_constant_expr
>> >> >> returning error_mark_node without giving an error when (complain &
>> >> >> tf_error)?
>> >> >
>> >> > This can happen on invalid code; e.g. tests nontype13.C and crash87.C.
>> >> > What happens there is that we're trying to convert a METHOD_TYPE to bool,
>> >> > which doesn't work: in standard_conversion we go into the
>> >> >     else if (tcode == BOOLEAN_TYPE)
>> >> > block, which returns NULL, implicit_conversion also then returns NULL, yet
>> >> > no error has been issued.
>> >>
>> >> Yes, that's normal.  The problem is in build_converted_constant_expr:
>> >>
>> >>   if (conv)
>> >>     expr = convert_like (conv, expr, complain);
>> >>   else
>> >>     expr = error_mark_node;
>> >>
>> >> Here when setting expr to error_mark_node I forgot to give an error if
>> >> (complain & tf_error).
>> >
>> > Done.  A few testcases needed adjusting but nothing surprising.
>> >
>> >> >> >> +      /* If we're in a template and we know the constant value, we can
>> >> >> >> +        warn.  Otherwise wait for instantiation.  */
>> >> >> >> +      || (processing_template_decl && !TREE_CONSTANT (init)))
>> >> >> >
>> >> >> > I don't think we want this condition.  If the value is non-constant
>> >> >> > but also not dependent, it'll never be constant, so we can go ahead
>> >> >> > and complain.
>> >> >
>> >> > (This to be investigated later.)
>> >>
>> >> Why later?
>> >
>> > So this was this wrong error:
>> > https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00159.html
>> > which was confusing.  But I noticed it's because we instantiate 'size' twice:
>> > in compute_array_index_type:
>> >   size = instantiate_non_dependent_expr_sfinae (size, complain);
>> >   size = build_converted_constant_expr (size_type_node, size, complain);
>> >   size = maybe_constant_value (size);
>> > and then in check_narrowing:
>> >   init = fold_non_dependent_expr (init, complain);
>> >
>> > (in this case, size is a call to constexpr user-defined conversion).
>> >
>> > But check_narrowing now returns early if instantiation_dependent_expression_p,
>> > so I thought perhaps we could simply call maybe_constant_value which fixes this
>> > problem and doesn't regress anything.  Does that seem like a sensible thing
>> > to do?
>>
>> Hmm, that'll have problems if we pass an unfolded template expression
>> to check_narrowing, but probably we don't want to do that anyway.  So
>> yes, it seems reasonable.
>
> Ok.
>
>> >> > --- gcc/cp/decl.c
>> >> > +++ gcc/cp/decl.c
>> >> > @@ -9581,7 +9581,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
>> >> >      {
>> >> >        tree folded = cp_fully_fold (size);
>> >> >        if (TREE_CODE (folded) == INTEGER_CST)
>> >> > -       pedwarn (location_of (size), OPT_Wpedantic,
>> >> > +       pedwarn (input_location, OPT_Wpedantic,
>> >>
>> >> It should work to use location_of (osize) here.
>> >
>> > I dropped this hunk altogether.  Because location_of will use
>> > DECL_SOURCE_LOCATION for DECLs, the error message will point to the declaration
>> > itself, not the use.  I don't really care either way.
>>
>> We want the message to point to the use, which location_of (osize)
>> will provide, since it should still have a location wrapper around a
>> DECL.
>
> location_of (osize) is actually the same as location_of (size) so that didn't
> change anything.

Hunh, that's strange.  Why isn't osize the unfolded expression?  Where
is the location wrapper getting stripped?

> The code below uses input_location which is why I went with
> it in the first place.  So, should I change this to input_location?

I suppose so.

>> >           expr = build_converted_constant_expr (type, expr, complain);
>> >           if (expr == error_mark_node)
>> > -           return error_mark_node;
>> > +           /* Make sure we return NULL_TREE only if we have really issued
>> > +              an error, as described above.  */
>> > +           return (complain & tf_error) ? NULL_TREE : error_mark_node;
>>
>> Now that you've fixed build_converted_constant_expr, we shouldn't need
>> this hunk.
>
> I think we should keep it; removing would violate the comment of the function
> "If the conversion is unsuccessful, return NULL_TREE if we issued an error
> message, or error_mark_node if we did not."

Ah, OK.  That convention seems strange to me now, but that's not your
problem.  :)

Jason
Marek Polacek Aug. 13, 2018, 10:24 p.m. UTC | #16
On Mon, Aug 13, 2018 at 10:14:21PM +1200, Jason Merrill wrote:
> >> >> > --- gcc/cp/decl.c
> >> >> > +++ gcc/cp/decl.c
> >> >> > @@ -9581,7 +9581,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
> >> >> >      {
> >> >> >        tree folded = cp_fully_fold (size);
> >> >> >        if (TREE_CODE (folded) == INTEGER_CST)
> >> >> > -       pedwarn (location_of (size), OPT_Wpedantic,
> >> >> > +       pedwarn (input_location, OPT_Wpedantic,
> >> >>
> >> >> It should work to use location_of (osize) here.
> >> >
> >> > I dropped this hunk altogether.  Because location_of will use
> >> > DECL_SOURCE_LOCATION for DECLs, the error message will point to the declaration
> >> > itself, not the use.  I don't really care either way.
> >>
> >> We want the message to point to the use, which location_of (osize)
> >> will provide, since it should still have a location wrapper around a
> >> DECL.
> >
> > location_of (osize) is actually the same as location_of (size) so that didn't
> > change anything.
> 
> Hunh, that's strange.  Why isn't osize the unfolded expression?  Where
> is the location wrapper getting stripped?

I actually see that it didn't have the location wrapper at the start.
The array bound is parsed in cp_parser_direct_new_declarator, and we
never called maybe_wrap_with_location to add the wrapper.  I don't know
where that's supposed to happen.

This quick hack works

--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8681,6 +8681,7 @@ cp_parser_direct_new_declarator (cp_parser* parser)
       cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);

       /* Add this bound to the declarator.  */
+      expression = maybe_wrap_with_location (expression, token->location);
       declarator = make_array_declarator (declarator, expression);

       /* If the next token is not a `[', then there are no more

but that feels too ad-hoc and beyond the scope of this fix.

> > The code below uses input_location which is why I went with
> > it in the first place.  So, should I change this to input_location?
> 
> I suppose so.

Here's the version with input_location.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-08-13  Marek Polacek  <polacek@redhat.com>

	PR c++/57891
	* call.c (struct conversion): Add check_narrowing_const_only.
	(build_converted_constant_expr): Set check_narrowing and
	check_narrowing_const_only.  Give error if expr is error node.
	(convert_like_real): Pass it to check_narrowing.
	* cp-tree.h (check_narrowing): Add a default parameter.
	* decl.c (compute_array_index_type): Use input_location instead of
	location_of.
	* pt.c (convert_nontype_argument): Return NULL_TREE if tf_error.
	* typeck2.c (check_narrowing): Don't warn for instantiation-dependent
	expressions.  Call maybe_constant_value instead of
	fold_non_dependent_expr.  Don't mention { } in diagnostic.  Only check
	narrowing for constants if CONST_ONLY.

	* g++.dg/cpp0x/Wnarrowing6.C: New test.
	* g++.dg/cpp0x/Wnarrowing7.C: New test.
	* g++.dg/cpp0x/Wnarrowing8.C: New test.
	* g++.dg/cpp0x/Wnarrowing9.C: New test.
	* g++.dg/cpp0x/Wnarrowing10.C: New test.

	* g++.dg/cpp0x/constexpr-47969.C: Adjust dg-error.
	* g++.dg/cpp0x/constexpr-ex2.C: Likewise.
	* g++.dg/cpp0x/constexpr-targ.C: Likewise.
	* g++.dg/cpp0x/scoped_enum2.C: Likewise.
	* g++.dg/ext/stmtexpr15.C: Likewise.
	* g++.dg/gomp/pr47963.C: Likewise.
	* g++.dg/init/new37.C: Likewise.
	* g++.dg/init/new43.C: Likewise.
	* g++.dg/other/fold1.C: Likewise.
	* g++.dg/parse/array-size2.C: Likewise.
	* g++.dg/template/dependent-name3.C: Likewise.
	* g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
	* g++.dg/other/vrp1.C: Likewise.
	* g++.dg/template/char1.C: Likewise.

diff --git gcc/cp/call.c gcc/cp/call.c
index 209c1fd2f0e..62654a9e407 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -107,6 +107,9 @@ struct conversion {
      binding a reference directly or decaying to a pointer.  */
   BOOL_BITFIELD rvaluedness_matches_p: 1;
   BOOL_BITFIELD check_narrowing: 1;
+  /* Whether check_narrowing should only check TREE_CONSTANTs; used
+     in build_converted_constant_expr.  */
+  BOOL_BITFIELD check_narrowing_const_only: 1;
   /* The type of the expression resulting from the conversion.  */
   tree type;
   union {
@@ -4152,9 +4155,18 @@ build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
     }
 
   if (conv)
-    expr = convert_like (conv, expr, complain);
+    {
+      conv->check_narrowing = true;
+      conv->check_narrowing_const_only = true;
+      expr = convert_like (conv, expr, complain);
+    }
   else
-    expr = error_mark_node;
+    {
+      if (complain & tf_error)
+	error_at (loc, "could not convert %qE from %qH to %qI", expr,
+		  TREE_TYPE (expr), type);
+      expr = error_mark_node;
+    }
 
   /* Free all the conversions we allocated.  */
   obstack_free (&conversion_obstack, p);
@@ -7142,7 +7154,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
     }
 
   if (convs->check_narrowing
-      && !check_narrowing (totype, expr, complain))
+      && !check_narrowing (totype, expr, complain,
+			   convs->check_narrowing_const_only))
     return error_mark_node;
 
   warning_sentinel w (warn_zero_as_null_pointer_constant);
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index 94a85b72d2b..9608cf5334b 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -7397,7 +7397,8 @@ extern int abstract_virtuals_error_sfinae	(abstract_class_use, tree, tsubst_flag
 
 extern tree store_init_value			(tree, tree, vec<tree, va_gc>**, int);
 extern tree split_nonconstant_init		(tree, tree);
-extern bool check_narrowing			(tree, tree, tsubst_flags_t);
+extern bool check_narrowing			(tree, tree, tsubst_flags_t,
+						 bool = false);
 extern tree digest_init				(tree, tree, tsubst_flags_t);
 extern tree digest_init_flags			(tree, tree, int, tsubst_flags_t);
 extern tree digest_nsdmi_init		        (tree, tree, tsubst_flags_t);
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 97f1cfb792e..9a2e3247946 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -9702,7 +9702,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
     {
       tree folded = cp_fully_fold (size);
       if (TREE_CODE (folded) == INTEGER_CST)
-	pedwarn (location_of (size), OPT_Wpedantic,
+	pedwarn (input_location, OPT_Wpedantic,
 		 "size of array is not an integral constant-expression");
       /* Use the folded result for VLAs, too; it will have resolved
 	 SIZEOF_EXPR.  */
diff --git gcc/cp/pt.c gcc/cp/pt.c
index 7fcf5d6b2d3..cbb7b8ea853 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -6682,7 +6682,9 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 	     template-parameter.  */
 	  expr = build_converted_constant_expr (type, expr, complain);
 	  if (expr == error_mark_node)
-	    return error_mark_node;
+	    /* Make sure we return NULL_TREE only if we have really issued
+	       an error, as described above.  */
+	    return (complain & tf_error) ? NULL_TREE : error_mark_node;
 	  expr = maybe_constant_value (expr);
 	  expr = convert_from_reference (expr);
 	}
diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index 72515d9ece7..674d08762b5 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -875,10 +875,12 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
 }
 
 
-/* Give diagnostic about narrowing conversions within { }.  */
+/* Give diagnostic about narrowing conversions within { }, or as part of
+   a converted constant expression.  If CONST_ONLY, only check
+   constants.  */
 
 bool
-check_narrowing (tree type, tree init, tsubst_flags_t complain)
+check_narrowing (tree type, tree init, tsubst_flags_t complain, bool const_only)
 {
   tree ftype = unlowered_expr_type (init);
   bool ok = true;
@@ -886,7 +888,9 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 
   if (((!warn_narrowing || !(complain & tf_warning))
        && cxx_dialect == cxx98)
-      || !ARITHMETIC_TYPE_P (type))
+      || !ARITHMETIC_TYPE_P (type)
+      /* Don't emit bogus warnings with e.g. value-dependent trees.  */
+      || instantiation_dependent_expression_p (init))
     return ok;
 
   if (BRACE_ENCLOSED_INITIALIZER_P (init)
@@ -902,7 +906,11 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
       return ok;
     }
 
-  init = fold_non_dependent_expr (init, complain);
+  init = maybe_constant_value (init);
+
+  /* If we were asked to only check constants, return early.  */
+  if (const_only && !TREE_CONSTANT (init))
+    return ok;
 
   if (TREE_CODE (type) == INTEGER_TYPE
       && TREE_CODE (ftype) == REAL_TYPE)
@@ -967,7 +975,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	{
 	  if (complain & tf_warning)
 	    warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
-			"from %qH to %qI inside { } is ill-formed in C++11",
+			"from %qH to %qI is ill-formed in C++11",
 			init, ftype, type);
 	  ok = true;
 	}
@@ -977,8 +985,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	    {
 	      if ((!almost_ok || pedantic)
 		  && pedwarn (loc, OPT_Wnarrowing,
-			      "narrowing conversion of %qE "
-			      "from %qH to %qI inside { }",
+			      "narrowing conversion of %qE from %qH to %qI",
 			      init, ftype, type)
 		  && almost_ok)
 		inform (loc, " the expression has a constant value but is not "
@@ -991,8 +998,8 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	  int savederrorcount = errorcount;
 	  global_dc->pedantic_errors = 1;
 	  pedwarn (loc, OPT_Wnarrowing,
-		   "narrowing conversion of %qE from %qH to %qI "
-		   "inside { }", init, ftype, type);
+		   "narrowing conversion of %qE from %qH to %qI ",
+		   init, ftype, type);
 	  if (errorcount == savederrorcount)
 	    ok = true;
 	  global_dc->pedantic_errors = flag_pedantic_errors;
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
index e69de29bb2d..8414b53e342 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
@@ -0,0 +1,5 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+template<int N, unsigned char M = N> struct S { char a[N]; };
+S<1000> s; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
index e69de29bb2d..989d277cd00 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
@@ -0,0 +1,8 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+template<unsigned int> struct A {};
+A<-1> a; // { dg-error "narrowing conversion" }
+
+template<signed char> struct B {};
+B<1000> b; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
index e69de29bb2d..099fdfb7d81 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
@@ -0,0 +1,9 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-narrowing" }
+
+template<unsigned int> struct A {};
+A<-1> a;
+
+template<signed char> struct B {};
+B<1000> b; // { dg-warning "overflow" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
index e69de29bb2d..39c924c9c6c 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
@@ -0,0 +1,6 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+struct X { constexpr operator int () { return 1000; } };
+template<signed char> struct C {};
+C<X{}> c; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
index e69de29bb2d..bc8a736ecb9 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
@@ -0,0 +1,6 @@
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+// N is value-dependent, don't warn.
+template<int N> struct S { char a[N]; }; // { dg-bogus "narrowing conversion" }
+S<1> s;
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
index 933831b94de..201ee17b41b 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
@@ -8,4 +8,4 @@ struct A
 
 constexpr A a = A();
 
-int ar[a]; // { dg-error "has non-integral type" }
+int ar[a]; // { dg-error "could not convert|has non-integral type" }
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
index 898102167de..dee5ed82301 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
@@ -43,4 +43,4 @@ extern template struct A3<int, 510>;
 
 // Use.
 A3<int, 1111> a31;
-A3<char, 9999> a32;		// { dg-warning "overflow" }
+A3<char, 9999> a32;		// { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
index 34b557ce76e..ceae9cb75d3 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
@@ -18,5 +18,5 @@ constexpr A a = 42;
 
 X<a> x;	    // OK: unique conversion to int
 int ar[X<a>::i]; // also OK
-int ary[a]; // { dg-error "ambiguous|conversion|array" } ambiguous conversion
+int ary[a]; // { dg-error "could not convert|ambiguous|conversion|array" } ambiguous conversion
 
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
index 98bb502249a..0f1f113f92f 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
@@ -10,4 +10,4 @@ struct B
 { };
 
 constexpr A a { };
-B<a> b;			 // { dg-error "template argument|converted constant" }
+B<a> b;			 // { dg-error "template argument|converted constant|could not convert" }
diff --git gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
index bb8ad750bd0..456b0daedd1 100644
--- gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
+++ gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
@@ -4,8 +4,8 @@ enum class E { e = 10 };
 enum E2 { e2 = 10 };
 
 struct C {
-  int arr[E::e];    // { dg-error "non-integral type" }
+  int arr[E::e];    // { dg-error "could not convert|non-integral type" }
   int arr2[E2::e2]; // OK
-  int i: E::e;	    // { dg-error "non-integral type" }
+  int i: E::e;	    // { dg-error "could not convert|non-integral type" }
   int i2: E2::e2;   // OK
 };
diff --git gcc/testsuite/g++.dg/ext/stmtexpr15.C gcc/testsuite/g++.dg/ext/stmtexpr15.C
index 83a831cdd4c..1a60a0d3cad 100644
--- gcc/testsuite/g++.dg/ext/stmtexpr15.C
+++ gcc/testsuite/g++.dg/ext/stmtexpr15.C
@@ -3,5 +3,5 @@
 
 void foo()
 {
-  int x[({ return; })];		// { dg-error "non-integral" }
+  int x[({ return; })];		// { dg-error "could not convert|non-integral" }
 }
diff --git gcc/testsuite/g++.dg/gomp/pr47963.C gcc/testsuite/g++.dg/gomp/pr47963.C
index 5b0c60b80a4..6be4c0e18fb 100644
--- gcc/testsuite/g++.dg/gomp/pr47963.C
+++ gcc/testsuite/g++.dg/gomp/pr47963.C
@@ -5,7 +5,7 @@
 void
 foo (float n)
 {
-  int A[n][n];	// { dg-error "has non-integral type|converted constant expression" }
+  int A[n][n];	// { dg-error "could not convert|has non-integral type|converted constant expression" }
 #pragma omp parallel private(A)
   ;
 }
diff --git gcc/testsuite/g++.dg/init/new37.C gcc/testsuite/g++.dg/init/new37.C
index 9ecbfd7903d..2a42fda33dc 100644
--- gcc/testsuite/g++.dg/init/new37.C
+++ gcc/testsuite/g++.dg/init/new37.C
@@ -32,7 +32,7 @@ template <typename T>
 void *
 callnew_fail_3()
 {
-  return new T[2][T::n]; // { dg-error "size of array has non-integral type|converted constant expression" }
+  return new T[2][T::n]; // { dg-error "could not convert|size of array has non-integral type|converted constant expression" }
 }
 
 struct T1 {
diff --git gcc/testsuite/g++.dg/init/new43.C gcc/testsuite/g++.dg/init/new43.C
index 9b0866720fe..aa40b429469 100644
--- gcc/testsuite/g++.dg/init/new43.C
+++ gcc/testsuite/g++.dg/init/new43.C
@@ -31,35 +31,35 @@ void test_literal ()
 
     // Verify integer literal.
     p = new char [-1];           // { dg-error "size of array is negative" }
-    p = new char [2][-3];        // { dg-error "size of array is negative" }
+    p = new char [2][-3];        // { dg-error "size of array|narrowing conversion" }
     p = new char [-4][5];        // { dg-error "size of array is negative" }
-    p = new char [-6][-7];       // { dg-error "size of array is negative" }
+    p = new char [-6][-7];       // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) char [-1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][-3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][-3];    // { dg-error "size of array|narrowing conversion" }
     p = new (p) char [-4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [-6][-7];   // { dg-error "size of array is negative" }
+    p = new (p) char [-6][-7];   // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) A [-1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][-3];       // { dg-error "size of array|narrowing conversion" }
     p = new (p) A [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) A [-6][-7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) B [-1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][-3];       // { dg-error "size of array|narrowing conversion" }
     p = new (p) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) B [-6][-7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new (&b) B [-1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][-3];       // { dg-error "size of array|narrowing conversion" }
     p = new (&b) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [-6][-7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new char [1 - 2];         // { dg-error "size of array is negative" }
     p = new (p) char [2 - 3];     // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? -1 : -2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 - 3 * 2];    // { dg-error "size of array is negative" }
-    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constant_expression ()
@@ -79,35 +79,35 @@ void test_constant_expression ()
 
     // Verify constant expression.
     p = new char [i1];           // { dg-error "size of array is negative" }
-    p = new char [2][i3];        // { dg-error "size of array is negative" }
+    p = new char [2][i3];        // { dg-error "size of array|narrowing conversion" }
     p = new char [i4][5];        // { dg-error "size of array is negative" }
-    p = new char [i6][i7];       // { dg-error "size of array is negative" }
+    p = new char [i6][i7];       // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) char [i1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][i3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][i3];    // { dg-error "size of array|narrowing conversion" }
     p = new (p) char [i4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [i6][i7];   // { dg-error "size of array is negative" }
+    p = new (p) char [i6][i7];   // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) A [i1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][i3];       // { dg-error "size of array|narrowing conversion" }
     p = new (p) A [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) A [i6][i7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) B [i1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][i3];       // { dg-error "size of array|narrowing conversion" }
     p = new (p) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) B [i6][i7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new (&b) B [i1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][i3];       // { dg-error "size of array|narrowing conversion" }
     p = new (&b) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [i6][i7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new short [i1 - 2];       // { dg-error "size of array is negative" }
     p = new (p) bool [i2 - 3];    // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? i1 : i2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 + i3 * 2];   // { dg-error "size of array is negative" }
-    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constexpr ()
@@ -132,33 +132,33 @@ void test_constexpr ()
 
     // Verify constant expression.
     p = new char [s1];           // { dg-error "size of array is negative" }
-    p = new char [2][s3];        // { dg-error "size of array is negative" }
+    p = new char [2][s3];        // { dg-error "size of array|narrowing conversion" }
     p = new char [s4][5];        // { dg-error "size of array is negative" }
-    p = new char [s6][s7];       // { dg-error "size of array is negative" }
+    p = new char [s6][s7];       // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) char [s1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][s3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][s3];    // { dg-error "size of array|narrowing conversion" }
     p = new (p) char [s4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [s6][s7];   // { dg-error "size of array is negative" }
+    p = new (p) char [s6][s7];   // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) A [s1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][s3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][s3];       // { dg-error "size of array|narrowing conversion" }
     p = new (p) A [s4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [s6][s7];      // { dg-error "size of array is negative" }
+    p = new (p) A [s6][s7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new (p) B [s1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][s3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][s3];       // { dg-error "size of array|narrowing conversion" }
     p = new (p) B [s4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [s6][s7];      // { dg-error "size of array is negative" }
+    p = new (p) B [s6][s7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new (&b) B [s1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][s3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][s3];       // { dg-error "size of array|narrowing conversion" }
     p = new (&b) B [s4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [s6][s7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [s6][s7];      // { dg-error "size of array|narrowing conversion" }
 
     p = new int [s1 + s2];           // { dg-error "size of array is negative" }
     p = new (p) long [2 * s3];       // { dg-error "size of array is negative" }
     p = new A [s2 < s1 ? s1 : s2];   // { dg-error "size of array is negative" }
     p = new (p) B [s7 - s2 * 2];     // { dg-error "size of array is negative" }
-    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of array is negative" }
+    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of array|narrowing conversion" }
 }
diff --git gcc/testsuite/g++.dg/other/fold1.C gcc/testsuite/g++.dg/other/fold1.C
index 23d34546e0b..bf074038b04 100644
--- gcc/testsuite/g++.dg/other/fold1.C
+++ gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];		     // { dg-error "constant-expression" }
+    int x[i];		     // { dg-error "constant-expression|narrowing conversion" }
 };
diff --git gcc/testsuite/g++.dg/other/vrp1.C gcc/testsuite/g++.dg/other/vrp1.C
index 0a798c9954e..466a15b4cbb 100644
--- gcc/testsuite/g++.dg/other/vrp1.C
+++ gcc/testsuite/g++.dg/other/vrp1.C
@@ -9,4 +9,4 @@ long long mod (long long l, long long r)
     return 0LL;
   return l % r;
 }
-template long long mod<-0x8000000000000000LL> (long long, long long);
+template long long mod<-0x8000000000000000LL> (long long, long long); // { dg-error "template-id" "" { target { c++11 } } }
diff --git gcc/testsuite/g++.dg/parse/array-size2.C gcc/testsuite/g++.dg/parse/array-size2.C
index d0bc47fe746..997b95eed1a 100644
--- gcc/testsuite/g++.dg/parse/array-size2.C
+++ gcc/testsuite/g++.dg/parse/array-size2.C
@@ -14,7 +14,7 @@ extern void bar (char *, char *);
 void
 foo (void)
 {
-  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" }
+  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant|narrowing conversion" }
   char h[(__SIZE_TYPE__) &((struct S *) 8)->b];	      // { dg-error "constant" }
   bar (g, h);
 }
diff --git gcc/testsuite/g++.dg/template/char1.C gcc/testsuite/g++.dg/template/char1.C
index 51e72e7ad06..a6cffaaf024 100644
--- gcc/testsuite/g++.dg/template/char1.C
+++ gcc/testsuite/g++.dg/template/char1.C
@@ -1,4 +1,5 @@
 template <class CharType, CharType line_terminator = 0>
 class String {};
 
-String<signed char, 255> s;		// { dg-warning "overflow" }
+String<signed char, 255> s;		// { dg-error "narrowing conversion" "" { target c++11 } }
+// { dg-warning "overflow" "" { target c++98_only } .-1 }
diff --git gcc/testsuite/g++.dg/template/dependent-name3.C gcc/testsuite/g++.dg/template/dependent-name3.C
index bbe6fb66266..f9d14055a11 100644
--- gcc/testsuite/g++.dg/template/dependent-name3.C
+++ gcc/testsuite/g++.dg/template/dependent-name3.C
@@ -11,7 +11,7 @@ template<int I> struct A
 template<int N> struct B
 {
   int x[A<N>::zero];       // { dg-error "zero" }
-  int y[A<N>::minus_one];  // { dg-error "negative" }
+  int y[A<N>::minus_one];  // { dg-error "size of array|narrowing conversion" }
 };
 
 B<0> b;

	Marek
Jason Merrill Aug. 13, 2018, 11:02 p.m. UTC | #17
On Tue, Aug 14, 2018, 10:24 AM Marek Polacek <polacek@redhat.com> wrote:

> On Mon, Aug 13, 2018 at 10:14:21PM +1200, Jason Merrill wrote:
> > >> >> > --- gcc/cp/decl.c
> > >> >> > +++ gcc/cp/decl.c
> > >> >> > @@ -9581,7 +9581,7 @@ compute_array_index_type (tree name, tree
> size, tsubst_flags_t complain)
> > >> >> >      {
> > >> >> >        tree folded = cp_fully_fold (size);
> > >> >> >        if (TREE_CODE (folded) == INTEGER_CST)
> > >> >> > -       pedwarn (location_of (size), OPT_Wpedantic,
> > >> >> > +       pedwarn (input_location, OPT_Wpedantic,
> > >> >>
> > >> >> It should work to use location_of (osize) here.
> > >> >
> > >> > I dropped this hunk altogether.  Because location_of will use
> > >> > DECL_SOURCE_LOCATION for DECLs, the error message will point to the
> declaration
> > >> > itself, not the use.  I don't really care either way.
> > >>
> > >> We want the message to point to the use, which location_of (osize)
> > >> will provide, since it should still have a location wrapper around a
> > >> DECL.
> > >
> > > location_of (osize) is actually the same as location_of (size) so that
> didn't
> > > change anything.
> >
> > Hunh, that's strange.  Why isn't osize the unfolded expression?  Where
> > is the location wrapper getting stripped?
>
> I actually see that it didn't have the location wrapper at the start.
> The array bound is parsed in cp_parser_direct_new_declarator, and we
> never called maybe_wrap_with_location to add the wrapper.  I don't know
> where that's supposed to happen.
>
> This quick hack works
>
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -8681,6 +8681,7 @@ cp_parser_direct_new_declarator (cp_parser* parser)
>        cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
>
>        /* Add this bound to the declarator.  */
> +      expression = maybe_wrap_with_location (expression, token->location);
>        declarator = make_array_declarator (declarator, expression);
>
>        /* If the next token is not a `[', then there are no more
>
> but that feels too ad-hoc and beyond the scope of this fix.
>

David, does this look right to you?

> > The code below uses input_location which is why I went with
> > > it in the first place.  So, should I change this to input_location?
> >
> > I suppose so.
>
> Here's the version with input_location.
>
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
>

Ok.

2018-08-13  Marek Polacek  <polacek@redhat.com>
>
>         PR c++/57891
>         * call.c (struct conversion): Add check_narrowing_const_only.
>         (build_converted_constant_expr): Set check_narrowing and
>         check_narrowing_const_only.  Give error if expr is error node.
>         (convert_like_real): Pass it to check_narrowing.
>         * cp-tree.h (check_narrowing): Add a default parameter.
>         * decl.c (compute_array_index_type): Use input_location instead of
>         location_of.
>         * pt.c (convert_nontype_argument): Return NULL_TREE if tf_error.
>         * typeck2.c (check_narrowing): Don't warn for
> instantiation-dependent
>         expressions.  Call maybe_constant_value instead of
>         fold_non_dependent_expr.  Don't mention { } in diagnostic.  Only
> check
>         narrowing for constants if CONST_ONLY.
>
>         * g++.dg/cpp0x/Wnarrowing6.C: New test.
>         * g++.dg/cpp0x/Wnarrowing7.C: New test.
>         * g++.dg/cpp0x/Wnarrowing8.C: New test.
>         * g++.dg/cpp0x/Wnarrowing9.C: New test.
>         * g++.dg/cpp0x/Wnarrowing10.C: New test.
>
>         * g++.dg/cpp0x/constexpr-47969.C: Adjust dg-error.
>         * g++.dg/cpp0x/constexpr-ex2.C: Likewise.
>         * g++.dg/cpp0x/constexpr-targ.C: Likewise.
>         * g++.dg/cpp0x/scoped_enum2.C: Likewise.
>         * g++.dg/ext/stmtexpr15.C: Likewise.
>         * g++.dg/gomp/pr47963.C: Likewise.
>         * g++.dg/init/new37.C: Likewise.
>         * g++.dg/init/new43.C: Likewise.
>         * g++.dg/other/fold1.C: Likewise.
>         * g++.dg/parse/array-size2.C: Likewise.
>         * g++.dg/template/dependent-name3.C: Likewise.
>         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
>         * g++.dg/other/vrp1.C: Likewise.
>         * g++.dg/template/char1.C: Likewise.
>
> diff --git gcc/cp/call.c gcc/cp/call.c
> index 209c1fd2f0e..62654a9e407 100644
> --- gcc/cp/call.c
> +++ gcc/cp/call.c
> @@ -107,6 +107,9 @@ struct conversion {
>       binding a reference directly or decaying to a pointer.  */
>    BOOL_BITFIELD rvaluedness_matches_p: 1;
>    BOOL_BITFIELD check_narrowing: 1;
> +  /* Whether check_narrowing should only check TREE_CONSTANTs; used
> +     in build_converted_constant_expr.  */
> +  BOOL_BITFIELD check_narrowing_const_only: 1;
>    /* The type of the expression resulting from the conversion.  */
>    tree type;
>    union {
> @@ -4152,9 +4155,18 @@ build_converted_constant_expr (tree type, tree
> expr, tsubst_flags_t complain)
>      }
>
>    if (conv)
> -    expr = convert_like (conv, expr, complain);
> +    {
> +      conv->check_narrowing = true;
> +      conv->check_narrowing_const_only = true;
> +      expr = convert_like (conv, expr, complain);
> +    }
>    else
> -    expr = error_mark_node;
> +    {
> +      if (complain & tf_error)
> +       error_at (loc, "could not convert %qE from %qH to %qI", expr,
> +                 TREE_TYPE (expr), type);
> +      expr = error_mark_node;
> +    }
>
>    /* Free all the conversions we allocated.  */
>    obstack_free (&conversion_obstack, p);
> @@ -7142,7 +7154,8 @@ convert_like_real (conversion *convs, tree expr,
> tree fn, int argnum,
>      }
>
>    if (convs->check_narrowing
> -      && !check_narrowing (totype, expr, complain))
> +      && !check_narrowing (totype, expr, complain,
> +                          convs->check_narrowing_const_only))
>      return error_mark_node;
>
>    warning_sentinel w (warn_zero_as_null_pointer_constant);
> diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
> index 94a85b72d2b..9608cf5334b 100644
> --- gcc/cp/cp-tree.h
> +++ gcc/cp/cp-tree.h
> @@ -7397,7 +7397,8 @@ extern int abstract_virtuals_error_sfinae
> (abstract_class_use, tree, tsubst_flag
>
>  extern tree store_init_value                   (tree, tree, vec<tree,
> va_gc>**, int);
>  extern tree split_nonconstant_init             (tree, tree);
> -extern bool check_narrowing                    (tree, tree,
> tsubst_flags_t);
> +extern bool check_narrowing                    (tree, tree,
> tsubst_flags_t,
> +                                                bool = false);
>  extern tree digest_init                                (tree, tree,
> tsubst_flags_t);
>  extern tree digest_init_flags                  (tree, tree, int,
> tsubst_flags_t);
>  extern tree digest_nsdmi_init                  (tree, tree,
> tsubst_flags_t);
> diff --git gcc/cp/decl.c gcc/cp/decl.c
> index 97f1cfb792e..9a2e3247946 100644
> --- gcc/cp/decl.c
> +++ gcc/cp/decl.c
> @@ -9702,7 +9702,7 @@ compute_array_index_type (tree name, tree size,
> tsubst_flags_t complain)
>      {
>        tree folded = cp_fully_fold (size);
>        if (TREE_CODE (folded) == INTEGER_CST)
> -       pedwarn (location_of (size), OPT_Wpedantic,
> +       pedwarn (input_location, OPT_Wpedantic,
>                  "size of array is not an integral constant-expression");
>        /* Use the folded result for VLAs, too; it will have resolved
>          SIZEOF_EXPR.  */
> diff --git gcc/cp/pt.c gcc/cp/pt.c
> index 7fcf5d6b2d3..cbb7b8ea853 100644
> --- gcc/cp/pt.c
> +++ gcc/cp/pt.c
> @@ -6682,7 +6682,9 @@ convert_nontype_argument (tree type, tree expr,
> tsubst_flags_t complain)
>              template-parameter.  */
>           expr = build_converted_constant_expr (type, expr, complain);
>           if (expr == error_mark_node)
> -           return error_mark_node;
> +           /* Make sure we return NULL_TREE only if we have really issued
> +              an error, as described above.  */
> +           return (complain & tf_error) ? NULL_TREE : error_mark_node;
>           expr = maybe_constant_value (expr);
>           expr = convert_from_reference (expr);
>         }
> diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
> index 72515d9ece7..674d08762b5 100644
> --- gcc/cp/typeck2.c
> +++ gcc/cp/typeck2.c
> @@ -875,10 +875,12 @@ store_init_value (tree decl, tree init, vec<tree,
> va_gc>** cleanups, int flags)
>  }
>
>
> -/* Give diagnostic about narrowing conversions within { }.  */
> +/* Give diagnostic about narrowing conversions within { }, or as part of
> +   a converted constant expression.  If CONST_ONLY, only check
> +   constants.  */
>
>  bool
> -check_narrowing (tree type, tree init, tsubst_flags_t complain)
> +check_narrowing (tree type, tree init, tsubst_flags_t complain, bool
> const_only)
>  {
>    tree ftype = unlowered_expr_type (init);
>    bool ok = true;
> @@ -886,7 +888,9 @@ check_narrowing (tree type, tree init, tsubst_flags_t
> complain)
>
>    if (((!warn_narrowing || !(complain & tf_warning))
>         && cxx_dialect == cxx98)
> -      || !ARITHMETIC_TYPE_P (type))
> +      || !ARITHMETIC_TYPE_P (type)
> +      /* Don't emit bogus warnings with e.g. value-dependent trees.  */
> +      || instantiation_dependent_expression_p (init))
>      return ok;
>
>    if (BRACE_ENCLOSED_INITIALIZER_P (init)
> @@ -902,7 +906,11 @@ check_narrowing (tree type, tree init, tsubst_flags_t
> complain)
>        return ok;
>      }
>
> -  init = fold_non_dependent_expr (init, complain);
> +  init = maybe_constant_value (init);
> +
> +  /* If we were asked to only check constants, return early.  */
> +  if (const_only && !TREE_CONSTANT (init))
> +    return ok;
>
>    if (TREE_CODE (type) == INTEGER_TYPE
>        && TREE_CODE (ftype) == REAL_TYPE)
> @@ -967,7 +975,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t
> complain)
>         {
>           if (complain & tf_warning)
>             warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
> -                       "from %qH to %qI inside { } is ill-formed in
> C++11",
> +                       "from %qH to %qI is ill-formed in C++11",
>                         init, ftype, type);
>           ok = true;
>         }
> @@ -977,8 +985,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t
> complain)
>             {
>               if ((!almost_ok || pedantic)
>                   && pedwarn (loc, OPT_Wnarrowing,
> -                             "narrowing conversion of %qE "
> -                             "from %qH to %qI inside { }",
> +                             "narrowing conversion of %qE from %qH to
> %qI",
>                               init, ftype, type)
>                   && almost_ok)
>                 inform (loc, " the expression has a constant value but is
> not "
> @@ -991,8 +998,8 @@ check_narrowing (tree type, tree init, tsubst_flags_t
> complain)
>           int savederrorcount = errorcount;
>           global_dc->pedantic_errors = 1;
>           pedwarn (loc, OPT_Wnarrowing,
> -                  "narrowing conversion of %qE from %qH to %qI "
> -                  "inside { }", init, ftype, type);
> +                  "narrowing conversion of %qE from %qH to %qI ",
> +                  init, ftype, type);
>           if (errorcount == savederrorcount)
>             ok = true;
>           global_dc->pedantic_errors = flag_pedantic_errors;
> diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
> gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
> index e69de29bb2d..8414b53e342 100644
> --- gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
> +++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
> @@ -0,0 +1,5 @@
> +// PR c++/57891
> +// { dg-do compile { target c++11 } }
> +
> +template<int N, unsigned char M = N> struct S { char a[N]; };
> +S<1000> s; // { dg-error "narrowing conversion" }
> diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
> gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
> index e69de29bb2d..989d277cd00 100644
> --- gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
> +++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
> @@ -0,0 +1,8 @@
> +// PR c++/57891
> +// { dg-do compile { target c++11 } }
> +
> +template<unsigned int> struct A {};
> +A<-1> a; // { dg-error "narrowing conversion" }
> +
> +template<signed char> struct B {};
> +B<1000> b; // { dg-error "narrowing conversion" }
> diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
> gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
> index e69de29bb2d..099fdfb7d81 100644
> --- gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
> +++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
> @@ -0,0 +1,9 @@
> +// PR c++/57891
> +// { dg-do compile { target c++11 } }
> +// { dg-options "-Wno-narrowing" }
> +
> +template<unsigned int> struct A {};
> +A<-1> a;
> +
> +template<signed char> struct B {};
> +B<1000> b; // { dg-warning "overflow" }
> diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
> gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
> index e69de29bb2d..39c924c9c6c 100644
> --- gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
> +++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
> @@ -0,0 +1,6 @@
> +// PR c++/57891
> +// { dg-do compile { target c++11 } }
> +
> +struct X { constexpr operator int () { return 1000; } };
> +template<signed char> struct C {};
> +C<X{}> c; // { dg-error "narrowing conversion" }
> diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
> gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
> index e69de29bb2d..bc8a736ecb9 100644
> --- gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
> +++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
> @@ -0,0 +1,6 @@
> +// PR c++/57891
> +// { dg-do compile { target c++11 } }
> +
> +// N is value-dependent, don't warn.
> +template<int N> struct S { char a[N]; }; // { dg-bogus "narrowing
> conversion" }
> +S<1> s;
> diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
> gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
> index 933831b94de..201ee17b41b 100644
> --- gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
> +++ gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
> @@ -8,4 +8,4 @@ struct A
>
>  constexpr A a = A();
>
> -int ar[a]; // { dg-error "has non-integral type" }
> +int ar[a]; // { dg-error "could not convert|has non-integral type" }
> diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
> gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
> index 898102167de..dee5ed82301 100644
> --- gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
> +++ gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
> @@ -43,4 +43,4 @@ extern template struct A3<int, 510>;
>
>  // Use.
>  A3<int, 1111> a31;
> -A3<char, 9999> a32;            // { dg-warning "overflow" }
> +A3<char, 9999> a32;            // { dg-error "narrowing conversion" }
> diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
> gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
> index 34b557ce76e..ceae9cb75d3 100644
> --- gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
> +++ gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
> @@ -18,5 +18,5 @@ constexpr A a = 42;
>
>  X<a> x;            // OK: unique conversion to int
>  int ar[X<a>::i]; // also OK
> -int ary[a]; // { dg-error "ambiguous|conversion|array" } ambiguous
> conversion
> +int ary[a]; // { dg-error "could not convert|ambiguous|conversion|array"
> } ambiguous conversion
>
> diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
> gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
> index 98bb502249a..0f1f113f92f 100644
> --- gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
> +++ gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
> @@ -10,4 +10,4 @@ struct B
>  { };
>
>  constexpr A a { };
> -B<a> b;                         // { dg-error "template
> argument|converted constant" }
> +B<a> b;                         // { dg-error "template
> argument|converted constant|could not convert" }
> diff --git gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
> gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
> index bb8ad750bd0..456b0daedd1 100644
> --- gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
> +++ gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
> @@ -4,8 +4,8 @@ enum class E { e = 10 };
>  enum E2 { e2 = 10 };
>
>  struct C {
> -  int arr[E::e];    // { dg-error "non-integral type" }
> +  int arr[E::e];    // { dg-error "could not convert|non-integral type" }
>    int arr2[E2::e2]; // OK
> -  int i: E::e;     // { dg-error "non-integral type" }
> +  int i: E::e;     // { dg-error "could not convert|non-integral type" }
>    int i2: E2::e2;   // OK
>  };
> diff --git gcc/testsuite/g++.dg/ext/stmtexpr15.C
> gcc/testsuite/g++.dg/ext/stmtexpr15.C
> index 83a831cdd4c..1a60a0d3cad 100644
> --- gcc/testsuite/g++.dg/ext/stmtexpr15.C
> +++ gcc/testsuite/g++.dg/ext/stmtexpr15.C
> @@ -3,5 +3,5 @@
>
>  void foo()
>  {
> -  int x[({ return; })];                // { dg-error "non-integral" }
> +  int x[({ return; })];                // { dg-error "could not
> convert|non-integral" }
>  }
> diff --git gcc/testsuite/g++.dg/gomp/pr47963.C
> gcc/testsuite/g++.dg/gomp/pr47963.C
> index 5b0c60b80a4..6be4c0e18fb 100644
> --- gcc/testsuite/g++.dg/gomp/pr47963.C
> +++ gcc/testsuite/g++.dg/gomp/pr47963.C
> @@ -5,7 +5,7 @@
>  void
>  foo (float n)
>  {
> -  int A[n][n]; // { dg-error "has non-integral type|converted constant
> expression" }
> +  int A[n][n]; // { dg-error "could not convert|has non-integral
> type|converted constant expression" }
>  #pragma omp parallel private(A)
>    ;
>  }
> diff --git gcc/testsuite/g++.dg/init/new37.C
> gcc/testsuite/g++.dg/init/new37.C
> index 9ecbfd7903d..2a42fda33dc 100644
> --- gcc/testsuite/g++.dg/init/new37.C
> +++ gcc/testsuite/g++.dg/init/new37.C
> @@ -32,7 +32,7 @@ template <typename T>
>  void *
>  callnew_fail_3()
>  {
> -  return new T[2][T::n]; // { dg-error "size of array has non-integral
> type|converted constant expression" }
> +  return new T[2][T::n]; // { dg-error "could not convert|size of array
> has non-integral type|converted constant expression" }
>  }
>
>  struct T1 {
> diff --git gcc/testsuite/g++.dg/init/new43.C
> gcc/testsuite/g++.dg/init/new43.C
> index 9b0866720fe..aa40b429469 100644
> --- gcc/testsuite/g++.dg/init/new43.C
> +++ gcc/testsuite/g++.dg/init/new43.C
> @@ -31,35 +31,35 @@ void test_literal ()
>
>      // Verify integer literal.
>      p = new char [-1];           // { dg-error "size of array is
> negative" }
> -    p = new char [2][-3];        // { dg-error "size of array is
> negative" }
> +    p = new char [2][-3];        // { dg-error "size of array|narrowing
> conversion" }
>      p = new char [-4][5];        // { dg-error "size of array is
> negative" }
> -    p = new char [-6][-7];       // { dg-error "size of array is
> negative" }
> +    p = new char [-6][-7];       // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (p) char [-1];       // { dg-error "size of array is
> negative" }
> -    p = new (p) char [2][-3];    // { dg-error "size of array is
> negative" }
> +    p = new (p) char [2][-3];    // { dg-error "size of array|narrowing
> conversion" }
>      p = new (p) char [-4][5];    // { dg-error "size of array is
> negative" }
> -    p = new (p) char [-6][-7];   // { dg-error "size of array is
> negative" }
> +    p = new (p) char [-6][-7];   // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (p) A [-1];          // { dg-error "size of array is
> negative" }
> -    p = new (p) A [2][-3];       // { dg-error "size of array is
> negative" }
> +    p = new (p) A [2][-3];       // { dg-error "size of array|narrowing
> conversion" }
>      p = new (p) A [-4][5];       // { dg-error "size of array is
> negative" }
> -    p = new (p) A [-6][-7];      // { dg-error "size of array is
> negative" }
> +    p = new (p) A [-6][-7];      // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (p) B [-1];          // { dg-error "size of array is
> negative" }
> -    p = new (p) B [2][-3];       // { dg-error "size of array is
> negative" }
> +    p = new (p) B [2][-3];       // { dg-error "size of array|narrowing
> conversion" }
>      p = new (p) B [-4][5];       // { dg-error "size of array is
> negative" }
> -    p = new (p) B [-6][-7];      // { dg-error "size of array is
> negative" }
> +    p = new (p) B [-6][-7];      // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (&b) B [-1];          // { dg-error "size of array is
> negative" }
> -    p = new (&b) B [2][-3];       // { dg-error "size of array is
> negative" }
> +    p = new (&b) B [2][-3];       // { dg-error "size of array|narrowing
> conversion" }
>      p = new (&b) B [-4][5];       // { dg-error "size of array is
> negative" }
> -    p = new (&b) B [-6][-7];      // { dg-error "size of array is
> negative" }
> +    p = new (&b) B [-6][-7];      // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new char [1 - 2];         // { dg-error "size of array is
> negative" }
>      p = new (p) char [2 - 3];     // { dg-error "size of array is
> negative" }
>      p = new A [2 < 1 ? -1 : -2];  // { dg-error "size of array is
> negative" }
>      p = new (p) B [2 - 3 * 2];    // { dg-error "size of array is
> negative" }
> -    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array is
> negative" }
> +    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array|narrowing
> conversion" }
>  }
>
>  void test_constant_expression ()
> @@ -79,35 +79,35 @@ void test_constant_expression ()
>
>      // Verify constant expression.
>      p = new char [i1];           // { dg-error "size of array is
> negative" }
> -    p = new char [2][i3];        // { dg-error "size of array is
> negative" }
> +    p = new char [2][i3];        // { dg-error "size of array|narrowing
> conversion" }
>      p = new char [i4][5];        // { dg-error "size of array is
> negative" }
> -    p = new char [i6][i7];       // { dg-error "size of array is
> negative" }
> +    p = new char [i6][i7];       // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (p) char [i1];       // { dg-error "size of array is
> negative" }
> -    p = new (p) char [2][i3];    // { dg-error "size of array is
> negative" }
> +    p = new (p) char [2][i3];    // { dg-error "size of array|narrowing
> conversion" }
>      p = new (p) char [i4][5];    // { dg-error "size of array is
> negative" }
> -    p = new (p) char [i6][i7];   // { dg-error "size of array is
> negative" }
> +    p = new (p) char [i6][i7];   // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (p) A [i1];          // { dg-error "size of array is
> negative" }
> -    p = new (p) A [2][i3];       // { dg-error "size of array is
> negative" }
> +    p = new (p) A [2][i3];       // { dg-error "size of array|narrowing
> conversion" }
>      p = new (p) A [i4][5];       // { dg-error "size of array is
> negative" }
> -    p = new (p) A [i6][i7];      // { dg-error "size of array is
> negative" }
> +    p = new (p) A [i6][i7];      // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (p) B [i1];          // { dg-error "size of array is
> negative" }
> -    p = new (p) B [2][i3];       // { dg-error "size of array is
> negative" }
> +    p = new (p) B [2][i3];       // { dg-error "size of array|narrowing
> conversion" }
>      p = new (p) B [i4][5];       // { dg-error "size of array is
> negative" }
> -    p = new (p) B [i6][i7];      // { dg-error "size of array is
> negative" }
> +    p = new (p) B [i6][i7];      // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (&b) B [i1];          // { dg-error "size of array is
> negative" }
> -    p = new (&b) B [2][i3];       // { dg-error "size of array is
> negative" }
> +    p = new (&b) B [2][i3];       // { dg-error "size of array|narrowing
> conversion" }
>      p = new (&b) B [i4][5];       // { dg-error "size of array is
> negative" }
> -    p = new (&b) B [i6][i7];      // { dg-error "size of array is
> negative" }
> +    p = new (&b) B [i6][i7];      // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new short [i1 - 2];       // { dg-error "size of array is
> negative" }
>      p = new (p) bool [i2 - 3];    // { dg-error "size of array is
> negative" }
>      p = new A [2 < 1 ? i1 : i2];  // { dg-error "size of array is
> negative" }
>      p = new (p) B [2 + i3 * 2];   // { dg-error "size of array is
> negative" }
> -    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array is
> negative" }
> +    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array|narrowing
> conversion" }
>  }
>
>  void test_constexpr ()
> @@ -132,33 +132,33 @@ void test_constexpr ()
>
>      // Verify constant expression.
>      p = new char [s1];           // { dg-error "size of array is
> negative" }
> -    p = new char [2][s3];        // { dg-error "size of array is
> negative" }
> +    p = new char [2][s3];        // { dg-error "size of array|narrowing
> conversion" }
>      p = new char [s4][5];        // { dg-error "size of array is
> negative" }
> -    p = new char [s6][s7];       // { dg-error "size of array is
> negative" }
> +    p = new char [s6][s7];       // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (p) char [s1];       // { dg-error "size of array is
> negative" }
> -    p = new (p) char [2][s3];    // { dg-error "size of array is
> negative" }
> +    p = new (p) char [2][s3];    // { dg-error "size of array|narrowing
> conversion" }
>      p = new (p) char [s4][5];    // { dg-error "size of array is
> negative" }
> -    p = new (p) char [s6][s7];   // { dg-error "size of array is
> negative" }
> +    p = new (p) char [s6][s7];   // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (p) A [s1];          // { dg-error "size of array is
> negative" }
> -    p = new (p) A [2][s3];       // { dg-error "size of array is
> negative" }
> +    p = new (p) A [2][s3];       // { dg-error "size of array|narrowing
> conversion" }
>      p = new (p) A [s4][5];       // { dg-error "size of array is
> negative" }
> -    p = new (p) A [s6][s7];      // { dg-error "size of array is
> negative" }
> +    p = new (p) A [s6][s7];      // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (p) B [s1];          // { dg-error "size of array is
> negative" }
> -    p = new (p) B [2][s3];       // { dg-error "size of array is
> negative" }
> +    p = new (p) B [2][s3];       // { dg-error "size of array|narrowing
> conversion" }
>      p = new (p) B [s4][5];       // { dg-error "size of array is
> negative" }
> -    p = new (p) B [s6][s7];      // { dg-error "size of array is
> negative" }
> +    p = new (p) B [s6][s7];      // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new (&b) B [s1];          // { dg-error "size of array is
> negative" }
> -    p = new (&b) B [2][s3];       // { dg-error "size of array is
> negative" }
> +    p = new (&b) B [2][s3];       // { dg-error "size of array|narrowing
> conversion" }
>      p = new (&b) B [s4][5];       // { dg-error "size of array is
> negative" }
> -    p = new (&b) B [s6][s7];      // { dg-error "size of array is
> negative" }
> +    p = new (&b) B [s6][s7];      // { dg-error "size of array|narrowing
> conversion" }
>
>      p = new int [s1 + s2];           // { dg-error "size of array is
> negative" }
>      p = new (p) long [2 * s3];       // { dg-error "size of array is
> negative" }
>      p = new A [s2 < s1 ? s1 : s2];   // { dg-error "size of array is
> negative" }
>      p = new (p) B [s7 - s2 * 2];     // { dg-error "size of array is
> negative" }
> -    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of array is
> negative" }
> +    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of
> array|narrowing conversion" }
>  }
> diff --git gcc/testsuite/g++.dg/other/fold1.C
> gcc/testsuite/g++.dg/other/fold1.C
> index 23d34546e0b..bf074038b04 100644
> --- gcc/testsuite/g++.dg/other/fold1.C
> +++ gcc/testsuite/g++.dg/other/fold1.C
> @@ -4,5 +4,5 @@
>  struct A
>  {
>      static const int i = i;  // { dg-error "not declared" }
> -    int x[i];               // { dg-error "constant-expression" }
> +    int x[i];               // { dg-error "constant-expression|narrowing
> conversion" }
>  };
> diff --git gcc/testsuite/g++.dg/other/vrp1.C
> gcc/testsuite/g++.dg/other/vrp1.C
> index 0a798c9954e..466a15b4cbb 100644
> --- gcc/testsuite/g++.dg/other/vrp1.C
> +++ gcc/testsuite/g++.dg/other/vrp1.C
> @@ -9,4 +9,4 @@ long long mod (long long l, long long r)
>      return 0LL;
>    return l % r;
>  }
> -template long long mod<-0x8000000000000000LL> (long long, long long);
> +template long long mod<-0x8000000000000000LL> (long long, long long); //
> { dg-error "template-id" "" { target { c++11 } } }
> diff --git gcc/testsuite/g++.dg/parse/array-size2.C
> gcc/testsuite/g++.dg/parse/array-size2.C
> index d0bc47fe746..997b95eed1a 100644
> --- gcc/testsuite/g++.dg/parse/array-size2.C
> +++ gcc/testsuite/g++.dg/parse/array-size2.C
> @@ -14,7 +14,7 @@ extern void bar (char *, char *);
>  void
>  foo (void)
>  {
> -  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error
> "constant" }
> +  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error
> "constant|narrowing conversion" }
>    char h[(__SIZE_TYPE__) &((struct S *) 8)->b];              // {
> dg-error "constant" }
>    bar (g, h);
>  }
> diff --git gcc/testsuite/g++.dg/template/char1.C
> gcc/testsuite/g++.dg/template/char1.C
> index 51e72e7ad06..a6cffaaf024 100644
> --- gcc/testsuite/g++.dg/template/char1.C
> +++ gcc/testsuite/g++.dg/template/char1.C
> @@ -1,4 +1,5 @@
>  template <class CharType, CharType line_terminator = 0>
>  class String {};
>
> -String<signed char, 255> s;            // { dg-warning "overflow" }
> +String<signed char, 255> s;            // { dg-error "narrowing
> conversion" "" { target c++11 } }
> +// { dg-warning "overflow" "" { target c++98_only } .-1 }
> diff --git gcc/testsuite/g++.dg/template/dependent-name3.C
> gcc/testsuite/g++.dg/template/dependent-name3.C
> index bbe6fb66266..f9d14055a11 100644
> --- gcc/testsuite/g++.dg/template/dependent-name3.C
> +++ gcc/testsuite/g++.dg/template/dependent-name3.C
> @@ -11,7 +11,7 @@ template<int I> struct A
>  template<int N> struct B
>  {
>    int x[A<N>::zero];       // { dg-error "zero" }
> -  int y[A<N>::minus_one];  // { dg-error "negative" }
> +  int y[A<N>::minus_one];  // { dg-error "size of array|narrowing
> conversion" }
>  };
>
>  B<0> b;
>
>         Marek
>
David Malcolm Aug. 14, 2018, 12:58 a.m. UTC | #18
On Tue, 2018-08-14 at 11:02 +1200, Jason Merrill wrote:
> 
> 
> On Tue, Aug 14, 2018, 10:24 AM Marek Polacek <polacek@redhat.com>
> wrote:
> > On Mon, Aug 13, 2018 at 10:14:21PM +1200, Jason Merrill wrote:
> > > >> >> > --- gcc/cp/decl.c
> > > >> >> > +++ gcc/cp/decl.c
> > > >> >> > @@ -9581,7 +9581,7 @@ compute_array_index_type (tree
> > name, tree size, tsubst_flags_t complain)
> > > >> >> >      {
> > > >> >> >        tree folded = cp_fully_fold (size);
> > > >> >> >        if (TREE_CODE (folded) == INTEGER_CST)
> > > >> >> > -       pedwarn (location_of (size), OPT_Wpedantic,
> > > >> >> > +       pedwarn (input_location, OPT_Wpedantic,
> > > >> >>
> > > >> >> It should work to use location_of (osize) here.
> > > >> >
> > > >> > I dropped this hunk altogether.  Because location_of will
> > use
> > > >> > DECL_SOURCE_LOCATION for DECLs, the error message will point
> > to the declaration
> > > >> > itself, not the use.  I don't really care either way.
> > > >>
> > > >> We want the message to point to the use, which location_of
> > (osize)
> > > >> will provide, since it should still have a location wrapper
> > around a
> > > >> DECL.
> > > >
> > > > location_of (osize) is actually the same as location_of (size)
> > so that didn't
> > > > change anything.
> > > 
> > > Hunh, that's strange.  Why isn't osize the unfolded expression? 
> > Where
> > > is the location wrapper getting stripped?
> > 
> > I actually see that it didn't have the location wrapper at the
> > start.
> > The array bound is parsed in cp_parser_direct_new_declarator, and
> > we
> > never called maybe_wrap_with_location to add the wrapper.  I don't
> > know
> > where that's supposed to happen.

Currently we only call maybe_wrap_with_location in a few select places
in the C++ FE: for the arguments of call sites, and a few other places.
 I hope to overhaul this at some point in gcc 9 stage 1, but there may
be a case for adding more special-cases.

> > This quick hack works
> > 
> > --- a/gcc/cp/parser.c
> > +++ b/gcc/cp/parser.c
> > @@ -8681,6 +8681,7 @@ cp_parser_direct_new_declarator (cp_parser*
> > parser)
> >        cp_parser_require (parser, CPP_CLOSE_SQUARE,
> > RT_CLOSE_SQUARE);
> > 
> >        /* Add this bound to the declarator.  */
> > +      expression = maybe_wrap_with_location (expression, token-
> > >location);
> >        declarator = make_array_declarator (declarator, expression);
> > 
> >        /* If the next token is not a `[', then there are no more
> > 
> > but that feels too ad-hoc and beyond the scope of this fix.
> 
> David, does this look right to you?

The usage of token->location struck me as potentially wrong.  There
have been plenty of places in our frontends where we've erroneously
used a token's location for an expression, rather than that of the
whole expression (due to grafting in location ranges in the gcc 6
timeframe); this jumped out at me as maybe one of these cases.

If I'm reading it right, the code is parsing this production:

   direct-new-declarator:
     [ expression ]
     direct-new-declarator [constant-expression]

What's an example of a string that matches this part of the grammar? 
Is it something like the highlighted part of:

  foo = new char[-42];
                ^^^^^

?

We parse the expression here:

      expression = cp_parser_expression (parser);

cp_parser_expression returns a cp_expr, which would implicitly wrap the
location if we have, say a integer constant.  In the example above,
this would capture the location of the constant:

  foo = new char[-42];
                 ^~~

However, we throw away the "on the side" location information since
"expression" is a tree, rather than a cp_expr.

token->location is purely the location of the opening '[' token.  That
sounds like it's also throwing away location information.

What is it that's being parsed, and what should the location be? 

If this is for issuing a diagnostic like:

  error: size of array is negative

then what should the user see?  Presumably something like:

  error: size of array is negative
   foo = new char[-42];
                  ^~~

or:

  error: size of array is negative
   foo = new char[-42];
                 ~^~~~

or somesuch?  For the former, then converting expression to a cp_expr
and adding:

  expression = expression.maybe_add_location_wrapper ();

might work.

I have a patch to overhaul all of this which I'll try to finish and
post (but I'm knee-deep in something else right now).

Hope this is constructive
Dave


> > > > The code below uses input_location which is why I went with
> > > > it in the first place.  So, should I change this to
> > input_location?
> > > 
> > > I suppose so.
> > 
> > Here's the version with input_location.
> > 
> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
> 
> Ok.
> 
> > 2018-08-13  Marek Polacek  <polacek@redhat.com>
> > 
> >         PR c++/57891
> >         * call.c (struct conversion): Add
> > check_narrowing_const_only.
> >         (build_converted_constant_expr): Set check_narrowing and
> >         check_narrowing_const_only.  Give error if expr is error
> > node.
> >         (convert_like_real): Pass it to check_narrowing.
> >         * cp-tree.h (check_narrowing): Add a default parameter.
> >         * decl.c (compute_array_index_type): Use input_location
> > instead of
> >         location_of.
> >         * pt.c (convert_nontype_argument): Return NULL_TREE if
> > tf_error.
> >         * typeck2.c (check_narrowing): Don't warn for
> > instantiation-dependent
> >         expressions.  Call maybe_constant_value instead of
> >         fold_non_dependent_expr.  Don't mention { } in diagnostic. 
> > Only check
> >         narrowing for constants if CONST_ONLY.
> > 
> >         * g++.dg/cpp0x/Wnarrowing6.C: New test.
> >         * g++.dg/cpp0x/Wnarrowing7.C: New test.
> >         * g++.dg/cpp0x/Wnarrowing8.C: New test.
> >         * g++.dg/cpp0x/Wnarrowing9.C: New test.
> >         * g++.dg/cpp0x/Wnarrowing10.C: New test.
> > 
> >         * g++.dg/cpp0x/constexpr-47969.C: Adjust dg-error.
> >         * g++.dg/cpp0x/constexpr-ex2.C: Likewise.
> >         * g++.dg/cpp0x/constexpr-targ.C: Likewise.
> >         * g++.dg/cpp0x/scoped_enum2.C: Likewise.
> >         * g++.dg/ext/stmtexpr15.C: Likewise.
> >         * g++.dg/gomp/pr47963.C: Likewise.
> >         * g++.dg/init/new37.C: Likewise.
> >         * g++.dg/init/new43.C: Likewise.
> >         * g++.dg/other/fold1.C: Likewise.
> >         * g++.dg/parse/array-size2.C: Likewise.
> >         * g++.dg/template/dependent-name3.C: Likewise.
> >         * g++.dg/cpp0x/constexpr-data2.C: Add dg-error.
> >         * g++.dg/other/vrp1.C: Likewise.
> >         * g++.dg/template/char1.C: Likewise.
> > 
> > diff --git gcc/cp/call.c gcc/cp/call.c
> > index 209c1fd2f0e..62654a9e407 100644
> > --- gcc/cp/call.c
> > +++ gcc/cp/call.c
> > @@ -107,6 +107,9 @@ struct conversion {
> >       binding a reference directly or decaying to a pointer.  */
> >    BOOL_BITFIELD rvaluedness_matches_p: 1;
> >    BOOL_BITFIELD check_narrowing: 1;
> > +  /* Whether check_narrowing should only check TREE_CONSTANTs;
> > used
> > +     in build_converted_constant_expr.  */
> > +  BOOL_BITFIELD check_narrowing_const_only: 1;
> >    /* The type of the expression resulting from the conversion.  */
> >    tree type;
> >    union {
> > @@ -4152,9 +4155,18 @@ build_converted_constant_expr (tree type,
> > tree expr, tsubst_flags_t complain)
> >      }
> > 
> >    if (conv)
> > -    expr = convert_like (conv, expr, complain);
> > +    {
> > +      conv->check_narrowing = true;
> > +      conv->check_narrowing_const_only = true;
> > +      expr = convert_like (conv, expr, complain);
> > +    }
> >    else
> > -    expr = error_mark_node;
> > +    {
> > +      if (complain & tf_error)
> > +       error_at (loc, "could not convert %qE from %qH to %qI",
> > expr,
> > +                 TREE_TYPE (expr), type);
> > +      expr = error_mark_node;
> > +    }
> > 
> >    /* Free all the conversions we allocated.  */
> >    obstack_free (&conversion_obstack, p);
> > @@ -7142,7 +7154,8 @@ convert_like_real (conversion *convs, tree
> > expr, tree fn, int argnum,
> >      }
> > 
> >    if (convs->check_narrowing
> > -      && !check_narrowing (totype, expr, complain))
> > +      && !check_narrowing (totype, expr, complain,
> > +                          convs->check_narrowing_const_only))
> >      return error_mark_node;
> > 
> >    warning_sentinel w (warn_zero_as_null_pointer_constant);
> > diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
> > index 94a85b72d2b..9608cf5334b 100644
> > --- gcc/cp/cp-tree.h
> > +++ gcc/cp/cp-tree.h
> > @@ -7397,7 +7397,8 @@ extern int abstract_virtuals_error_sfinae
> > (abstract_class_use, tree, tsubst_flag
> > 
> >  extern tree store_init_value                   (tree, tree,
> > vec<tree, va_gc>**, int);
> >  extern tree split_nonconstant_init             (tree, tree);
> > -extern bool check_narrowing                    (tree, tree,
> > tsubst_flags_t);
> > +extern bool check_narrowing                    (tree, tree,
> > tsubst_flags_t,
> > +                                                bool = false);
> >  extern tree digest_init                                (tree,
> > tree, tsubst_flags_t);
> >  extern tree digest_init_flags                  (tree, tree, int,
> > tsubst_flags_t);
> >  extern tree digest_nsdmi_init                  (tree, tree,
> > tsubst_flags_t);
> > diff --git gcc/cp/decl.c gcc/cp/decl.c
> > index 97f1cfb792e..9a2e3247946 100644
> > --- gcc/cp/decl.c
> > +++ gcc/cp/decl.c
> > @@ -9702,7 +9702,7 @@ compute_array_index_type (tree name, tree
> > size, tsubst_flags_t complain)
> >      {
> >        tree folded = cp_fully_fold (size);
> >        if (TREE_CODE (folded) == INTEGER_CST)
> > -       pedwarn (location_of (size), OPT_Wpedantic,
> > +       pedwarn (input_location, OPT_Wpedantic,
> >                  "size of array is not an integral constant-
> > expression");
> >        /* Use the folded result for VLAs, too; it will have
> > resolved
> >          SIZEOF_EXPR.  */
> > diff --git gcc/cp/pt.c gcc/cp/pt.c
> > index 7fcf5d6b2d3..cbb7b8ea853 100644
> > --- gcc/cp/pt.c
> > +++ gcc/cp/pt.c
> > @@ -6682,7 +6682,9 @@ convert_nontype_argument (tree type, tree
> > expr, tsubst_flags_t complain)
> >              template-parameter.  */
> >           expr = build_converted_constant_expr (type, expr,
> > complain);
> >           if (expr == error_mark_node)
> > -           return error_mark_node;
> > +           /* Make sure we return NULL_TREE only if we have really
> > issued
> > +              an error, as described above.  */
> > +           return (complain & tf_error) ? NULL_TREE :
> > error_mark_node;
> >           expr = maybe_constant_value (expr);
> >           expr = convert_from_reference (expr);
> >         }
> > diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
> > index 72515d9ece7..674d08762b5 100644
> > --- gcc/cp/typeck2.c
> > +++ gcc/cp/typeck2.c
> > @@ -875,10 +875,12 @@ store_init_value (tree decl, tree init,
> > vec<tree, va_gc>** cleanups, int flags)
> >  }
> > 
> > 
> > -/* Give diagnostic about narrowing conversions within { }.  */
> > +/* Give diagnostic about narrowing conversions within { }, or as
> > part of
> > +   a converted constant expression.  If CONST_ONLY, only check
> > +   constants.  */
> > 
> >  bool
> > -check_narrowing (tree type, tree init, tsubst_flags_t complain)
> > +check_narrowing (tree type, tree init, tsubst_flags_t complain,
> > bool const_only)
> >  {
> >    tree ftype = unlowered_expr_type (init);
> >    bool ok = true;
> > @@ -886,7 +888,9 @@ check_narrowing (tree type, tree init,
> > tsubst_flags_t complain)
> > 
> >    if (((!warn_narrowing || !(complain & tf_warning))
> >         && cxx_dialect == cxx98)
> > -      || !ARITHMETIC_TYPE_P (type))
> > +      || !ARITHMETIC_TYPE_P (type)
> > +      /* Don't emit bogus warnings with e.g. value-dependent
> > trees.  */
> > +      || instantiation_dependent_expression_p (init))
> >      return ok;
> > 
> >    if (BRACE_ENCLOSED_INITIALIZER_P (init)
> > @@ -902,7 +906,11 @@ check_narrowing (tree type, tree init,
> > tsubst_flags_t complain)
> >        return ok;
> >      }
> > 
> > -  init = fold_non_dependent_expr (init, complain);
> > +  init = maybe_constant_value (init);
> > +
> > +  /* If we were asked to only check constants, return early.  */
> > +  if (const_only && !TREE_CONSTANT (init))
> > +    return ok;
> > 
> >    if (TREE_CODE (type) == INTEGER_TYPE
> >        && TREE_CODE (ftype) == REAL_TYPE)
> > @@ -967,7 +975,7 @@ check_narrowing (tree type, tree init,
> > tsubst_flags_t complain)
> >         {
> >           if (complain & tf_warning)
> >             warning_at (loc, OPT_Wnarrowing, "narrowing conversion
> > of %qE "
> > -                       "from %qH to %qI inside { } is ill-formed
> > in C++11",
> > +                       "from %qH to %qI is ill-formed in C++11",
> >                         init, ftype, type);
> >           ok = true;
> >         }
> > @@ -977,8 +985,7 @@ check_narrowing (tree type, tree init,
> > tsubst_flags_t complain)
> >             {
> >               if ((!almost_ok || pedantic)
> >                   && pedwarn (loc, OPT_Wnarrowing,
> > -                             "narrowing conversion of %qE "
> > -                             "from %qH to %qI inside { }",
> > +                             "narrowing conversion of %qE from %qH
> > to %qI",
> >                               init, ftype, type)
> >                   && almost_ok)
> >                 inform (loc, " the expression has a constant value
> > but is not "
> > @@ -991,8 +998,8 @@ check_narrowing (tree type, tree init,
> > tsubst_flags_t complain)
> >           int savederrorcount = errorcount;
> >           global_dc->pedantic_errors = 1;
> >           pedwarn (loc, OPT_Wnarrowing,
> > -                  "narrowing conversion of %qE from %qH to %qI "
> > -                  "inside { }", init, ftype, type);
> > +                  "narrowing conversion of %qE from %qH to %qI ",
> > +                  init, ftype, type);
> >           if (errorcount == savederrorcount)
> >             ok = true;
> >           global_dc->pedantic_errors = flag_pedantic_errors;
> > diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
> > gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
> > index e69de29bb2d..8414b53e342 100644
> > --- gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
> > +++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing10.C
> > @@ -0,0 +1,5 @@
> > +// PR c++/57891
> > +// { dg-do compile { target c++11 } }
> > +
> > +template<int N, unsigned char M = N> struct S { char a[N]; };
> > +S<1000> s; // { dg-error "narrowing conversion" }
> > diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
> > gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
> > index e69de29bb2d..989d277cd00 100644
> > --- gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
> > +++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
> > @@ -0,0 +1,8 @@
> > +// PR c++/57891
> > +// { dg-do compile { target c++11 } }
> > +
> > +template<unsigned int> struct A {};
> > +A<-1> a; // { dg-error "narrowing conversion" }
> > +
> > +template<signed char> struct B {};
> > +B<1000> b; // { dg-error "narrowing conversion" }
> > diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
> > gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
> > index e69de29bb2d..099fdfb7d81 100644
> > --- gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
> > +++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
> > @@ -0,0 +1,9 @@
> > +// PR c++/57891
> > +// { dg-do compile { target c++11 } }
> > +// { dg-options "-Wno-narrowing" }
> > +
> > +template<unsigned int> struct A {};
> > +A<-1> a;
> > +
> > +template<signed char> struct B {};
> > +B<1000> b; // { dg-warning "overflow" }
> > diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
> > gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
> > index e69de29bb2d..39c924c9c6c 100644
> > --- gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
> > +++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
> > @@ -0,0 +1,6 @@
> > +// PR c++/57891
> > +// { dg-do compile { target c++11 } }
> > +
> > +struct X { constexpr operator int () { return 1000; } };
> > +template<signed char> struct C {};
> > +C<X{}> c; // { dg-error "narrowing conversion" }
> > diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
> > gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
> > index e69de29bb2d..bc8a736ecb9 100644
> > --- gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
> > +++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing9.C
> > @@ -0,0 +1,6 @@
> > +// PR c++/57891
> > +// { dg-do compile { target c++11 } }
> > +
> > +// N is value-dependent, don't warn.
> > +template<int N> struct S { char a[N]; }; // { dg-bogus "narrowing
> > conversion" }
> > +S<1> s;
> > diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
> > gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
> > index 933831b94de..201ee17b41b 100644
> > --- gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
> > +++ gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
> > @@ -8,4 +8,4 @@ struct A
> > 
> >  constexpr A a = A();
> > 
> > -int ar[a]; // { dg-error "has non-integral type" }
> > +int ar[a]; // { dg-error "could not convert|has non-integral type"
> > }
> > diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
> > gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
> > index 898102167de..dee5ed82301 100644
> > --- gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
> > +++ gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
> > @@ -43,4 +43,4 @@ extern template struct A3<int, 510>;
> > 
> >  // Use.
> >  A3<int, 1111> a31;
> > -A3<char, 9999> a32;            // { dg-warning "overflow" }
> > +A3<char, 9999> a32;            // { dg-error "narrowing
> > conversion" }
> > diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
> > gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
> > index 34b557ce76e..ceae9cb75d3 100644
> > --- gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
> > +++ gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
> > @@ -18,5 +18,5 @@ constexpr A a = 42;
> > 
> >  X<a> x;            // OK: unique conversion to int
> >  int ar[X<a>::i]; // also OK
> > -int ary[a]; // { dg-error "ambiguous|conversion|array" } ambiguous
> > conversion
> > +int ary[a]; // { dg-error "could not
> > convert|ambiguous|conversion|array" } ambiguous conversion
> > 
> > diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
> > gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
> > index 98bb502249a..0f1f113f92f 100644
> > --- gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
> > +++ gcc/testsuite/g++.dg/cpp0x/constexpr-targ.C
> > @@ -10,4 +10,4 @@ struct B
> >  { };
> > 
> >  constexpr A a { };
> > -B<a> b;                         // { dg-error "template
> > argument|converted constant" }
> > +B<a> b;                         // { dg-error "template
> > argument|converted constant|could not convert" }
> > diff --git gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
> > gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
> > index bb8ad750bd0..456b0daedd1 100644
> > --- gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
> > +++ gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
> > @@ -4,8 +4,8 @@ enum class E { e = 10 };
> >  enum E2 { e2 = 10 };
> > 
> >  struct C {
> > -  int arr[E::e];    // { dg-error "non-integral type" }
> > +  int arr[E::e];    // { dg-error "could not convert|non-integral
> > type" }
> >    int arr2[E2::e2]; // OK
> > -  int i: E::e;     // { dg-error "non-integral type" }
> > +  int i: E::e;     // { dg-error "could not convert|non-integral
> > type" }
> >    int i2: E2::e2;   // OK
> >  };
> > diff --git gcc/testsuite/g++.dg/ext/stmtexpr15.C
> > gcc/testsuite/g++.dg/ext/stmtexpr15.C
> > index 83a831cdd4c..1a60a0d3cad 100644
> > --- gcc/testsuite/g++.dg/ext/stmtexpr15.C
> > +++ gcc/testsuite/g++.dg/ext/stmtexpr15.C
> > @@ -3,5 +3,5 @@
> > 
> >  void foo()
> >  {
> > -  int x[({ return; })];                // { dg-error "non-
> > integral" }
> > +  int x[({ return; })];                // { dg-error "could not
> > convert|non-integral" }
> >  }
> > diff --git gcc/testsuite/g++.dg/gomp/pr47963.C
> > gcc/testsuite/g++.dg/gomp/pr47963.C
> > index 5b0c60b80a4..6be4c0e18fb 100644
> > --- gcc/testsuite/g++.dg/gomp/pr47963.C
> > +++ gcc/testsuite/g++.dg/gomp/pr47963.C
> > @@ -5,7 +5,7 @@
> >  void
> >  foo (float n)
> >  {
> > -  int A[n][n]; // { dg-error "has non-integral type|converted
> > constant expression" }
> > +  int A[n][n]; // { dg-error "could not convert|has non-integral
> > type|converted constant expression" }
> >  #pragma omp parallel private(A)
> >    ;
> >  }
> > diff --git gcc/testsuite/g++.dg/init/new37.C
> > gcc/testsuite/g++.dg/init/new37.C
> > index 9ecbfd7903d..2a42fda33dc 100644
> > --- gcc/testsuite/g++.dg/init/new37.C
> > +++ gcc/testsuite/g++.dg/init/new37.C
> > @@ -32,7 +32,7 @@ template <typename T>
> >  void *
> >  callnew_fail_3()
> >  {
> > -  return new T[2][T::n]; // { dg-error "size of array has non-
> > integral type|converted constant expression" }
> > +  return new T[2][T::n]; // { dg-error "could not convert|size of
> > array has non-integral type|converted constant expression" }
> >  }
> > 
> >  struct T1 {
> > diff --git gcc/testsuite/g++.dg/init/new43.C
> > gcc/testsuite/g++.dg/init/new43.C
> > index 9b0866720fe..aa40b429469 100644
> > --- gcc/testsuite/g++.dg/init/new43.C
> > +++ gcc/testsuite/g++.dg/init/new43.C
> > @@ -31,35 +31,35 @@ void test_literal ()
> > 
> >      // Verify integer literal.
> >      p = new char [-1];           // { dg-error "size of array is
> > negative" }
> > -    p = new char [2][-3];        // { dg-error "size of array is
> > negative" }
> > +    p = new char [2][-3];        // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new char [-4][5];        // { dg-error "size of array is
> > negative" }
> > -    p = new char [-6][-7];       // { dg-error "size of array is
> > negative" }
> > +    p = new char [-6][-7];       // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (p) char [-1];       // { dg-error "size of array is
> > negative" }
> > -    p = new (p) char [2][-3];    // { dg-error "size of array is
> > negative" }
> > +    p = new (p) char [2][-3];    // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (p) char [-4][5];    // { dg-error "size of array is
> > negative" }
> > -    p = new (p) char [-6][-7];   // { dg-error "size of array is
> > negative" }
> > +    p = new (p) char [-6][-7];   // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (p) A [-1];          // { dg-error "size of array is
> > negative" }
> > -    p = new (p) A [2][-3];       // { dg-error "size of array is
> > negative" }
> > +    p = new (p) A [2][-3];       // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (p) A [-4][5];       // { dg-error "size of array is
> > negative" }
> > -    p = new (p) A [-6][-7];      // { dg-error "size of array is
> > negative" }
> > +    p = new (p) A [-6][-7];      // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (p) B [-1];          // { dg-error "size of array is
> > negative" }
> > -    p = new (p) B [2][-3];       // { dg-error "size of array is
> > negative" }
> > +    p = new (p) B [2][-3];       // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (p) B [-4][5];       // { dg-error "size of array is
> > negative" }
> > -    p = new (p) B [-6][-7];      // { dg-error "size of array is
> > negative" }
> > +    p = new (p) B [-6][-7];      // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (&b) B [-1];          // { dg-error "size of array is
> > negative" }
> > -    p = new (&b) B [2][-3];       // { dg-error "size of array is
> > negative" }
> > +    p = new (&b) B [2][-3];       // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (&b) B [-4][5];       // { dg-error "size of array is
> > negative" }
> > -    p = new (&b) B [-6][-7];      // { dg-error "size of array is
> > negative" }
> > +    p = new (&b) B [-6][-7];      // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new char [1 - 2];         // { dg-error "size of array is
> > negative" }
> >      p = new (p) char [2 - 3];     // { dg-error "size of array is
> > negative" }
> >      p = new A [2 < 1 ? -1 : -2];  // { dg-error "size of array is
> > negative" }
> >      p = new (p) B [2 - 3 * 2];    // { dg-error "size of array is
> > negative" }
> > -    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array is
> > negative" }
> > +    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of
> > array|narrowing conversion" }
> >  }
> > 
> >  void test_constant_expression ()
> > @@ -79,35 +79,35 @@ void test_constant_expression ()
> > 
> >      // Verify constant expression.
> >      p = new char [i1];           // { dg-error "size of array is
> > negative" }
> > -    p = new char [2][i3];        // { dg-error "size of array is
> > negative" }
> > +    p = new char [2][i3];        // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new char [i4][5];        // { dg-error "size of array is
> > negative" }
> > -    p = new char [i6][i7];       // { dg-error "size of array is
> > negative" }
> > +    p = new char [i6][i7];       // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (p) char [i1];       // { dg-error "size of array is
> > negative" }
> > -    p = new (p) char [2][i3];    // { dg-error "size of array is
> > negative" }
> > +    p = new (p) char [2][i3];    // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (p) char [i4][5];    // { dg-error "size of array is
> > negative" }
> > -    p = new (p) char [i6][i7];   // { dg-error "size of array is
> > negative" }
> > +    p = new (p) char [i6][i7];   // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (p) A [i1];          // { dg-error "size of array is
> > negative" }
> > -    p = new (p) A [2][i3];       // { dg-error "size of array is
> > negative" }
> > +    p = new (p) A [2][i3];       // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (p) A [i4][5];       // { dg-error "size of array is
> > negative" }
> > -    p = new (p) A [i6][i7];      // { dg-error "size of array is
> > negative" }
> > +    p = new (p) A [i6][i7];      // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (p) B [i1];          // { dg-error "size of array is
> > negative" }
> > -    p = new (p) B [2][i3];       // { dg-error "size of array is
> > negative" }
> > +    p = new (p) B [2][i3];       // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (p) B [i4][5];       // { dg-error "size of array is
> > negative" }
> > -    p = new (p) B [i6][i7];      // { dg-error "size of array is
> > negative" }
> > +    p = new (p) B [i6][i7];      // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (&b) B [i1];          // { dg-error "size of array is
> > negative" }
> > -    p = new (&b) B [2][i3];       // { dg-error "size of array is
> > negative" }
> > +    p = new (&b) B [2][i3];       // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (&b) B [i4][5];       // { dg-error "size of array is
> > negative" }
> > -    p = new (&b) B [i6][i7];      // { dg-error "size of array is
> > negative" }
> > +    p = new (&b) B [i6][i7];      // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new short [i1 - 2];       // { dg-error "size of array is
> > negative" }
> >      p = new (p) bool [i2 - 3];    // { dg-error "size of array is
> > negative" }
> >      p = new A [2 < 1 ? i1 : i2];  // { dg-error "size of array is
> > negative" }
> >      p = new (p) B [2 + i3 * 2];   // { dg-error "size of array is
> > negative" }
> > -    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array is
> > negative" }
> > +    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of
> > array|narrowing conversion" }
> >  }
> > 
> >  void test_constexpr ()
> > @@ -132,33 +132,33 @@ void test_constexpr ()
> > 
> >      // Verify constant expression.
> >      p = new char [s1];           // { dg-error "size of array is
> > negative" }
> > -    p = new char [2][s3];        // { dg-error "size of array is
> > negative" }
> > +    p = new char [2][s3];        // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new char [s4][5];        // { dg-error "size of array is
> > negative" }
> > -    p = new char [s6][s7];       // { dg-error "size of array is
> > negative" }
> > +    p = new char [s6][s7];       // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (p) char [s1];       // { dg-error "size of array is
> > negative" }
> > -    p = new (p) char [2][s3];    // { dg-error "size of array is
> > negative" }
> > +    p = new (p) char [2][s3];    // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (p) char [s4][5];    // { dg-error "size of array is
> > negative" }
> > -    p = new (p) char [s6][s7];   // { dg-error "size of array is
> > negative" }
> > +    p = new (p) char [s6][s7];   // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (p) A [s1];          // { dg-error "size of array is
> > negative" }
> > -    p = new (p) A [2][s3];       // { dg-error "size of array is
> > negative" }
> > +    p = new (p) A [2][s3];       // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (p) A [s4][5];       // { dg-error "size of array is
> > negative" }
> > -    p = new (p) A [s6][s7];      // { dg-error "size of array is
> > negative" }
> > +    p = new (p) A [s6][s7];      // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (p) B [s1];          // { dg-error "size of array is
> > negative" }
> > -    p = new (p) B [2][s3];       // { dg-error "size of array is
> > negative" }
> > +    p = new (p) B [2][s3];       // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (p) B [s4][5];       // { dg-error "size of array is
> > negative" }
> > -    p = new (p) B [s6][s7];      // { dg-error "size of array is
> > negative" }
> > +    p = new (p) B [s6][s7];      // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new (&b) B [s1];          // { dg-error "size of array is
> > negative" }
> > -    p = new (&b) B [2][s3];       // { dg-error "size of array is
> > negative" }
> > +    p = new (&b) B [2][s3];       // { dg-error "size of
> > array|narrowing conversion" }
> >      p = new (&b) B [s4][5];       // { dg-error "size of array is
> > negative" }
> > -    p = new (&b) B [s6][s7];      // { dg-error "size of array is
> > negative" }
> > +    p = new (&b) B [s6][s7];      // { dg-error "size of
> > array|narrowing conversion" }
> > 
> >      p = new int [s1 + s2];           // { dg-error "size of array
> > is negative" }
> >      p = new (p) long [2 * s3];       // { dg-error "size of array
> > is negative" }
> >      p = new A [s2 < s1 ? s1 : s2];   // { dg-error "size of array
> > is negative" }
> >      p = new (p) B [s7 - s2 * 2];     // { dg-error "size of array
> > is negative" }
> > -    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of array
> > is negative" }
> > +    p = new (&b) B [9][s4 - s1 * 2]; // { dg-error "size of
> > array|narrowing conversion" }
> >  }
> > diff --git gcc/testsuite/g++.dg/other/fold1.C
> > gcc/testsuite/g++.dg/other/fold1.C
> > index 23d34546e0b..bf074038b04 100644
> > --- gcc/testsuite/g++.dg/other/fold1.C
> > +++ gcc/testsuite/g++.dg/other/fold1.C
> > @@ -4,5 +4,5 @@
> >  struct A
> >  {
> >      static const int i = i;  // { dg-error "not declared" }
> > -    int x[i];               // { dg-error "constant-expression" }
> > +    int x[i];               // { dg-error "constant-
> > expression|narrowing conversion" }
> >  };
> > diff --git gcc/testsuite/g++.dg/other/vrp1.C
> > gcc/testsuite/g++.dg/other/vrp1.C
> > index 0a798c9954e..466a15b4cbb 100644
> > --- gcc/testsuite/g++.dg/other/vrp1.C
> > +++ gcc/testsuite/g++.dg/other/vrp1.C
> > @@ -9,4 +9,4 @@ long long mod (long long l, long long r)
> >      return 0LL;
> >    return l % r;
> >  }
> > -template long long mod<-0x8000000000000000LL> (long long, long
> > long);
> > +template long long mod<-0x8000000000000000LL> (long long, long
> > long); // { dg-error "template-id" "" { target { c++11 } } }
> > diff --git gcc/testsuite/g++.dg/parse/array-size2.C
> > gcc/testsuite/g++.dg/parse/array-size2.C
> > index d0bc47fe746..997b95eed1a 100644
> > --- gcc/testsuite/g++.dg/parse/array-size2.C
> > +++ gcc/testsuite/g++.dg/parse/array-size2.C
> > @@ -14,7 +14,7 @@ extern void bar (char *, char *);
> >  void
> >  foo (void)
> >  {
> > -  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-
> > error "constant" }
> > +  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-
> > error "constant|narrowing conversion" }
> >    char h[(__SIZE_TYPE__) &((struct S *) 8)->b];              // {
> > dg-error "constant" }
> >    bar (g, h);
> >  }
> > diff --git gcc/testsuite/g++.dg/template/char1.C
> > gcc/testsuite/g++.dg/template/char1.C
> > index 51e72e7ad06..a6cffaaf024 100644
> > --- gcc/testsuite/g++.dg/template/char1.C
> > +++ gcc/testsuite/g++.dg/template/char1.C
> > @@ -1,4 +1,5 @@
> >  template <class CharType, CharType line_terminator = 0>
> >  class String {};
> > 
> > -String<signed char, 255> s;            // { dg-warning "overflow"
> > }
> > +String<signed char, 255> s;            // { dg-error "narrowing
> > conversion" "" { target c++11 } }
> > +// { dg-warning "overflow" "" { target c++98_only } .-1 }
> > diff --git gcc/testsuite/g++.dg/template/dependent-name3.C
> > gcc/testsuite/g++.dg/template/dependent-name3.C
> > index bbe6fb66266..f9d14055a11 100644
> > --- gcc/testsuite/g++.dg/template/dependent-name3.C
> > +++ gcc/testsuite/g++.dg/template/dependent-name3.C
> > @@ -11,7 +11,7 @@ template<int I> struct A
> >  template<int N> struct B
> >  {
> >    int x[A<N>::zero];       // { dg-error "zero" }
> > -  int y[A<N>::minus_one];  // { dg-error "negative" }
> > +  int y[A<N>::minus_one];  // { dg-error "size of array|narrowing
> > conversion" }
> >  };
> > 
> >  B<0> b;
> > 
> >         Marek
Jason Merrill Sept. 7, 2018, 12:40 p.m. UTC | #19
On Mon, Aug 13, 2018 at 11:24 PM, Marek Polacek <polacek@redhat.com> wrote:
> On Mon, Aug 13, 2018 at 10:14:21PM +1200, Jason Merrill wrote:
>> >> >> > --- gcc/cp/decl.c
>> >> >> > +++ gcc/cp/decl.c
>> >> >> > @@ -9581,7 +9581,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
>> >> >> >      {
>> >> >> >        tree folded = cp_fully_fold (size);
>> >> >> >        if (TREE_CODE (folded) == INTEGER_CST)
>> >> >> > -       pedwarn (location_of (size), OPT_Wpedantic,
>> >> >> > +       pedwarn (input_location, OPT_Wpedantic,
>> >> >>
>> >> >> It should work to use location_of (osize) here.
>> >> >
>> >> > I dropped this hunk altogether.  Because location_of will use
>> >> > DECL_SOURCE_LOCATION for DECLs, the error message will point to the declaration
>> >> > itself, not the use.  I don't really care either way.
>> >>
>> >> We want the message to point to the use, which location_of (osize)
>> >> will provide, since it should still have a location wrapper around a
>> >> DECL.
>> >
>> > location_of (osize) is actually the same as location_of (size) so that didn't
>> > change anything.
>>
>> Hunh, that's strange.  Why isn't osize the unfolded expression?  Where
>> is the location wrapper getting stripped?
>
> I actually see that it didn't have the location wrapper at the start.
> The array bound is parsed in cp_parser_direct_new_declarator, and we
> never called maybe_wrap_with_location to add the wrapper.  I don't know
> where that's supposed to happen.
>
> This quick hack works
>
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -8681,6 +8681,7 @@ cp_parser_direct_new_declarator (cp_parser* parser)
>        cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
>
>        /* Add this bound to the declarator.  */
> +      expression = maybe_wrap_with_location (expression, token->location);
>        declarator = make_array_declarator (declarator, expression);
>
>        /* If the next token is not a `[', then there are no more
>
> but that feels too ad-hoc and beyond the scope of this fix.
>
>> > The code below uses input_location which is why I went with
>> > it in the first place.  So, should I change this to input_location?
>>
>> I suppose so.
>
> Here's the version with input_location.
>
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
>
> 2018-08-13  Marek Polacek  <polacek@redhat.com>
>
>         PR c++/57891
>         * call.c (struct conversion): Add check_narrowing_const_only.
>         (build_converted_constant_expr): Set check_narrowing and
>         check_narrowing_const_only.  Give error if expr is error node.
>         (convert_like_real): Pass it to check_narrowing.
>         * cp-tree.h (check_narrowing): Add a default parameter.
>         * decl.c (compute_array_index_type): Use input_location instead of
>         location_of.
>         * pt.c (convert_nontype_argument): Return NULL_TREE if tf_error.
>         * typeck2.c (check_narrowing): Don't warn for instantiation-dependent
>         expressions.  Call maybe_constant_value instead of
>         fold_non_dependent_expr.  Don't mention { } in diagnostic.  Only check
>         narrowing for constants if CONST_ONLY.

This seems to have broken cpp1z/direct-enum-init1.C with -std=c++17
and above; please use make check-c++-all (or set
GXX_TESTSUITE_STDS=98,11,14,17,2a) to test C++ patches in all
conformance modes.

Jason
Marek Polacek Sept. 7, 2018, 3:20 p.m. UTC | #20
On Fri, Sep 07, 2018 at 01:40:53PM +0100, Jason Merrill wrote:
> > 2018-08-13  Marek Polacek  <polacek@redhat.com>
> >
> >         PR c++/57891
> >         * call.c (struct conversion): Add check_narrowing_const_only.
> >         (build_converted_constant_expr): Set check_narrowing and
> >         check_narrowing_const_only.  Give error if expr is error node.
> >         (convert_like_real): Pass it to check_narrowing.
> >         * cp-tree.h (check_narrowing): Add a default parameter.
> >         * decl.c (compute_array_index_type): Use input_location instead of
> >         location_of.
> >         * pt.c (convert_nontype_argument): Return NULL_TREE if tf_error.
> >         * typeck2.c (check_narrowing): Don't warn for instantiation-dependent
> >         expressions.  Call maybe_constant_value instead of
> >         fold_non_dependent_expr.  Don't mention { } in diagnostic.  Only check
> >         narrowing for constants if CONST_ONLY.
> 
> This seems to have broken cpp1z/direct-enum-init1.C with -std=c++17
> and above; please use make check-c++-all (or set
> GXX_TESTSUITE_STDS=98,11,14,17,2a) to test C++ patches in all
> conformance modes.

Sorry about that, I've updated my testing and will fix it shortly.

Marek
diff mbox series

Patch

diff --git gcc/cp/call.c gcc/cp/call.c
index 209c1fd2f0e..956c7b149dc 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -4152,7 +4152,10 @@  build_converted_constant_expr (tree type, tree expr, tsubst_flags_t complain)
     }
 
   if (conv)
-    expr = convert_like (conv, expr, complain);
+    {
+      conv->check_narrowing = !processing_template_decl;
+      expr = convert_like (conv, expr, complain);
+    }
   else
     expr = error_mark_node;
 
diff --git gcc/cp/decl.c gcc/cp/decl.c
index c04b9b7d457..8da63fa2aaa 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -9508,6 +9508,8 @@  compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
       else
 	{
 	  size = instantiate_non_dependent_expr_sfinae (size, complain);
+	  /* Don't warn about narrowing for VLAs.  */
+	  warning_sentinel s (warn_narrowing, !TREE_CONSTANT (osize));
 	  size = build_converted_constant_expr (size_type_node, size, complain);
 	  size = maybe_constant_value (size);
 
@@ -9556,7 +9558,7 @@  compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
     {
       tree folded = cp_fully_fold (size);
       if (TREE_CODE (folded) == INTEGER_CST)
-	pedwarn (location_of (size), OPT_Wpedantic,
+	pedwarn (input_location, OPT_Wpedantic,
 		 "size of array is not an integral constant-expression");
       /* Use the folded result for VLAs, too; it will have resolved
 	 SIZEOF_EXPR.  */
diff --git gcc/cp/pt.c gcc/cp/pt.c
index 3780f3492aa..12d1a1e1cd3 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -6669,9 +6669,10 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 	  /* C++17: A template-argument for a non-type template-parameter shall
 	     be a converted constant expression (8.20) of the type of the
 	     template-parameter.  */
+	  int errs = errorcount;
 	  expr = build_converted_constant_expr (type, expr, complain);
 	  if (expr == error_mark_node)
-	    return error_mark_node;
+	    return errorcount > errs ? NULL_TREE : error_mark_node;
 	  expr = maybe_constant_value (expr);
 	  expr = convert_from_reference (expr);
 	}
diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index 91aa5a62856..d82e3b608da 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -875,7 +875,8 @@  store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
 }
 
 
-/* Give diagnostic about narrowing conversions within { }.  */
+/* Give diagnostic about narrowing conversions within { }, or as part of
+   a converted constant expression.  */
 
 bool
 check_narrowing (tree type, tree init, tsubst_flags_t complain)
@@ -967,7 +968,7 @@  check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	{
 	  if (complain & tf_warning)
 	    warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
-			"from %qH to %qI inside { } is ill-formed in C++11",
+			"from %qH to %qI is ill-formed in C++11",
 			init, ftype, type);
 	  ok = true;
 	}
@@ -977,8 +978,7 @@  check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	    {
 	      if ((!almost_ok || pedantic)
 		  && pedwarn (loc, OPT_Wnarrowing,
-			      "narrowing conversion of %qE "
-			      "from %qH to %qI inside { }",
+			      "narrowing conversion of %qE from %qH to %qI",
 			      init, ftype, type)
 		  && almost_ok)
 		inform (loc, " the expression has a constant value but is not "
@@ -991,8 +991,8 @@  check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	  int savederrorcount = errorcount;
 	  global_dc->pedantic_errors = 1;
 	  pedwarn (loc, OPT_Wnarrowing,
-		   "narrowing conversion of %qE from %qH to %qI "
-		   "inside { }", init, ftype, type);
+		   "narrowing conversion of %qE from %qH to %qI ",
+		   init, ftype, type);
 	  if (errorcount == savederrorcount)
 	    ok = true;
 	  global_dc->pedantic_errors = flag_pedantic_errors;
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
index e69de29bb2d..989d277cd00 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing6.C
@@ -0,0 +1,8 @@ 
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+template<unsigned int> struct A {};
+A<-1> a; // { dg-error "narrowing conversion" }
+
+template<signed char> struct B {};
+B<1000> b; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
index e69de29bb2d..099fdfb7d81 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing7.C
@@ -0,0 +1,9 @@ 
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-narrowing" }
+
+template<unsigned int> struct A {};
+A<-1> a;
+
+template<signed char> struct B {};
+B<1000> b; // { dg-warning "overflow" }
diff --git gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
index e69de29bb2d..39c924c9c6c 100644
--- gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
+++ gcc/testsuite/g++.dg/cpp0x/Wnarrowing8.C
@@ -0,0 +1,6 @@ 
+// PR c++/57891
+// { dg-do compile { target c++11 } }
+
+struct X { constexpr operator int () { return 1000; } };
+template<signed char> struct C {};
+C<X{}> c; // { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
index 898102167de..dee5ed82301 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-data2.C
@@ -43,4 +43,4 @@  extern template struct A3<int, 510>;
 
 // Use.
 A3<int, 1111> a31;
-A3<char, 9999> a32;		// { dg-warning "overflow" }
+A3<char, 9999> a32;		// { dg-error "narrowing conversion" }
diff --git gcc/testsuite/g++.dg/ext/builtin12.C gcc/testsuite/g++.dg/ext/builtin12.C
index 1d6bb75cd77..489b37777c4 100644
--- gcc/testsuite/g++.dg/ext/builtin12.C
+++ gcc/testsuite/g++.dg/ext/builtin12.C
@@ -5,6 +5,6 @@  template<bool> struct A {};
 
 constexpr int foo()
 {
-  A<__builtin_constant_p(0)> a{};
+  A<__builtin_constant_p(0)> a{}; // { dg-error "narrowing conversion" }
   return 0;
 }
diff --git gcc/testsuite/g++.dg/init/new43.C gcc/testsuite/g++.dg/init/new43.C
index 9b0866720fe..7ab2a36392e 100644
--- gcc/testsuite/g++.dg/init/new43.C
+++ gcc/testsuite/g++.dg/init/new43.C
@@ -31,35 +31,35 @@  void test_literal ()
 
     // Verify integer literal.
     p = new char [-1];           // { dg-error "size of array is negative" }
-    p = new char [2][-3];        // { dg-error "size of array is negative" }
+    p = new char [2][-3];        // { dg-error "size of array is negative|narrowing conversion" }
     p = new char [-4][5];        // { dg-error "size of array is negative" }
-    p = new char [-6][-7];       // { dg-error "size of array is negative" }
+    p = new char [-6][-7];       // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) char [-1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][-3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][-3];    // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) char [-4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [-6][-7];   // { dg-error "size of array is negative" }
+    p = new (p) char [-6][-7];   // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) A [-1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) A [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) A [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (p) B [-1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (p) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (p) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new (&b) B [-1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][-3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][-3];       // { dg-error "size of array is negative|narrowing conversion" }
     p = new (&b) B [-4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [-6][-7];      // { dg-error "size of array is negative|narrowing conversion" }
 
     p = new char [1 - 2];         // { dg-error "size of array is negative" }
     p = new (p) char [2 - 3];     // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? -1 : -2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 - 3 * 2];    // { dg-error "size of array is negative" }
-    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][2 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constant_expression ()
@@ -79,35 +79,35 @@  void test_constant_expression ()
 
     // Verify constant expression.
     p = new char [i1];           // { dg-error "size of array is negative" }
-    p = new char [2][i3];        // { dg-error "size of array is negative" }
+    p = new char [2][i3];        // { dg-error "size of array is|narrowing conversion" }
     p = new char [i4][5];        // { dg-error "size of array is negative" }
-    p = new char [i6][i7];       // { dg-error "size of array is negative" }
+    p = new char [i6][i7];       // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) char [i1];       // { dg-error "size of array is negative" }
-    p = new (p) char [2][i3];    // { dg-error "size of array is negative" }
+    p = new (p) char [2][i3];    // { dg-error "size of array is|narrowing conversion" }
     p = new (p) char [i4][5];    // { dg-error "size of array is negative" }
-    p = new (p) char [i6][i7];   // { dg-error "size of array is negative" }
+    p = new (p) char [i6][i7];   // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) A [i1];          // { dg-error "size of array is negative" }
-    p = new (p) A [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) A [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (p) A [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) A [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) A [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new (p) B [i1];          // { dg-error "size of array is negative" }
-    p = new (p) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (p) B [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (p) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (p) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (p) B [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new (&b) B [i1];          // { dg-error "size of array is negative" }
-    p = new (&b) B [2][i3];       // { dg-error "size of array is negative" }
+    p = new (&b) B [2][i3];       // { dg-error "size of array is|narrowing conversion" }
     p = new (&b) B [i4][5];       // { dg-error "size of array is negative" }
-    p = new (&b) B [i6][i7];      // { dg-error "size of array is negative" }
+    p = new (&b) B [i6][i7];      // { dg-error "size of array is|narrowing conversion" }
 
     p = new short [i1 - 2];       // { dg-error "size of array is negative" }
     p = new (p) bool [i2 - 3];    // { dg-error "size of array is negative" }
     p = new A [2 < 1 ? i1 : i2];  // { dg-error "size of array is negative" }
     p = new (p) B [2 + i3 * 2];   // { dg-error "size of array is negative" }
-    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array is negative" }
+    p = new (&b) B [1][i1 - 3 * 2];// { dg-error "size of array|narrowing conversion" }
 }
 
 void test_constexpr ()
diff --git gcc/testsuite/g++.dg/other/fold1.C gcc/testsuite/g++.dg/other/fold1.C
index 23d34546e0b..bf074038b04 100644
--- gcc/testsuite/g++.dg/other/fold1.C
+++ gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@ 
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];		     // { dg-error "constant-expression" }
+    int x[i];		     // { dg-error "constant-expression|narrowing conversion" }
 };
diff --git gcc/testsuite/g++.dg/other/vrp1.C gcc/testsuite/g++.dg/other/vrp1.C
index 0a798c9954e..466a15b4cbb 100644
--- gcc/testsuite/g++.dg/other/vrp1.C
+++ gcc/testsuite/g++.dg/other/vrp1.C
@@ -9,4 +9,4 @@  long long mod (long long l, long long r)
     return 0LL;
   return l % r;
 }
-template long long mod<-0x8000000000000000LL> (long long, long long);
+template long long mod<-0x8000000000000000LL> (long long, long long); // { dg-error "template-id" "" { target { c++11 } } }
diff --git gcc/testsuite/g++.dg/parse/array-size2.C gcc/testsuite/g++.dg/parse/array-size2.C
index d0bc47fe746..997b95eed1a 100644
--- gcc/testsuite/g++.dg/parse/array-size2.C
+++ gcc/testsuite/g++.dg/parse/array-size2.C
@@ -14,7 +14,7 @@  extern void bar (char *, char *);
 void
 foo (void)
 {
-  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" }
+  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant|narrowing conversion" }
   char h[(__SIZE_TYPE__) &((struct S *) 8)->b];	      // { dg-error "constant" }
   bar (g, h);
 }
diff --git gcc/testsuite/g++.dg/template/char1.C gcc/testsuite/g++.dg/template/char1.C
index 51e72e7ad06..a6cffaaf024 100644
--- gcc/testsuite/g++.dg/template/char1.C
+++ gcc/testsuite/g++.dg/template/char1.C
@@ -1,4 +1,5 @@ 
 template <class CharType, CharType line_terminator = 0>
 class String {};
 
-String<signed char, 255> s;		// { dg-warning "overflow" }
+String<signed char, 255> s;		// { dg-error "narrowing conversion" "" { target c++11 } }
+// { dg-warning "overflow" "" { target c++98_only } .-1 }
diff --git gcc/testsuite/g++.dg/template/dependent-name3.C gcc/testsuite/g++.dg/template/dependent-name3.C
index bbe6fb66266..f9d14055a11 100644
--- gcc/testsuite/g++.dg/template/dependent-name3.C
+++ gcc/testsuite/g++.dg/template/dependent-name3.C
@@ -11,7 +11,7 @@  template<int I> struct A
 template<int N> struct B
 {
   int x[A<N>::zero];       // { dg-error "zero" }
-  int y[A<N>::minus_one];  // { dg-error "negative" }
+  int y[A<N>::minus_one];  // { dg-error "size of array|narrowing conversion" }
 };
 
 B<0> b;