public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Jakub Jelinek <jakub@gcc.gnu.org>
To: gcc-cvs@gcc.gnu.org
Subject: [gcc r13-2889] c++: Improve diagnostics about conflicting specifiers
Date: Tue, 27 Sep 2022 06:21:48 +0000 (GMT)	[thread overview]
Message-ID: <20220927062148.0200E3858D39@sourceware.org> (raw)

https://gcc.gnu.org/g:5b86d5dbe47c477daf739b82c3793a70f8cbd96c

commit r13-2889-g5b86d5dbe47c477daf739b82c3793a70f8cbd96c
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Tue Sep 27 08:20:05 2022 +0200

    c++: Improve diagnostics about conflicting specifiers
    
    On Sat, Sep 17, 2022 at 01:23:59AM +0200, Jason Merrill wrote:
    > I wonder why we don't give an error when setting the
    > conflicting_specifiers_p flag in cp_parser_set_storage_class?  We should be
    > able to give a better diagnostic at that point.
    
    I didn't have time to update the whole patch last night, but this part
    seems to be independent and I've managed to test it.
    
    The diagnostics then looks like:
    a.C:1:9: error: ‘static’ specifier conflicts with ‘typedef’
        1 | typedef static int a;
          | ~~~~~~~ ^~~~~~
    a.C:2:8: error: ‘typedef’ specifier conflicts with ‘static’
        2 | static typedef int b;
          | ~~~~~~ ^~~~~~~
    a.C:3:8: error: duplicate ‘static’ specifier
        3 | static static int c;
          | ~~~~~~ ^~~~~~
    a.C:4:8: error: ‘extern’ specifier conflicts with ‘static’
        4 | static extern int d;
          | ~~~~~~ ^~~~~~
    
    2022-09-27  Jakub Jelinek  <jakub@redhat.com>
    
    gcc/cp/
            * parser.cc (cp_parser_lambda_declarator_opt): Don't diagnose
            conflicting specifiers here.
            (cp_storage_class_name): New variable.
            (cp_parser_decl_specifier_seq): When setting conflicting_specifiers_p
            for the first time, diagnose which exact specifiers conflict.
            (cp_parser_set_storage_class): Likewise.  Move storage_class
            computation earlier.
            * decl.cc (grokdeclarator): Don't diagnose conflicting specifiers
            here, just return error_mark_node.
    gcc/testsuite/
            * g++.dg/diagnostic/conflicting-specifiers-1.C: Adjust expected
            diagnostics.
            * g++.dg/parse/typedef8.C: Likewise.
            * g++.dg/parse/crash39.C: Likewise.
            * g++.dg/other/mult-stor1.C: Likewise.
            * g++.dg/cpp2a/constinit3.C: Likewise.

Diff:
---
 gcc/cp/decl.cc                                     |  7 +-
 gcc/cp/parser.cc                                   | 88 +++++++++++++++-------
 gcc/testsuite/g++.dg/cpp2a/constinit3.C            |  2 +-
 .../g++.dg/diagnostic/conflicting-specifiers-1.C   |  2 +-
 gcc/testsuite/g++.dg/other/mult-stor1.C            |  2 +-
 gcc/testsuite/g++.dg/parse/crash39.C               |  2 +-
 gcc/testsuite/g++.dg/parse/typedef8.C              | 10 +--
 7 files changed, 71 insertions(+), 42 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 80467c19254..f4460c911b3 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -12095,12 +12095,7 @@ grokdeclarator (const cp_declarator *declarator,
     }
 
   if (declspecs->conflicting_specifiers_p)
-    {
-      error_at (min_location (declspecs->locations[ds_typedef],
-			      declspecs->locations[ds_storage_class]),
-		"conflicting specifiers in declaration of %qs", name);
-      return error_mark_node;
-    }
+    return error_mark_node;
 
   /* Extract the basic type from the decl-specifier-seq.  */
   type = declspecs->type;
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 3dedd140428..d876a8623b4 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -11729,9 +11729,6 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
     {
       LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1;
       quals = TYPE_UNQUALIFIED;
-      if (lambda_specs.conflicting_specifiers_p)
-	error_at (lambda_specs.locations[ds_storage_class],
-		  "duplicate %<mutable%>");
     }
 
   tx_qual = cp_parser_tx_qualifier_opt (parser);
