PR c/71613 identifies a problem where we fail to report this enum:

  enum { e1 = LLONG_MIN };

with -pedantic, due to LLONG_MIN being inside a system header.

This patch updates the C and C++ frontends to use the location of the
name as the primary location in the diagnostic, supplying the location
of the value as a secondary location, fixing the issue.

Before:
  $ gcc -c /tmp/test.c -Wpedantic
  /tmp/test.c: In function 'main':
  /tmp/test.c:3:14: warning: ISO C restricts enumerator values to range of 
'int' [-Wpedantic]
     enum { c = -3000000000 };
                ^

After:
  $ ./xgcc -B. -c /tmp/test.c -Wpedantic
  /tmp/test.c: In function 'main':
  /tmp/test.c:3:10: warning: ISO C restricts enumerator values to range of 
'int' [-Wpedantic]
     enum { c = -3000000000 };
            ^   ~~~~~~~~~~~

Successfully bootstrapped&regretested on x86_64-pc-linux-gnu;
adds 13 PASS results to gcc.sum and 9 PASS results to g++.sum.

OK for trunk?

gcc/c/ChangeLog:
        PR c/71610
        PR c/71613
        * c-decl.c (build_enumerator): Fix description of LOC in comment.
        Update diagnostics to use a rich_location at decl_loc, rather than
        at loc, adding loc as a secondary range if available.
        * c-parser.c (c_parser_enum_specifier): Use the full location of
        the expression for value_loc, rather than just the first token.

gcc/cp/ChangeLog:
        PR c/71610
        PR c/71613
        * cp-tree.h (build_enumerator): Add location_t param.
        * decl.c (build_enumerator): Add "value_loc" param.  Update
        "not an integer constant" diagnostic to use "loc" rather than
        input_location, and to add "value_loc" as a secondary range if
        available.
        * parser.c (cp_parser_enumerator_definition): Extract the
        location of the value from the cp_expr for the constant
        expression, if any, and pass it to build_enumerator.
        * pt.c (tsubst_enum): Extract EXPR_LOCATION of the value,
        and pass it to build_enumerator.

gcc/ChangeLog:
        PR c/71610
        PR c/71613
        * diagnostic-core.h (pedwarn_at_rich_loc): New prototype.
        * diagnostic.c (pedwarn_at_rich_loc): New function.

gcc/testsuite/ChangeLog:
        PR c/71610
        PR c/71613
        * c-c++-common/pr71610.c: New test case.
        * gcc.dg/c90-const-expr-8.c: Update expected column of diagnostic.
        * gcc.dg/pr71610-2.c: New test case.
        * gcc.dg/pr71613.c: New test case.
---
 gcc/c/c-decl.c                          | 32 +++++++++++++++++++++-----------
 gcc/c/c-parser.c                        | 10 ++++++++--
 gcc/cp/cp-tree.h                        |  2 +-
 gcc/cp/decl.c                           | 11 ++++++++---
 gcc/cp/parser.c                         |  7 +++++--
 gcc/cp/pt.c                             |  3 ++-
 gcc/diagnostic-core.h                   |  2 ++
 gcc/diagnostic.c                        | 12 ++++++++++++
 gcc/testsuite/c-c++-common/pr71610.c    | 11 +++++++++++
 gcc/testsuite/gcc.dg/c90-const-expr-8.c |  2 +-
 gcc/testsuite/gcc.dg/pr71610-2.c        | 17 +++++++++++++++++
 gcc/testsuite/gcc.dg/pr71613.c          | 19 +++++++++++++++++++
 12 files changed, 107 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/pr71610.c
 create mode 100644 gcc/testsuite/gcc.dg/pr71610-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr71613.c

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 5c08c59..0d081ff 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -8159,7 +8159,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
 /* Build and install a CONST_DECL for one value of the
    current enumeration type (one that was begun with start_enum).
    DECL_LOC is the location of the enumerator.
-   LOC is the location of the '=' operator if any, DECL_LOC otherwise.
+   LOC is the location of the value if any, DECL_LOC otherwise.
    Return a tree-list containing the CONST_DECL and its value.
    Assignment of sequential values by default is handled here.  */
 
