From fe43c635035edcd29eca0a8e3b08d8bcf14d9ba8 Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Mon, 30 Apr 2018 17:21:32 -0400
Subject: [PATCH] PR c++/84701 - unsigned typeof.

	* decl.c (grokdeclarator): Overhaul diagnostics for invalid use
	of long/short/signed/unsigned.

From-SVN: r259780
---
 gcc/cp/ChangeLog                     |  4 ++
 gcc/cp/decl.c                        | 82 +++++++++++++++++-----------
 gcc/testsuite/g++.dg/cpp1z/decomp3.C |  2 +-
 gcc/testsuite/g++.dg/ext/typeof13.C  |  8 +++
 4 files changed, 62 insertions(+), 34 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/typeof13.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 95f77f4bf985..65f556e0c767 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,9 @@
 2018-04-30  Jason Merrill  <jason@redhat.com>
 
+	PR c++/84701 - unsigned typeof.
+	* decl.c (grokdeclarator): Overhaul diagnostics for invalid use
+	of long/short/signed/unsigned.
+
 	PR c++/85305 - pack in lambda init-capture.
 	* parser.c (cp_parser_initializer): Add subexpression_p parm; don't
 	check_for_bare_parameter_packs in a subexpression.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 07f3a61fed6c..6f2fe01d83d3 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10608,45 +10608,61 @@ grokdeclarator (const cp_declarator *declarator,
 
   if (unsigned_p || signed_p || long_p || short_p)
     {
-      int ok = 0;
-
-      if ((signed_p || unsigned_p) && TREE_CODE (type) != INTEGER_TYPE)
-	error ("%<signed%> or %<unsigned%> invalid for %qs", name);
-      else if (signed_p && unsigned_p)
-	error ("%<signed%> and %<unsigned%> specified together for %qs", name);
-      else if (longlong && TREE_CODE (type) != INTEGER_TYPE)
-	error ("%<long long%> invalid for %qs", name);
-      else if (long_p && TREE_CODE (type) == REAL_TYPE)
-	error ("%<long%> invalid for %qs", name);
-      else if (short_p && TREE_CODE (type) == REAL_TYPE)
-	error ("%<short%> invalid for %qs", name);
-      else if ((long_p || short_p) && TREE_CODE (type) != INTEGER_TYPE)
-	error ("%<long%> or %<short%> invalid for %qs", name);
-      else if ((long_p || short_p || explicit_char || explicit_int) && explicit_intN)
-	error ("%<long%>, %<int%>, %<short%>, or %<char%> invalid for %qs", name);
-      else if ((long_p || short_p) && explicit_char)
-	error ("%<long%> or %<short%> specified with char for %qs", name);
-      else if (long_p && short_p)
-	error ("%<long%> and %<short%> specified together for %qs", name);
-      else if (type == char16_type_node || type == char32_type_node)
+      location_t loc;
+      const char *key;
+      if (unsigned_p)
 	{
-	  if (signed_p || unsigned_p)
-	    error ("%<signed%> or %<unsigned%> invalid for %qs", name);
-	  else if (short_p || long_p)
-	    error ("%<short%> or %<long%> invalid for %qs", name);
+	  key = "unsigned";
+	  loc = declspecs->locations[ds_unsigned];
 	}
-      else
+      else if (signed_p)
+	{
+	  key = "signed";
+	  loc = declspecs->locations[ds_signed];
+	}
+      else if (longlong)
+	{
+	  key = "long long";
+	  loc = declspecs->locations[ds_long_long];
+	}
+      else if (long_p)
 	{
-	  ok = 1;
-	  if (!explicit_int && !defaulted_int && !explicit_char && !explicit_intN && pedantic)
+	  key = "long";
+	  loc = declspecs->locations[ds_long];
+	}
+      else /* if (short_p) */
+	{
+	  key = "short";
+	  loc = declspecs->locations[ds_short];
+	}
+
+      int ok = 0;
+
+      if (signed_p && unsigned_p)
+	error_at (loc, "%<signed%> and %<unsigned%> specified together");
+      else if (long_p && short_p)
+	error_at (loc, "%<long%> and %<short%> specified together");
+      else if (TREE_CODE (type) != INTEGER_TYPE
+	       || type == char16_type_node || type == char32_type_node
+	       || ((long_p || short_p)
+		   && (explicit_char || explicit_intN)))
+	error_at (loc, "%qs specified with %qT", key, type);
+      else if (!explicit_int && !defaulted_int
+	       && !explicit_char && !explicit_intN)
+	{
+	  if (typedef_decl)
 	    {
-	      pedwarn (input_location, OPT_Wpedantic, 
-		       "long, short, signed or unsigned used invalidly for %qs",
-		       name);
-	      if (flag_pedantic_errors)
-		ok = 0;
+	      pedwarn (loc, OPT_Wpedantic, "%qs specified with %qT",
+		       key, type);
+	      ok = !flag_pedantic_errors;
 	    }
+	  else if (declspecs->decltype_p)
+	    error_at (loc, "%qs specified with %<decltype%>", key);
+	  else
+	    error_at (loc, "%qs specified with %<typeof%>", key);
 	}
+      else
+	ok = 1;
 
       /* Discard the type modifiers if they are invalid.  */
       if (! ok)
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp3.C b/gcc/testsuite/g++.dg/cpp1z/decomp3.C
index 1886cdbe90d6..4d75e9380988 100644
--- a/gcc/testsuite/g++.dg/cpp1z/decomp3.C
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp3.C
@@ -29,7 +29,7 @@ test (A &b, B c)
 					// { dg-warning "structured bindings only available with -std=c..17 or -std=gnu..17" "" { target c++14_down } .-1 }
   __restrict auto [ t ] = c;		// { dg-error "invalid use of 'restrict'" }
 					// { dg-warning "structured bindings only available with -std=c..17 or -std=gnu..17" "" { target c++14_down } .-1 }
-  long long auto [ u ] = c;		// { dg-error "'long long' invalid for 'structured binding'" }
+  long long auto [ u ] = c;		// { dg-error "'long long' specified with 'auto'" }
 					// { dg-warning "structured bindings only available with -std=c..17 or -std=gnu..17" "" { target c++14_down } .-1 }
   virtual auto [ v ] = c;		// { dg-error "'virtual' outside class declaration" }
 					// { dg-warning "structured bindings only available with -std=c..17 or -std=gnu..17" "" { target c++14_down } .-1 }
diff --git a/gcc/testsuite/g++.dg/ext/typeof13.C b/gcc/testsuite/g++.dg/ext/typeof13.C
new file mode 100644
index 000000000000..820d50d23a3c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/typeof13.C
@@ -0,0 +1,8 @@
+// PR c++/84701
+// { dg-options "-pedantic" }
+
+typedef short foo_t;
+foo_t s = -1;  /* FFFF */
+
+unsigned u = (unsigned foo_t)s;	       // { dg-warning foo_t }
+unsigned u2 = (unsigned __typeof(s))s;   // { dg-error typeof }
-- 
GitLab