@@ -15731,6 +15728,13 @@ cp_parser_decomposition_declaration (cp_parser *parser,
   return decl;
 }
 
+/* Names of storage classes.  */
+
+static const char *const
+cp_storage_class_name[] = {
+  "", "auto", "register", "static", "extern", "mutable"
+};
+
 /* Parse a decl-specifier-seq.
 
    decl-specifier-seq:
@@ -15952,8 +15956,18 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 	     may as well commit at this point.  */
 	  cp_parser_commit_to_tentative_parse (parser);
 
-          if (decl_specs->storage_class != sc_none)
-            decl_specs->conflicting_specifiers_p = true;
+	  if (decl_specs->storage_class != sc_none)
+	    {
+	      if (decl_specs->conflicting_specifiers_p)
+		break;
+	      gcc_rich_location richloc (token->location);
+	      location_t oloc = decl_specs->locations[ds_storage_class];
+	      richloc.add_location_if_nearby (oloc);
+	      error_at (&richloc,
+			"%<typedef%> specifier conflicts with %qs",
+			cp_storage_class_name[decl_specs->storage_class]);
+	      decl_specs->conflicting_specifiers_p = true;
+	    }
 	  break;
 
 	  /* storage-class-specifier:
@@ -32845,26 +32859,6 @@ cp_parser_set_storage_class (cp_parser *parser,
 {
   cp_storage_class storage_class;
 
-  if (parser->in_unbraced_linkage_specification_p)
-    {
-      error_at (token->location, "invalid use of %qD in linkage specification",
-		ridpointers[keyword]);
-      return;
-    }
-  else if (decl_specs->storage_class != sc_none)
-    {
-      decl_specs->conflicting_specifiers_p = true;
-      return;
-    }
-
-  if ((keyword == RID_EXTERN || keyword == RID_STATIC)
-      && decl_spec_seq_has_spec_p (decl_specs, ds_thread)
-      && decl_specs->gnu_thread_keyword_p)
-    {
-      pedwarn (decl_specs->locations[ds_thread], 0,
-		"%<__thread%> before %qD", ridpointers[keyword]);
-    }
-
   switch (keyword)
     {
     case RID_AUTO:
@@ -32885,6 +32879,38 @@ cp_parser_set_storage_class (cp_parser *parser,
     default:
       gcc_unreachable ();
     }
+
+  if (parser->in_unbraced_linkage_specification_p)
+    {
+      error_at (token->location, "invalid use of %qD in linkage specification",
+		ridpointers[keyword]);
+      return;
+    }
+  else if (decl_specs->storage_class != sc_none)
+    {
+      if (decl_specs->conflicting_specifiers_p)
+	return;
+      gcc_rich_location richloc (token->location);
+      richloc.add_location_if_nearby (decl_specs->locations[ds_storage_class]);
+      if (decl_specs->storage_class == storage_class)
+	error_at (&richloc, "duplicate %qD specifier", ridpointers[keyword]);
+      else
+	error_at (&richloc,
+		  "%qD specifier conflicts with %qs",
+		  ridpointers[keyword],
+		  cp_storage_class_name[decl_specs->storage_class]);
+      decl_specs->conflicting_specifiers_p = true;
+      return;
+    }
+
+  if ((keyword == RID_EXTERN || keyword == RID_STATIC)
+      && decl_spec_seq_has_spec_p (decl_specs, ds_thread)
+      && decl_specs->gnu_thread_keyword_p)
+    {
+      pedwarn (decl_specs->locations[ds_thread], 0,
+		"%<__thread%> before %qD", ridpointers[keyword]);
+    }
+
   decl_specs->storage_class = storage_class;
   set_and_check_decl_spec_loc (decl_specs, ds_storage_class, token);
 
@@ -32892,8 +32918,16 @@ cp_parser_set_storage_class (cp_parser *parser,
      specifier. If there is a typedef specifier present then set
      conflicting_specifiers_p which will trigger an error later
      on in grokdeclarator. */