@@ -8169,6 +8169,10 @@ build_enumerator (location_t decl_loc, location_t loc,
 {
   tree decl, type;
 
+  rich_location richloc (line_table, decl_loc);
+  if (loc && loc != decl_loc)
+    richloc.add_range (loc, false);
+
   /* Validate and default VALUE.  */
 
   if (value != 0)
@@ -8179,8 +8183,10 @@ build_enumerator (location_t decl_loc, location_t loc,
        value = 0;
       else if (!INTEGRAL_TYPE_P (TREE_TYPE (value)))
        {
-         error_at (loc, "enumerator value for %qE is not an integer constant",
-                   name);
+         error_at_rich_loc
+           (&richloc,
+            "enumerator value for %qE is not an integer constant",
+            name);
          value = 0;
        }
       else
@@ -8189,14 +8195,17 @@ build_enumerator (location_t decl_loc, location_t loc,
            {
              value = c_fully_fold (value, false, NULL);
              if (TREE_CODE (value) == INTEGER_CST)
-               pedwarn (loc, OPT_Wpedantic,
-                        "enumerator value for %qE is not an integer "
-                        "constant expression", name);
+               pedwarn_at_rich_loc
+                 (&richloc, OPT_Wpedantic,
+                  "enumerator value for %qE is not an integer "
+                  "constant expression", name);
            }
          if (TREE_CODE (value) != INTEGER_CST)
            {
-             error ("enumerator value for %qE is not an integer constant",
-                    name);
+             error_at_rich_loc
+               (&richloc,
+                "enumerator value for %qE is not an integer constant",
+                name);
              value = 0;
            }
          else
@@ -8214,15 +8223,16 @@ build_enumerator (location_t decl_loc, location_t loc,
     {
       value = the_enum->enum_next_value;
       if (the_enum->enum_overflow)
-       error_at (loc, "overflow in enumeration values");
+       error_at_rich_loc (&richloc, "overflow in enumeration values");
     }
   /* Even though the underlying type of an enum is unspecified, the
      type of enumeration constants is explicitly defined as int
      (6.4.4.3/2 in the C99 Standard).  GCC allows any integer type as
      an extension.  */
   else if (!int_fits_type_p (value, integer_type_node))
-    pedwarn (loc, OPT_Wpedantic,
-            "ISO C restricts enumerator values to range of %<int%>");
+    pedwarn_at_rich_loc
+      (&richloc, OPT_Wpedantic,
+       "ISO C restricts enumerator values to range of %<int%>");
 
   /* The ISO C Standard mandates enumerators to have type int, even
      though the underlying type of an enum type is unspecified.
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 78bf68e..3e9458c 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -2720,8 +2720,14 @@ c_parser_enum_specifier (c_parser *parser)
          if (c_parser_next_token_is (parser, CPP_EQ))
            {
              c_parser_consume_token (parser);
-             value_loc = c_parser_peek_token (parser)->location;
-             enum_value = c_parser_expr_no_commas (parser, NULL).value;
+             c_expr value = c_parser_expr_no_commas (parser, NULL);
+             enum_value = value.value;
+             if (EXPR_HAS_LOCATION (enum_value))
+               value_loc = EXPR_LOCATION (enum_value);
+             else
+               value_loc
+                 = make_location (value.get_start (), value.get_start (),
+                                  value.get_finish ());
            }
          else
            enum_value = NULL_TREE;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5b87bb3..9ce0ee5 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5792,7 +5792,7 @@ extern void xref_basetypes                        (tree, 
tree);
 extern tree start_enum                         (tree, tree, tree, tree, bool, 
bool *);
 extern void finish_enum_value_list             (tree);
 extern void finish_enum                                (tree);
-extern void build_enumerator                   (tree, tree, tree, tree, 
location_t);
+extern void build_enumerator                   (tree, tree, tree, tree, 
location_t, location_t);
 extern tree lookup_enumerator                  (tree, tree);
 extern bool start_preparsed_function           (tree, tree, int);
 extern bool start_function                     (cp_decl_specifier_seq *,
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index c86a131..3db8317 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -13542,7 +13542,7 @@ finish_enum (tree enumtype)
 
 void
 build_enumerator (tree name, tree value, tree enumtype, tree attributes,
-                 location_t loc)
+                 location_t loc, location_t value_loc)
 {
   tree decl;
   tree context;
@@ -13590,8 +13590,13 @@ build_enumerator (tree name, tree value, tree 
enumtype, tree attributes,
              if (TREE_CODE (value) != INTEGER_CST
                  || ! INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (value)))
                {
-                 error ("enumerator value for %qD is not an integer constant",
-                        name);
+                 rich_location richloc (line_table, loc);
+                 if (value_loc)
+                   richloc.add_range (value_loc, false);
+                 error_at_rich_loc
+                   (&richloc,
+                    "enumerator value for %qD is not an integer constant",
+                    name);
                  value = NULL_TREE;
                }
            }
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d1f06fd..306b1dc 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -17398,6 +17398,7 @@ cp_parser_enumerator_definition (cp_parser* parser, 
tree type)
   tree identifier;
   tree value;
   location_t loc;
+  location_t value_loc = UNKNOWN_LOCATION;
 
   /* Save the input location because we are interested in the location
      of the identifier and not the location of the explicit value.  */
@@ -17417,7 +17418,9 @@ cp_parser_enumerator_definition (cp_parser* parser, 
tree type)
       /* Consume the `=' token.  */
       cp_lexer_consume_token (parser->lexer);
       /* Parse the value.  */
-      value = cp_parser_constant_expression (parser);
+      cp_expr value_expr = cp_parser_constant_expression (parser);
+      value = value_expr;
+      value_loc = value_expr.get_location ();
     }
   else
     value = NULL_TREE;
@@ -17428,7 +17431,7 @@ cp_parser_enumerator_definition (cp_parser* parser, 
tree type)
     value = error_mark_node;
 
   /* Create the enumerator.  */
-  build_enumerator (identifier, value, type, attrs, loc);
+  build_enumerator (identifier, value, type, attrs, loc, value_loc);
 }
 
 /* Parse a namespace-name.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 11b5d82..4e062c5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -22373,7 +22373,8 @@ tsubst_enum (tree tag, tree newtag, tree args)
       /* Actually build the enumerator itself.  Here we're assuming that
         enumerators can't have dependent attributes.  */
       build_enumerator (DECL_NAME (decl), value, newtag,
-                       DECL_ATTRIBUTES (decl), DECL_SOURCE_LOCATION (decl));
+                       DECL_ATTRIBUTES (decl), DECL_SOURCE_LOCATION (decl),
+                       EXPR_LOCATION (value));
     }
 
   if (SCOPED_ENUM_P (newtag))
diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
index f783761..51df150 100644
--- a/gcc/diagnostic-core.h
+++ b/gcc/diagnostic-core.h
@@ -76,6 +76,8 @@ extern void fatal_error (location_t, const char *, ...) 
ATTRIBUTE_GCC_DIAG(2,3)
 /* Pass one of the OPT_W* from options.h as the second parameter.  */
 extern bool pedwarn (location_t, int, const char *, ...)
      ATTRIBUTE_GCC_DIAG(3,4);
+extern bool pedwarn_at_rich_loc (rich_location *, int, const char *, ...)
+     ATTRIBUTE_GCC_DIAG(3,4);
 extern bool permerror (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
 extern bool permerror_at_rich_loc (rich_location *, const char *,
                                   ...) ATTRIBUTE_GCC_DIAG(2,3);
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 8467aaa..62ba5b4 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -1089,6 +1089,18 @@ pedwarn (location_t location, int opt, const char 
*gmsgid, ...)
   return ret;
 }
 
+/* Same as "pedwarn", but at RICHLOC.  */
+
+bool
+pedwarn_at_rich_loc (rich_location *richloc, int opt, const char *gmsgid, ...)
+{
+  va_list ap;
+  va_start (ap, gmsgid);
+  bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_PEDWARN);
+  va_end (ap);
+  return ret;
+}
+
 /* A "permissive" error at LOCATION: issues an error unless
    -fpermissive was given on the command line, in which case it issues
    a warning.  Use this for things that really should be errors but we
diff --git a/gcc/testsuite/c-c++-common/pr71610.c 
b/gcc/testsuite/c-c++-common/pr71610.c
new file mode 100644
index 0000000..b62a2e1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr71610.c
@@ -0,0 +1,11 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+void test (void)
+{
+  enum { c1 = "not int", /* { dg-error "10: enumerator value for .c1. is not 
an integer constant" } */
+/* { dg-begin-multiline-output "" }
+   enum { c1 = "not int",
+          ^~   ~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+        c_end };
+}
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-8.c 
b/gcc/testsuite/gcc.dg/c90-const-expr-8.c
index b6aba7b..ba2b029 100644
--- a/gcc/testsuite/gcc.dg/c90-const-expr-8.c
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-8.c
@@ -22,7 +22,7 @@ enum e {
   E5 = 0 * -INT_MIN, /* { dg-warning "12:integer overflow in expression" } */
   /* { dg-error "3:overflow in constant expression" "constant" { target *-*-* 
} 22 } */
   E6 = 0 * !-INT_MIN, /* { dg-warning "13:integer overflow in expression" } */
-  /* { dg-error "8:not an integer constant" "constant" { target *-*-* } 24 } */
+  /* { dg-error "3:not an integer constant" "constant" { target *-*-* } 24 } */
   E7 = INT_MIN % -1 /* { dg-warning "16:integer overflow in expression" } */
   /* { dg-error "1:overflow in constant expression" "constant" { target *-*-* 
} 28 } */
 };
diff --git a/gcc/testsuite/gcc.dg/pr71610-2.c b/gcc/testsuite/gcc.dg/pr71610-2.c
new file mode 100644
index 0000000..36bed6e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr71610-2.c
@@ -0,0 +1,17 @@
+/* { dg-options "-pedantic -fdiagnostics-show-caret" } */
+void test (void)
+{
+  enum { c1 = -3000000000, /* { dg-warning "10: ISO C restricts enumerator 
values to range of .int." } */
+/* { dg-begin-multiline-output "" }
+   enum { c1 = -3000000000,
+          ^~   ~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+          c2 = "not int", /* { dg-error "11: enumerator value for .c2. is not 
an integer constant" } */
+/* { dg-begin-multiline-output "" }
+           c2 = "not int",
+           ^~   ~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+        c_end };
+}
diff --git a/gcc/testsuite/gcc.dg/pr71613.c b/gcc/testsuite/gcc.dg/pr71613.c
new file mode 100644
index 0000000..fa1bba2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr71613.c
@@ -0,0 +1,19 @@
+/* { dg-options "-pedantic -fdiagnostics-show-caret" } */
+
+#include <limits.h>
+
+void test (void)
+{
+  enum { e1 = LLONG_MIN };  /* { dg-warning "ISO C restricts enumerator values 
to range of .int." } */
+/* { dg-begin-multiline-output "" }
+   enum { e1 = LLONG_MIN };
+          ^~
+   { dg-end-multiline-output "" } */
+
+  enum { e2 = +LLONG_MIN }; /* { dg-warning "ISO C restricts enumerator values 
to range of .int." } */
+/* { dg-begin-multiline-output "" }
+   enum { e2 = +LLONG_MIN };
+          ^~
+   { dg-end-multiline-output "" } */
+
+}
-- 
1.8.5.3

Reply via email to