-  if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef))
-    decl_specs->conflicting_specifiers_p = true;
+  if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef)
+      && !decl_specs->conflicting_specifiers_p)
+    {
+      gcc_rich_location richloc (token->location);
+      richloc.add_location_if_nearby (decl_specs->locations[ds_typedef]);
+      error_at (&richloc,
+		"%qD specifier conflicts with %<typedef%>",
+		ridpointers[keyword]);
+      decl_specs->conflicting_specifiers_p = true;
+    }
 }
 
 /* Update the DECL_SPECS to reflect the TYPE_SPEC.  If TYPE_DEFINITION_P
diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit3.C b/gcc/testsuite/g++.dg/cpp2a/constinit3.C
index a29c594657a..ffa61847824 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constinit3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constinit3.C
@@ -5,7 +5,7 @@ constinit constinit int v1; // { dg-error "duplicate .constinit." }
 constexpr constinit int v2 = 1; // { dg-error "can use at most one of the .constinit. and .constexpr. specifiers" }
 constinit constexpr int v3 = 1; // { dg-error "an use at most one of the .constinit. and .constexpr. specifiers" }
 
-extern static constinit int v4; // { dg-error "conflicting specifiers" }
+extern static constinit int v4; // { dg-error "'static' specifier conflicts with 'extern'" }
 extern thread_local constinit int v5;
 extern constinit int v6;
 
diff --git a/gcc/testsuite/g++.dg/diagnostic/conflicting-specifiers-1.C b/gcc/testsuite/g++.dg/diagnostic/conflicting-specifiers-1.C
index 1a8ac02b77e..89e2ebdebf6 100644
--- a/gcc/testsuite/g++.dg/diagnostic/conflicting-specifiers-1.C
+++ b/gcc/testsuite/g++.dg/diagnostic/conflicting-specifiers-1.C
@@ -1 +1 @@
-static typedef int i __attribute__((unused));  // { dg-error "1:conflicting specifiers" }
+static typedef int i __attribute__((unused));  // { dg-error "8:'typedef' specifier conflicts with 'static'" }
diff --git a/gcc/testsuite/g++.dg/other/mult-stor1.C b/gcc/testsuite/g++.dg/other/mult-stor1.C
index 1eaec4f14f9..e582b03ee60 100644
--- a/gcc/testsuite/g++.dg/other/mult-stor1.C
+++ b/gcc/testsuite/g++.dg/other/mult-stor1.C
@@ -4,5 +4,5 @@
 
 struct A
 {
-  extern static int i;  // { dg-error "conflicting specifiers" }
+  extern static int i;  // { dg-error "'static' specifier conflicts with 'extern'" }
 };
diff --git a/gcc/testsuite/g++.dg/parse/crash39.C b/gcc/testsuite/g++.dg/parse/crash39.C
index 2f39c10e31d..5d4e02d79ca 100644
--- a/gcc/testsuite/g++.dg/parse/crash39.C
+++ b/gcc/testsuite/g++.dg/parse/crash39.C
@@ -1,3 +1,3 @@
 // PR c++/31747
 
-static extern int i; // { dg-error "conflicting specifiers" }
+static extern int i; // { dg-error "'extern' specifier conflicts with 'static'" }
diff --git a/gcc/testsuite/g++.dg/parse/typedef8.C b/gcc/testsuite/g++.dg/parse/typedef8.C
index 60b8f39ee5e..e21bdb911d9 100644
--- a/gcc/testsuite/g++.dg/parse/typedef8.C
+++ b/gcc/testsuite/g++.dg/parse/typedef8.C
@@ -1,11 +1,11 @@
 //PR c++ 29024
 
-typedef static int a;   // { dg-error "conflicting" }
-typedef register int b; // { dg-error "conflicting" }
-typedef extern int c;   // { dg-error "conflicting" }
-static typedef int a;   // { dg-error "conflicting" }
+typedef static int a;   // { dg-error "'static' specifier conflicts with 'typedef'" }
+typedef register int b; // { dg-error "'register' specifier conflicts with 'typedef'" }
+typedef extern int c;   // { dg-error "'extern' specifier conflicts with 'typedef'" }
+static typedef int a;   // { dg-error "'typedef' specifier conflicts with 'static'" }
 
 void foo()
 {
-  typedef auto int bar; // { dg-error "conflicting|two or more data types" }
+  typedef auto int bar; // { dg-error "'auto' specifier conflicts with 'typedef'|two or more data types" }
 }

                 reply	other threads:[~2022-09-27  6:21 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220927062148.0200E3858D39@sourceware.org \
    --to=jakub@gcc.gnu.org \
    --cc=gcc-cvs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).