]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR preprocessor/7263 - Avoid pedantic warnings on system headers macro tokens
authorDodji Seketeli <dodji@redhat.com>
Wed, 16 May 2012 10:51:15 +0000 (10:51 +0000)
committerDodji Seketeli <dodji@gcc.gnu.org>
Wed, 16 May 2012 10:51:15 +0000 (12:51 +0200)
Now that we track token locations accross macro expansions, it would
be cool to be able to fix PR preprocessor/7263 for real.  That is,
consider this example where we have a system header named header.h
like this:

#define _Complex __complex__ #define _Complex_I 1.0iF

and then a normal C file like this:

    #include "header.h"

    static _Complex float c = _Complex_I;

If we compile the file with -pedantic, the usages of _Complex or
_Complex_I should not trigger any warning, even though __complex__ and
the complex literal are extensions to the standard C.

They shouldn't trigger any warning because _Complex and _Complex_I are
defined in a system header (and expanded in normal user code).

To be able to handle this, we must address two separate concerns.

First, warnings about non-standard usage of numerical literals are emitted
directly from within libcpp.  So we must teach libcpp's parser for numerical
literals to use virtual locations, instead of the spelling
location it uses today.  Once we have that, as the diagnostics machinery
already knows how to avoid emitting errors happening on tokens that come from
system headers, we win.

Second, there is the issue of tracking locations for declaration
specifiers, like the "_Complex" in the declaration:

static _Complex float c;

For that, we need to arrange for each possible declaration specifier
to have its own location, because otherwise, we'd warn on e.g, on:

    _Complex float c;

but not on:

    static _Complex float c;

So this patch addresses the two concerns above.  It's actually a
follow-up on an earlier patch[1] I wrote as part of my initial work on
virtual locations.  We then agreed[2] that the second concern was
important to address before the patch could get a chance to go in.

[1]: http://gcc.gnu.org/ml/gcc-patches/2011-09/msg00957.html
[2]: http://gcc.gnu.org/ml/gcc-patches/2011-10/msg00264.html

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

libcpp/

PR preprocessor/7263
* include/cpplib.h (cpp_classify_number): Take a location
parameter.
* expr.c (SYNTAX_ERROR_AT, SYNTAX_ERROR2_AT): New diagnostic
macros that take a location parameter.
(cpp_classify_number): Take a (virtual) location parameter.  Use
it for diagnostics.  Adjust comments.
(eval_token): Take a location parameter.  Pass it to
cpp_classify_number and to diagnostic routines.
(_cpp_parse_expr): Use virtual locations of tokens when parsing
expressions.  Pass a virtual location to eval_token and to
diagnostic routines.

gcc/c-family/

PR preprocessor/7263
* c-lex.c (c_lex_with_flags):  Pass a virtual location to the call
to cpp_classify_number.  For diagnostics, use the precise location
instead of the global input_location.

gcc/
PR preprocessor/7263
* c-tree.h (enum c_declspec_word): Declare new enum.
(struct c_declspecs::locations): New member.
(declspecs_add_qual, declspecs_add_scspec)
(declspecs_add_addrspace, declspecs_add_alignas): Take a new
location parameter.
* c-decl.c (build_null_declspecs): Initialize the new struct
c_declspecs::locations member.
(declspecs_add_addrspace): Take a location parameter for the
address space.  Store it onto declaration specifiers.
(declspecs_add_qual): Likewise, take a location parameter for the
qualifier.
(declspecs_add_type): Likewise, take a location parameter for the
type specifier.
(declspecs_add_scspec): Likewise, take a location parameter for
the storage class specifier.
(declspecs_add_attrs): Likewise, take a location parameter for the
first attribute.
(declspecs_add_alignas): Likewise, take a location parameter for
the alignas token.
(finish_declspecs): For diagnostics, use the location of the
relevant declspec, instead of the global input_location.
* c-parser.c (c_parser_parameter_declaration): Pass the precise
virtual location of the declspec to the declspecs-setters.
(c_parser_declspecs): Likewise.  Avoid calling c_parser_peek_token
repeatedly.

gcc/cp/

PR preprocessor/7263
* cp-tree.h (enum cp_decl_spec): Add new enumerators to cover all
the possible declarator specifiers so far.
(struct cp_decl_specifier_seq::locations): Declare new member.
(cp_decl_specifier_seq::{specs, type_location}): Remove.
(decl_spec_seq_has_spec_p): Declare new function.
* parser.c (cp_parser_check_decl_spec): Remove.
(set_and_check_decl_spec_loc): Define new static function.
(decl_spec_seq_has_spec_p): Define new public function.
(cp_parser_decl_specifier_seq, cp_parser_function_specifier_opt)
(cp_parser_type_specifier, cp_parser_simple_type_specifier)
(cp_parser_set_storage_class, cp_parser_set_decl_spec_type)
(cp_parser_alias_declaration): Set the locations for each
declspec, using set_and_check_decl_spec_loc.
(cp_parser_explicit_instantiation, cp_parser_init_declarator)
(cp_parser_member_declaration, cp_parser_init_declarator): Use the
new declspec location for specifiers.  Use the new
decl_spec_seq_has_spec_p.
(cp_parser_type_specifier_seq): Use the new
set_and_check_decl_spec_loc.  Stop using
cp_parser_check_decl_spec.  Use the new decl_spec_seq_has_spec_p.
(, cp_parser_init_declarator): Use the new
set_and_check_decl_spec_loc.
(cp_parser_single_declaration, cp_parser_friend_p)
(cp_parser_objc_class_ivars, cp_parser_objc_struct_declaration):
Use the new decl_spec_seq_has_spec_p.
* decl.c (check_tag_decl): Use new decl_spec_seq_has_spec_p.  Use
the more precise ds_redefined_builtin_type_spec location for
diagnostics about re-declaring C++ built-in types.
(start_decl, grokvardecl, grokdeclarator): Use the new
decl_spec_seq_has_spec_p.

gcc/testsuite/

PR preprocessor/7263
* gcc.dg/binary-constants-2.c: Run without tracking locations
accross macro expansion.
* gcc.dg/binary-constants-3.c: Likewise.
* gcc.dg/cpp/sysmac2.c: Likewise.
* testsuite/gcc.dg/nofixed-point-2.c: Adjust for more precise
location.
* gcc.dg/cpp/syshdr3.c: New test.
* gcc.dg/cpp/syshdr3.h: New header for the new test above.
* gcc.dg/system-binary-constants-1.c: New test.
* gcc.dg/system-binary-constants-1.h: New header for the new test
above.
* g++.dg/cpp/syshdr3.C: New test.
* g++.dg/cpp/syshdr3.h: New header the new test above.
* g++.dg/system-binary-constants-1.C: New test.
* g++.dg/system-binary-constants-1.h: New header the new test
above.

From-SVN: r187587

29 files changed:
gcc/ChangeLog
gcc/c-decl.c
gcc/c-family/ChangeLog
gcc/c-family/c-lex.c
gcc/c-parser.c
gcc/c-tree.h
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp/syshdr3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp/syshdr3.h [new file with mode: 0644]
gcc/testsuite/g++.dg/system-binary-constants-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/system-binary-constants-1.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/binary-constants-2.c
gcc/testsuite/gcc.dg/binary-constants-3.c
gcc/testsuite/gcc.dg/cpp/pr7263-3.c
gcc/testsuite/gcc.dg/cpp/syshdr3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/syshdr3.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/sysmac1.c
gcc/testsuite/gcc.dg/cpp/sysmac2.c
gcc/testsuite/gcc.dg/nofixed-point-2.c
gcc/testsuite/gcc.dg/system-binary-constants-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/system-binary-constants-1.h [new file with mode: 0644]
libcpp/ChangeLog
libcpp/expr.c
libcpp/include/cpplib.h

index 2d2260fa45283e203bb4ce11ab1a304f26982d54..9a0d8160028c3313cdf0f6c47df76f9033737555 100644 (file)
@@ -1,3 +1,32 @@
+2012-05-16  Dodji Seketeli  <dodji@redhat.com>
+
+       PR preprocessor/7263
+       * c-tree.h (enum c_declspec_word): Declare new enum.
+       (struct c_declspecs::locations): New member.
+       (declspecs_add_qual, declspecs_add_scspec)
+       (declspecs_add_addrspace, declspecs_add_alignas): Take a new
+       location parameter.
+       * c-decl.c (build_null_declspecs): Initialize the new struct
+       c_declspecs::locations member.
+       (declspecs_add_addrspace): Take a location parameter for the
+       address space.  Store it onto declaration specifiers.
+       (declspecs_add_qual): Likewise, take a location parameter for the
+       qualifier.
+       (declspecs_add_type): Likewise, take a location parameter for the
+       type specifier.
+       (declspecs_add_scspec): Likewise, take a location parameter for
+       the storage class specifier.
+       (declspecs_add_attrs): Likewise, take a location parameter for the
+       first attribute.
+       (declspecs_add_alignas): Likewise, take a location parameter for
+       the alignas token.
+       (finish_declspecs): For diagnostics, use the location of the
+       relevant declspec, instead of the global input_location.
+       * c-parser.c (c_parser_parameter_declaration): Pass the precise
+       virtual location of the declspec to the declspecs-setters.
+       (c_parser_declspecs): Likewise.  Avoid calling c_parser_peek_token
+       repeatedly.
+
 2012-05-16  Igor Zamyatin  <igor.zamyatin@intel.com>
 
        * configure.ac: Stack protector enabling for Android targets.
index 3153cf4e18364d8e55812c5b0aa0b5833402d7ec..41688a7220d061e3a6f0ed2c547e8e7dce09a1c5 100644 (file)
@@ -8787,6 +8787,7 @@ struct c_declspecs *
 build_null_declspecs (void)
 {
   struct c_declspecs *ret = XOBNEW (&parser_obstack, struct c_declspecs);
+  memset (&ret->locations, 0, cdw_number_of_elements);
   ret->type = 0;
   ret->expr = 0;
   ret->decl_attr = 0;
@@ -8824,7 +8825,8 @@ build_null_declspecs (void)
    SPECS, returning SPECS.  */
 
 struct c_declspecs *
-declspecs_add_addrspace (struct c_declspecs *specs, addr_space_t as)
+declspecs_add_addrspace (source_location location,
+                        struct c_declspecs *specs, addr_space_t as)
 {
   specs->non_sc_seen_p = true;
   specs->declspecs_seen_p = true;
@@ -8835,7 +8837,10 @@ declspecs_add_addrspace (struct c_declspecs *specs, addr_space_t as)
           c_addr_space_name (as),
           c_addr_space_name (specs->address_space));
   else
-    specs->address_space = as;
+    {
+      specs->address_space = as;
+      specs->locations[cdw_address_space] = location;
+    }
   return specs;
 }
 
@@ -8843,7 +8848,8 @@ declspecs_add_addrspace (struct c_declspecs *specs, addr_space_t as)
    returning SPECS.  */
 
 struct c_declspecs *
-declspecs_add_qual (struct c_declspecs *specs, tree qual)
+declspecs_add_qual (source_location loc,
+                   struct c_declspecs *specs, tree qual)
 {
   enum rid i;
   bool dupe = false;
@@ -8857,20 +8863,23 @@ declspecs_add_qual (struct c_declspecs *specs, tree qual)
     case RID_CONST:
       dupe = specs->const_p;
       specs->const_p = true;
+      specs->locations[cdw_const] = loc;
       break;
     case RID_VOLATILE:
       dupe = specs->volatile_p;
       specs->volatile_p = true;
+      specs->locations[cdw_volatile] = loc;
       break;
     case RID_RESTRICT:
       dupe = specs->restrict_p;
       specs->restrict_p = true;
+      specs->locations[cdw_restrict] = loc;
       break;
     default:
       gcc_unreachable ();
     }
   if (dupe && !flag_isoc99)
-    pedwarn (input_location, OPT_Wpedantic, "duplicate %qE", qual);
+    pedwarn (loc, OPT_Wpedantic, "duplicate %qE", qual);
   return specs;
 }
 
@@ -8923,6 +8932,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                  pedwarn_c90 (loc, OPT_Wlong_long,
                               "ISO C90 does not support %<long long%>");
                  specs->long_long_p = 1;
+                 specs->locations[cdw_long_long] = loc;
                  break;
                }
              if (specs->short_p)
@@ -8962,7 +8972,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<long%> and %<_Decimal128%> in "
                           "declaration specifiers"));
              else
-               specs->long_p = true;
+               {
+                 specs->long_p = true;
+                 specs->locations[cdw_long] = loc;
+               }
              break;
            case RID_SHORT:
              dupe = specs->short_p;
@@ -9007,7 +9020,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<short%> and %<_Decimal128%> in "
                           "declaration specifiers"));
              else
-               specs->short_p = true;
+               {
+                 specs->short_p = true;
+                 specs->locations[cdw_short] = loc;
+               }
              break;
            case RID_SIGNED:
              dupe = specs->signed_p;
@@ -9044,7 +9060,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<signed%> and %<_Decimal128%> in "
                           "declaration specifiers"));
              else
-               specs->signed_p = true;
+               {
+                 specs->signed_p = true;
+                 specs->locations[cdw_signed] = loc;
+               }
              break;
            case RID_UNSIGNED:
              dupe = specs->unsigned_p;
@@ -9081,11 +9100,14 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<unsigned%> and %<_Decimal128%> in "
                           "declaration specifiers"));
              else
-               specs->unsigned_p = true;
+               {
+                 specs->unsigned_p = true;
+                 specs->locations[cdw_unsigned] = loc;
+               }
              break;
            case RID_COMPLEX:
              dupe = specs->complex_p;
-             if (!flag_isoc99 && !in_system_header)
+             if (!flag_isoc99 && !in_system_header_at (loc))
                pedwarn (loc, OPT_Wpedantic,
                         "ISO C90 does not support complex types");
              if (specs->typespec_word == cts_void)
@@ -9121,7 +9143,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<complex%> and %<_Sat%> in "
                           "declaration specifiers"));
              else
-               specs->complex_p = true;
+               {
+                 specs->complex_p = true;
+                 specs->locations[cdw_complex] = loc;
+               }
              break;
            case RID_SAT:
              dupe = specs->saturating_p;
@@ -9174,7 +9199,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<_Sat%> and %<complex%> in "
                           "declaration specifiers"));
              else
-               specs->saturating_p = true;
+               {
+                 specs->saturating_p = true;
+                 specs->locations[cdw_saturating] = loc;
+               }
              break;
            default:
              gcc_unreachable ();
@@ -9220,7 +9248,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<__int128%> and %<short%> in "
                           "declaration specifiers"));
              else
-               specs->typespec_word = cts_int128;
+               {
+                 specs->typespec_word = cts_int128;
+                 specs->locations[cdw_typespec] = loc;
+               }
              return specs;
            case RID_VOID:
              if (specs->long_p)
@@ -9248,7 +9279,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<_Sat%> and %<void%> in "
                           "declaration specifiers"));
              else
-               specs->typespec_word = cts_void;
+               {
+                 specs->typespec_word = cts_void;
+                 specs->locations[cdw_typespec] = loc;
+               }
              return specs;
            case RID_BOOL:
              if (specs->long_p)
@@ -9276,7 +9310,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<_Sat%> and %<_Bool%> in "
                           "declaration specifiers"));
              else
-               specs->typespec_word = cts_bool;
+               {
+                 specs->typespec_word = cts_bool;
+                 specs->locations[cdw_typespec] = loc;
+               }
              return specs;
            case RID_CHAR:
              if (specs->long_p)
@@ -9292,7 +9329,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<_Sat%> and %<char%> in "
                           "declaration specifiers"));
              else
-               specs->typespec_word = cts_char;
+               {
+                 specs->typespec_word = cts_char;
+                 specs->locations[cdw_typespec] = loc;
+               }
              return specs;
            case RID_INT:
              if (specs->saturating_p)
@@ -9300,7 +9340,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<_Sat%> and %<int%> in "
                           "declaration specifiers"));
              else
-               specs->typespec_word = cts_int;
+               {
+                 specs->typespec_word = cts_int;
+                 specs->locations[cdw_typespec] = loc;
+               }
              return specs;
            case RID_FLOAT:
              if (specs->long_p)
@@ -9324,7 +9367,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<_Sat%> and %<float%> in "
                           "declaration specifiers"));
              else
-               specs->typespec_word = cts_float;
+               {
+                 specs->typespec_word = cts_float;
+                 specs->locations[cdw_typespec] = loc;
+               }
              return specs;
            case RID_DOUBLE:
              if (specs->long_long_p)
@@ -9348,7 +9394,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                          ("both %<_Sat%> and %<double%> in "
                           "declaration specifiers"));
              else
-               specs->typespec_word = cts_double;
+               {
+                 specs->typespec_word = cts_double;
+                 specs->locations[cdw_typespec] = loc;
+               }
              return specs;
            case RID_DFLOAT32:
            case RID_DFLOAT64:
@@ -9402,6 +9451,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                  specs->typespec_word = cts_dfloat64;
                else
                  specs->typespec_word = cts_dfloat128;
+               specs->locations[cdw_typespec] = loc;
              }
              if (!targetm.decimal_float_supported_p ())
                error_at (loc,
@@ -9427,6 +9477,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                    specs->typespec_word = cts_fract;
                else
                    specs->typespec_word = cts_accum;
+               specs->locations[cdw_typespec] = loc;
              }
              if (!targetm.fixed_point_supported_p ())
                error_at (loc,
@@ -9460,6 +9511,7 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
          specs->decl_attr = DECL_ATTRIBUTES (type);
          specs->typedef_p = true;
          specs->explicit_signed_p = C_TYPEDEF_EXPLICITLY_SIGNED (type);
+         specs->locations[cdw_typedef] = loc;
 
          /* If this typedef name is defined in a struct, then a C++
             lookup would return a different value.  */
@@ -9483,13 +9535,17 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
       else if (TREE_TYPE (t) == error_mark_node)
        ;
       else
-       specs->type = TREE_TYPE (t);
+       {
+         specs->type = TREE_TYPE (t);
+         specs->locations[cdw_typespec] = loc;
+       }
     }
   else
     {
       if (TREE_CODE (type) != ERROR_MARK && spec.kind == ctsk_typeof)
        {
          specs->typedef_p = true;
+         specs->locations[cdw_typedef] = loc;
          if (spec.expr)
            {
              if (specs->expr)
@@ -9510,7 +9566,9 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
    declaration specifiers SPECS, returning SPECS.  */
 
 struct c_declspecs *
-declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
+declspecs_add_scspec (source_location loc,
+                     struct c_declspecs *specs,
+                     tree scspec)
 {
   enum rid i;
   enum c_storage_class n = csc_none;
@@ -9531,11 +9589,13 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
         difference between gnu89 and C99 inline.  */
       dupe = false;
       specs->inline_p = true;
+      specs->locations[cdw_inline] = loc;
       break;
     case RID_NORETURN:
       /* Duplicate _Noreturn is permitted.  */
       dupe = false;
       specs->noreturn_p = true;
+      specs->locations[cdw_noreturn] = loc;
       break;
     case RID_THREAD:
       dupe = specs->thread_p;
@@ -9546,7 +9606,10 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
       else if (specs->storage_class == csc_typedef)
        error ("%<__thread%> used with %<typedef%>");
       else
-       specs->thread_p = true;
+       {
+         specs->thread_p = true;
+         specs->locations[cdw_thread] = loc;
+       }
       break;
     case RID_AUTO:
       n = csc_auto;
@@ -9585,6 +9648,7 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
       else
        {
          specs->storage_class = n;
+         specs->locations[cdw_storage_class] = loc;
          if (n != csc_extern && n != csc_static && specs->thread_p)
            {
              error ("%<__thread%> used with %qE", scspec);
@@ -9599,9 +9663,10 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
    returning SPECS.  */
 
 struct c_declspecs *
-declspecs_add_attrs (struct c_declspecs *specs, tree attrs)
+declspecs_add_attrs (source_location loc, struct c_declspecs *specs, tree attrs)
 {
   specs->attrs = chainon (attrs, specs->attrs);
+  specs->locations[cdw_attributes] = loc;
   specs->declspecs_seen_p = true;
   return specs;
 }
@@ -9610,10 +9675,12 @@ declspecs_add_attrs (struct c_declspecs *specs, tree attrs)
    alignment is ALIGN) to the declaration specifiers SPECS, returning
    SPECS.  */
 struct c_declspecs *
-declspecs_add_alignas (struct c_declspecs *specs, tree align)
+declspecs_add_alignas (source_location loc,
+                      struct c_declspecs *specs, tree align)
 {
   int align_log;
   specs->alignas_p = true;
+  specs->locations[cdw_alignas] = loc;
   if (align == error_mark_node)
     return specs;
   align_log = check_user_alignment (align, true);
@@ -9654,9 +9721,11 @@ finish_declspecs (struct c_declspecs *specs)
     {
       if (specs->saturating_p)
        {
-         error ("%<_Sat%> is used without %<_Fract%> or %<_Accum%>");
+         error_at (specs->locations[cdw_saturating],
+                   "%<_Sat%> is used without %<_Fract%> or %<_Accum%>");
          if (!targetm.fixed_point_supported_p ())
-           error ("fixed-point types not supported for this target");
+           error_at (specs->locations[cdw_saturating],
+                     "fixed-point types not supported for this target");
          specs->typespec_word = cts_fract;
        }
       else if (specs->long_p || specs->short_p
@@ -9667,7 +9736,7 @@ finish_declspecs (struct c_declspecs *specs)
       else if (specs->complex_p)
        {
          specs->typespec_word = cts_double;
-         pedwarn (input_location, OPT_Wpedantic,
+         pedwarn (specs->locations[cdw_complex], OPT_Wpedantic,
                   "ISO C does not support plain %<complex%> meaning "
                   "%<double complex%>");
        }
@@ -9712,7 +9781,7 @@ finish_declspecs (struct c_declspecs *specs)
        specs->type = char_type_node;
       if (specs->complex_p)
        {
-         pedwarn (input_location, OPT_Wpedantic,
+         pedwarn (specs->locations[cdw_complex], OPT_Wpedantic,
                   "ISO C does not support complex integer types");
          specs->type = build_complex_type (specs->type);
        }
@@ -9725,7 +9794,7 @@ finish_declspecs (struct c_declspecs *specs)
                     : int128_integer_type_node);
       if (specs->complex_p)
        {
-         pedwarn (input_location, OPT_Wpedantic,
+         pedwarn (specs->locations[cdw_complex], OPT_Wpedantic,
                   "ISO C does not support complex integer types");
          specs->type = build_complex_type (specs->type);
        }
@@ -9751,7 +9820,7 @@ finish_declspecs (struct c_declspecs *specs)
                       : integer_type_node);
       if (specs->complex_p)
        {
-         pedwarn (input_location, OPT_Wpedantic,
+         pedwarn (specs->locations[cdw_complex], OPT_Wpedantic,
                   "ISO C does not support complex integer types");
          specs->type = build_complex_type (specs->type);
        }
index da28510c730615fcd62a7b59d42511ceb7e11410..0229a92000aa022329deac73ac2384890bf55cc3 100644 (file)
@@ -1,3 +1,10 @@
+2012-05-16  Dodji Seketeli  <dodji@redhat.com>
+
+       PR preprocessor/7263
+       * c-lex.c (c_lex_with_flags):  Pass a virtual location to the call
+       to cpp_classify_number.  For diagnostics, use the precise location
+       instead of the global input_location.
+
 2012-05-15  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/11856
index 2a605f65e824217ced1feea0ed2d506963147f94..b122dab308661e11b1d0e3ebaa460b00ff63bad4 100644 (file)
@@ -315,7 +315,7 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags,
     case CPP_NUMBER:
       {
        const char *suffix = NULL;
-       unsigned int flags = cpp_classify_number (parse_in, tok, &suffix);
+       unsigned int flags = cpp_classify_number (parse_in, tok, &suffix, *loc);
 
        switch (flags & CPP_N_CATEGORY)
          {
@@ -417,7 +417,7 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags,
 
        *cpp_spell_token (parse_in, tok, name, true) = 0;
 
-       error ("stray %qs in program", name);
+       error_at (*loc, "stray %qs in program", name);
       }
 
       goto retry;
index 47908f140549fde700dd950ef25efe0293c82b7e..33420ca46229439c9bfe05920c3978a47c788fa8 100644 (file)
@@ -2015,14 +2015,15 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 
       if (c_parser_next_token_is (parser, CPP_NAME))
        {
-         tree value = c_parser_peek_token (parser)->value;
-         c_id_kind kind = c_parser_peek_token (parser)->id_kind;
+         c_token *name_token = c_parser_peek_token (parser);
+         tree value = name_token->value;
+         c_id_kind kind = name_token->id_kind;
 
          if (kind == C_ID_ADDRSPACE)
            {
              addr_space_t as
-               = c_parser_peek_token (parser)->keyword - RID_FIRST_ADDR_SPACE;
-             declspecs_add_addrspace (specs, as);
+               = name_token->keyword - RID_FIRST_ADDR_SPACE;
+             declspecs_add_addrspace (name_token->location, specs, as);
              c_parser_consume_token (parser);
              attrs_ok = true;
              continue;
@@ -2068,7 +2069,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
            }
          t.expr = NULL_TREE;
          t.expr_const_operands = true;
-         declspecs_add_type (loc, specs, t);
+         declspecs_add_type (name_token->location, specs, t);
          continue;
        }
       if (c_parser_next_token_is (parser, CPP_LESS))
@@ -2104,7 +2105,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
          /* TODO: Distinguish between function specifiers (inline, noreturn)
             and storage class specifiers, either here or in
             declspecs_add_scspec.  */
-         declspecs_add_scspec (specs, c_parser_peek_token (parser)->value);
+         declspecs_add_scspec (loc, specs,
+                               c_parser_peek_token (parser)->value);
          c_parser_consume_token (parser);
          break;
        case RID_UNSIGNED:
@@ -2171,18 +2173,18 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
        case RID_VOLATILE:
        case RID_RESTRICT:
          attrs_ok = true;
-         declspecs_add_qual (specs, c_parser_peek_token (parser)->value);
+         declspecs_add_qual (loc, specs, c_parser_peek_token (parser)->value);
          c_parser_consume_token (parser);
          break;
        case RID_ATTRIBUTE:
          if (!attrs_ok)
            goto out;
          attrs = c_parser_attributes (parser);
-         declspecs_add_attrs (specs, attrs);
+         declspecs_add_attrs (loc, specs, attrs);
          break;
        case RID_ALIGNAS:
          align = c_parser_alignas_specifier (parser);
-         declspecs_add_alignas (specs, align);
+         declspecs_add_alignas (loc, specs, align);
          break;
        default:
          goto out;
@@ -3332,7 +3334,7 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
   specs = build_null_declspecs ();
   if (attrs)
     {
-      declspecs_add_attrs (specs, attrs);
+      declspecs_add_attrs (input_location, specs, attrs);
       attrs = NULL_TREE;
     }
   c_parser_declspecs (parser, specs, true, true, true, cla_nonabstract_decl);
index 468cfe4a278999827f88d58d8312ebb33b5b7325..8f8c9d8e01406a4cedfaedee41870094af828ad8 100644 (file)
@@ -222,8 +222,45 @@ enum c_typespec_keyword {
   cts_accum
 };
 
-/* A sequence of declaration specifiers in C.  */
+/* This enum lists all the possible declarator specifiers, storage
+   class or attribute that a user can write.  There is at least one
+   enumerator per possible declarator specifier in the struct
+   c_declspecs below.
+
+   It is used to index the array of declspec locations in struct
+   c_declspecs.  */
+enum c_declspec_word {
+  cdw_typespec /* A catch-all for a typespec.  */,
+  cdw_storage_class  /* A catch-all for a storage class */,
+  cdw_attributes,
+  cdw_typedef,
+  cdw_explicit_signed,
+  cdw_deprecated,
+  cdw_default_int,
+  cdw_long,
+  cdw_long_long,
+  cdw_short,
+  cdw_signed,
+  cdw_unsigned,
+  cdw_complex,
+  cdw_inline,
+  cdw_noreturn,
+  cdw_thread,
+  cdw_const,
+  cdw_volatile,
+  cdw_restrict,
+  cdw_saturating,
+  cdw_alignas,
+  cdw_address_space,
+  cdw_number_of_elements /* This one must always be the last
+                           enumerator.  */
+};
+
+/* A sequence of declaration specifiers in C.  When a new declaration
+   specifier is added, please update the enum c_declspec_word above
+   accordingly.  */
 struct c_declspecs {
+  source_location locations[cdw_number_of_elements];
   /* The type specified, if a single type specifier such as a struct,
      union or enum specifier, typedef name or typeof specifies the
      whole type, or NULL_TREE if none or a keyword such as "void" or
@@ -509,15 +546,20 @@ extern struct c_declarator *build_id_declarator (tree);
 extern struct c_declarator *make_pointer_declarator (struct c_declspecs *,
                                                     struct c_declarator *);
 extern struct c_declspecs *build_null_declspecs (void);
-extern struct c_declspecs *declspecs_add_qual (struct c_declspecs *, tree);
+extern struct c_declspecs *declspecs_add_qual (source_location,
+                                              struct c_declspecs *, tree);
 extern struct c_declspecs *declspecs_add_type (location_t,
                                               struct c_declspecs *,
                                               struct c_typespec);
-extern struct c_declspecs *declspecs_add_scspec (struct c_declspecs *, tree);
-extern struct c_declspecs *declspecs_add_attrs (struct c_declspecs *, tree);
-extern struct c_declspecs *declspecs_add_addrspace (struct c_declspecs *,
+extern struct c_declspecs *declspecs_add_scspec (source_location,
+                                                struct c_declspecs *, tree);
+extern struct c_declspecs *declspecs_add_attrs (source_location,
+                                               struct c_declspecs *, tree);
+extern struct c_declspecs *declspecs_add_addrspace (source_location,
+                                                   struct c_declspecs *,
                                                    addr_space_t);
-extern struct c_declspecs *declspecs_add_alignas (struct c_declspecs *, tree);
+extern struct c_declspecs *declspecs_add_alignas (source_location,
+                                                 struct c_declspecs *, tree);
 extern struct c_declspecs *finish_declspecs (struct c_declspecs *);
 
 /* in c-objc-common.c */
index b0cfbe6027295e301f99bca27a69e6bc7acadee3..9913002f2772adc2ec574b3001950708ad2b70ae 100644 (file)
@@ -1,3 +1,37 @@
+2012-05-16  Dodji Seketeli  <dodji@redhat.com>
+
+       PR preprocessor/7263
+       * cp-tree.h (enum cp_decl_spec): Add new enumerators to cover all
+       the possible declarator specifiers so far.
+       (struct cp_decl_specifier_seq::locations): Declare new member.
+       (cp_decl_specifier_seq::{specs, type_location}): Remove.
+       (decl_spec_seq_has_spec_p): Declare new function.
+       * parser.c (cp_parser_check_decl_spec): Remove.
+       (set_and_check_decl_spec_loc): Define new static function.
+       (decl_spec_seq_has_spec_p): Define new public function.
+       (cp_parser_decl_specifier_seq, cp_parser_function_specifier_opt)
+       (cp_parser_type_specifier, cp_parser_simple_type_specifier)
+       (cp_parser_set_storage_class, cp_parser_set_decl_spec_type)
+       (cp_parser_alias_declaration): Set the locations for each
+       declspec, using set_and_check_decl_spec_loc.
+       (cp_parser_explicit_instantiation, cp_parser_init_declarator)
+       (cp_parser_member_declaration, cp_parser_init_declarator): Use the
+       new declspec location for specifiers.  Use the new
+       decl_spec_seq_has_spec_p.
+       (cp_parser_type_specifier_seq): Use the new
+       set_and_check_decl_spec_loc.  Stop using
+       cp_parser_check_decl_spec.  Use the new decl_spec_seq_has_spec_p.
+       (, cp_parser_init_declarator): Use the new
+       set_and_check_decl_spec_loc.
+       (cp_parser_single_declaration, cp_parser_friend_p)
+       (cp_parser_objc_class_ivars, cp_parser_objc_struct_declaration):
+       Use the new decl_spec_seq_has_spec_p.
+       * decl.c (check_tag_decl): Use new decl_spec_seq_has_spec_p.  Use
+       the more precise ds_redefined_builtin_type_spec location for
+       diagnostics about re-declaring C++ built-in types.
+       (start_decl, grokvardecl, grokdeclarator): Use the new
+       decl_spec_seq_has_spec_p.
+
 2012-05-15  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/11856
index e5ec1d4841f6dbe7b75c1f504efd8370aeac5df1..8eaf766b99dae1ef613cca8c3dee2d508132829b 100644 (file)
@@ -4647,7 +4647,9 @@ typedef enum cp_storage_class {
   sc_mutable
 } cp_storage_class;
 
-/* An individual decl-specifier.  */
+/* An individual decl-specifier.  This is used to index the array of
+   locations for the declspecs in struct cp_decl_specifier_seq
+   below.  */
 
 typedef enum cp_decl_spec {
   ds_first,
@@ -4667,17 +4669,20 @@ typedef enum cp_decl_spec {
   ds_constexpr,
   ds_complex,
   ds_thread,
-  ds_last
+  ds_type_spec,
+  ds_redefined_builtin_type_spec,
+  ds_attribute,
+  ds_storage_class,
+  ds_long_long,
+  ds_last /* This enumerator must always be the last one.  */
 } cp_decl_spec;
 
 /* A decl-specifier-seq.  */
 
 typedef struct cp_decl_specifier_seq {
-  /* The number of times each of the keywords has been seen.  */
-  unsigned specs[(int) ds_last];
-  /* The location of the primary type. Mainly used for error
-     reporting.  */
-  location_t type_location;
+  /* An array of locations for the declaration sepecifiers, indexed by
+     enum cp_decl_spec_word.  */
+  source_location locations[ds_last];
   /* The primary type, if any, given by the decl-specifier-seq.
      Modifiers, like "short", "const", and "unsigned" are not
      reflected here.  This field will be a TYPE, unless a typedef-name
@@ -4827,6 +4832,8 @@ struct GTY((chain_next ("%h.next"))) tinst_level {
   bool in_system_header_p;
 };
 
+bool decl_spec_seq_has_spec_p (const cp_decl_specifier_seq *, cp_decl_spec);
+
 /* Return the type of the `this' parameter of FNTYPE.  */
 
 static inline tree
index 8d7d745176892207b62b178f39c93a84269d1389..fa9fcc8da9b52a35ba33c91a43d8364044bb0cc4 100644 (file)
@@ -4129,8 +4129,8 @@ fixup_anonymous_aggr (tree t)
 tree
 check_tag_decl (cp_decl_specifier_seq *declspecs)
 {
-  int saw_friend = declspecs->specs[(int)ds_friend] != 0;
-  int saw_typedef = declspecs->specs[(int)ds_typedef] != 0;
+  int saw_friend = decl_spec_seq_has_spec_p (declspecs, ds_friend);
+  int saw_typedef = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
   /* If a class, struct, or enum type is declared by the DECLSPECS
      (i.e, if a class-specifier, enum-specifier, or non-typename
      elaborated-type-specifier appears in the DECLSPECS),
@@ -4143,7 +4143,8 @@ check_tag_decl (cp_decl_specifier_seq *declspecs)
   else if (declspecs->redefined_builtin_type)
     {
       if (!in_system_header)
-       permerror (input_location, "redeclaration of C++ built-in type %qT",
+       permerror (declspecs->locations[ds_redefined_builtin_type_spec],
+                  "redeclaration of C++ built-in type %qT",
                   declspecs->redefined_builtin_type);
       return NULL_TREE;
     }
@@ -4198,29 +4199,29 @@ check_tag_decl (cp_decl_specifier_seq *declspecs)
 
   else
     {
-      if (declspecs->specs[(int)ds_inline]
-         || declspecs->specs[(int)ds_virtual])
+      if (decl_spec_seq_has_spec_p (declspecs, ds_inline)
+         || decl_spec_seq_has_spec_p (declspecs, ds_virtual))
        error ("%qs can only be specified for functions",
-              declspecs->specs[(int)ds_inline]
+              decl_spec_seq_has_spec_p (declspecs, ds_inline)
               ? "inline" : "virtual");
       else if (saw_friend
               && (!current_class_type
                   || current_scope () != current_class_type))
        error ("%<friend%> can only be specified inside a class");
-      else if (declspecs->specs[(int)ds_explicit])
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_explicit))
        error ("%<explicit%> can only be specified for constructors");
       else if (declspecs->storage_class)
        error ("a storage class can only be specified for objects "
               "and functions");
-      else if (declspecs->specs[(int)ds_const]
-              || declspecs->specs[(int)ds_volatile]
-              || declspecs->specs[(int)ds_restrict]
-              || declspecs->specs[(int)ds_thread])
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_const)
+              || decl_spec_seq_has_spec_p (declspecs, ds_volatile)
+              || decl_spec_seq_has_spec_p (declspecs, ds_restrict)
+              || decl_spec_seq_has_spec_p (declspecs, ds_thread))
        error ("qualifiers can only be specified for objects "
               "and functions");
       else if (saw_typedef)
        warning (0, "%<typedef%> was ignored in this declaration");
-      else if (declspecs->specs[(int) ds_constexpr])
+      else if (decl_spec_seq_has_spec_p (declspecs,  ds_constexpr))
         error ("%<constexpr%> cannot be used for type declarations");
     }
 
@@ -4472,7 +4473,7 @@ start_decl (const cp_declarator *declarator,
                error ("duplicate initialization of %qD", decl);
              if (duplicate_decls (decl, field, /*newdecl_is_friend=*/false))
                decl = field;
-              if (declspecs->specs[(int) ds_constexpr]
+              if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr)
                   && !DECL_DECLARED_CONSTEXPR_P (field))
                 error ("%qD declared %<constexpr%> outside its class", field);
            }
@@ -7682,7 +7683,7 @@ grokvardecl (tree type,
       TREE_PUBLIC (decl) = DECL_EXTERNAL (decl);
     }
 
-  if (declspecs->specs[(int)ds_thread])
+  if (decl_spec_seq_has_spec_p (declspecs, ds_thread))
     DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
 
   /* If the type of the decl has no linkage, make sure that we'll
@@ -8436,16 +8437,16 @@ grokdeclarator (const cp_declarator *declarator,
   bool parameter_pack_p = declarator? declarator->parameter_pack_p : false;
   bool template_type_arg = false;
   bool template_parm_flag = false;
-  bool constexpr_p = declspecs->specs[(int) ds_constexpr];
+  bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
   const char *errmsg;
 
-  signed_p = declspecs->specs[(int)ds_signed];
-  unsigned_p = declspecs->specs[(int)ds_unsigned];
-  short_p = declspecs->specs[(int)ds_short];
-  long_p = declspecs->specs[(int)ds_long];
-  longlong = declspecs->specs[(int)ds_long] >= 2;
+  signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
+  unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned);
+  short_p = decl_spec_seq_has_spec_p (declspecs, ds_short);
+  long_p = decl_spec_seq_has_spec_p (declspecs, ds_long);
+  longlong = decl_spec_seq_has_spec_p (declspecs, ds_long_long);
   explicit_int128 = declspecs->explicit_int128_p;
-  thread_p = declspecs->specs[(int)ds_thread];
+  thread_p = decl_spec_seq_has_spec_p (declspecs, ds_thread);
 
   if (decl_context == FUNCDEF)
     funcdef_flag = true, decl_context = NORMAL;
@@ -8646,7 +8647,7 @@ grokdeclarator (const cp_declarator *declarator,
 
   if (dname && IDENTIFIER_OPNAME_P (dname))
     {
-      if (declspecs->specs[(int)ds_typedef])
+      if (decl_spec_seq_has_spec_p (declspecs, ds_typedef))
        {
          error ("declaration of %qD as %<typedef%>", dname);
          return error_mark_node;
@@ -8684,7 +8685,7 @@ grokdeclarator (const cp_declarator *declarator,
   if (name == NULL)
     name = decl_context == PARM ? "parameter" : "type name";
 
-  if (constexpr_p && declspecs->specs[(int)ds_typedef])
+  if (constexpr_p && decl_spec_seq_has_spec_p (declspecs, ds_typedef))
     {
       error ("%<constexpr%> cannot appear in a typedef declaration");
       return error_mark_node;
@@ -8910,7 +8911,7 @@ grokdeclarator (const cp_declarator *declarator,
   else if (short_p)
     type = short_integer_type_node;
 
-  if (declspecs->specs[(int)ds_complex])
+  if (decl_spec_seq_has_spec_p (declspecs, ds_complex))
     {
       if (TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE)
        error ("complex invalid for %qs", name);
@@ -8934,11 +8935,11 @@ grokdeclarator (const cp_declarator *declarator,
     }
 
   type_quals = TYPE_UNQUALIFIED;
-  if (declspecs->specs[(int)ds_const])
+  if (decl_spec_seq_has_spec_p (declspecs, ds_const))
     type_quals |= TYPE_QUAL_CONST;
-  if (declspecs->specs[(int)ds_volatile])
+  if (decl_spec_seq_has_spec_p (declspecs, ds_volatile))
     type_quals |= TYPE_QUAL_VOLATILE;
-  if (declspecs->specs[(int)ds_restrict])
+  if (decl_spec_seq_has_spec_p (declspecs, ds_restrict))
     type_quals |= TYPE_QUAL_RESTRICT;
   if (sfk == sfk_conversion && type_quals != TYPE_UNQUALIFIED)
     error ("qualifiers are not allowed on declaration of %<operator %T%>",
@@ -8963,9 +8964,9 @@ grokdeclarator (const cp_declarator *declarator,
   type_quals = cp_type_quals (type);
 
   staticp = 0;
-  inlinep = !! declspecs->specs[(int)ds_inline];
-  virtualp = !! declspecs->specs[(int)ds_virtual];
-  explicitp = !! declspecs->specs[(int)ds_explicit];
+  inlinep = decl_spec_seq_has_spec_p (declspecs, ds_inline);
+  virtualp =  decl_spec_seq_has_spec_p (declspecs, ds_virtual);
+  explicitp = decl_spec_seq_has_spec_p (declspecs, ds_explicit);
 
   storage_class = declspecs->storage_class;
   if (storage_class == sc_static)
@@ -8977,7 +8978,7 @@ grokdeclarator (const cp_declarator *declarator,
       storage_class = sc_none;
       staticp = 0;
     }
-  friendp = !! declspecs->specs[(int)ds_friend];
+  friendp = decl_spec_seq_has_spec_p (declspecs, ds_friend);
 
   if (dependent_name && !friendp)
     {
@@ -8988,7 +8989,7 @@ grokdeclarator (const cp_declarator *declarator,
   /* Issue errors about use of storage classes for parameters.  */
   if (decl_context == PARM)
     {
-      if (declspecs->specs[(int)ds_typedef])
+      if (decl_spec_seq_has_spec_p (declspecs, ds_typedef))
        {
          error ("typedef declaration invalid in parameter declaration");
          return error_mark_node;
@@ -9032,7 +9033,7 @@ grokdeclarator (const cp_declarator *declarator,
       && ((storage_class
           && storage_class != sc_extern
           && storage_class != sc_static)
-         || declspecs->specs[(int)ds_typedef]))
+         || decl_spec_seq_has_spec_p (declspecs, ds_typedef)))
     {
       error ("multiple storage classes in declaration of %qs", name);
       thread_p = false;
@@ -9046,7 +9047,7 @@ grokdeclarator (const cp_declarator *declarator,
          && (storage_class == sc_register
              || storage_class == sc_auto))
        ;
-      else if (declspecs->specs[(int)ds_typedef])
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_typedef))
        ;
       else if (decl_context == FIELD
               /* C++ allows static class elements.  */
@@ -9640,7 +9641,7 @@ grokdeclarator (const cp_declarator *declarator,
              return error_mark_node;
            }
        }
-      else if (declspecs->specs[(int)ds_typedef]
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_typedef)
               && current_class_type)
        {
          error ("cannot declare member %<%T::%s%> within %qT",
@@ -9711,7 +9712,8 @@ grokdeclarator (const cp_declarator *declarator,
          error ("non-member %qs cannot be declared %<mutable%>", name);
          storage_class = sc_none;
        }
-      else if (decl_context == TYPENAME || declspecs->specs[(int)ds_typedef])
+      else if (decl_context == TYPENAME
+              || decl_spec_seq_has_spec_p (declspecs, ds_typedef))
        {
          error ("non-object member %qs cannot be declared %<mutable%>", name);
          storage_class = sc_none;
@@ -9741,7 +9743,7 @@ grokdeclarator (const cp_declarator *declarator,
     }
 
   /* If this is declaring a typedef name, return a TYPE_DECL.  */
-  if (declspecs->specs[(int)ds_typedef] && decl_context != TYPENAME)
+  if (decl_spec_seq_has_spec_p (declspecs, ds_typedef) && decl_context != TYPENAME)
     {
       tree decl;
 
@@ -9853,7 +9855,7 @@ grokdeclarator (const cp_declarator *declarator,
                      memfn_quals != TYPE_UNQUALIFIED,
                      inlinep, friendp, raises != NULL_TREE);
 
-      if (declspecs->specs[(int)ds_alias])
+      if (decl_spec_seq_has_spec_p (declspecs, ds_alias))
        /* Acknowledge that this was written:
             `using analias = atype;'.  */
        TYPE_DECL_ALIAS_P (decl) = 1;
@@ -10352,7 +10354,7 @@ grokdeclarator (const cp_declarator *declarator,
           and `extern' makes no difference.  */
        if (! toplevel_bindings_p ()
            && (storage_class == sc_static
-               || declspecs->specs[(int)ds_inline])
+               || decl_spec_seq_has_spec_p (declspecs, ds_inline))
            && pedantic)
          {
            if (storage_class == sc_static)
index b0544bbb91d6c1963cefc543e09c39fce5bc57f3..aa2324ec7848cfc95a42d16ffac1980e49339a89 100644 (file)
@@ -864,7 +864,7 @@ grokfield (const cp_declarator *declarator,
          cplus_decl_attributes (&value, attrlist, attrflags);
        }
 
-      if (declspecs->specs[(int)ds_typedef]
+      if (decl_spec_seq_has_spec_p (declspecs, ds_typedef)
           && TREE_TYPE (value) != error_mark_node
           && TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (value))) != value)
        set_underlying_type (value);
index dc64fa1f62ae2f91e87315b0b913575f1979559c..2dc8f564fe89b3a862f54aface4f30c0a41266aa 100644 (file)
@@ -2223,6 +2223,9 @@ static void cp_parser_set_storage_class
   (cp_parser *, cp_decl_specifier_seq *, enum rid, location_t);
 static void cp_parser_set_decl_spec_type
   (cp_decl_specifier_seq *, tree, location_t, bool);
+static void set_and_check_decl_spec_loc
+  (cp_decl_specifier_seq *decl_specs,
+   cp_decl_spec ds, source_location location);
 static bool cp_parser_friend_p
   (const cp_decl_specifier_seq *);
 static void cp_parser_required_error
@@ -2494,53 +2497,6 @@ cp_parser_simulate_error (cp_parser* parser)
   return false;
 }
 
-/* Check for repeated decl-specifiers.  */
-
-static void
-cp_parser_check_decl_spec (cp_decl_specifier_seq *decl_specs,
-                          location_t location)
-{
-  int ds;
-
-  for (ds = ds_first; ds != ds_last; ++ds)
-    {
-      unsigned count = decl_specs->specs[ds];
-      if (count < 2)
-       continue;
-      /* The "long" specifier is a special case because of "long long".  */
-      if (ds == ds_long)
-       {
-         if (count > 2)
-           error_at (location, "%<long long long%> is too long for GCC");
-         else 
-           pedwarn_cxx98 (location, OPT_Wlong_long, 
-                          "ISO C++ 1998 does not support %<long long%>");
-       }
-      else if (count > 1)
-       {
-         static const char *const decl_spec_names[] = {
-           "signed",
-           "unsigned",
-           "short",
-           "long",
-           "const",
-           "volatile",
-           "restrict",
-           "inline",
-           "virtual",
-           "explicit",
-           "friend",
-           "typedef",
-           "using",
-            "constexpr",
-           "__complex",
-           "__thread"
-         };
-         error_at (location, "duplicate %qs", decl_spec_names[ds]);
-       }
-    }
-}
-
 /* This function is called when a type is defined.  If type
    definitions are forbidden at this point, an error message is
    issued.  */
@@ -10555,6 +10511,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 {
   bool constructor_possible_p = !parser->in_declarator_p;
   cp_token *start_token = NULL;
+  cp_decl_spec ds;
 
   /* Clear DECL_SPECS.  */
   clear_decl_specs (decl_specs);
@@ -10568,6 +10525,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
       bool constructor_p;
       bool found_decl_spec;
       cp_token *token;
+      ds = ds_last;
 
       /* Peek at the next token.  */
       token = cp_lexer_peek_token (parser->lexer);
@@ -10583,6 +10541,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
          decl_specs->attributes
            = chainon (decl_specs->attributes,
                       cp_parser_attributes_opt (parser));
+         if (decl_specs->locations[ds_attribute] == 0)
+           decl_specs->locations[ds_attribute] = token->location;
          continue;
        }
       /* Assume we will find a decl-specifier keyword.  */
@@ -10602,14 +10562,14 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
            }
          else
            {
-             ++decl_specs->specs[(int) ds_friend];
+             ds = ds_friend;
              /* Consume the token.  */
              cp_lexer_consume_token (parser->lexer);
            }
          break;
 
         case RID_CONSTEXPR:
-          ++decl_specs->specs[(int) ds_constexpr];
+         ds = ds_constexpr;
           cp_lexer_consume_token (parser->lexer);
           break;
 
@@ -10626,7 +10586,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
          /* decl-specifier:
               typedef  */
        case RID_TYPEDEF:
-         ++decl_specs->specs[(int) ds_typedef];
+         ds = ds_typedef;
          /* Consume the token.  */
          cp_lexer_consume_token (parser->lexer);
          /* A constructor declarator cannot appear in a typedef.  */
@@ -10679,8 +10639,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
          break;
        case RID_THREAD:
          /* Consume the token.  */
+         ds = ds_thread;
          cp_lexer_consume_token (parser->lexer);
-         ++decl_specs->specs[(int) ds_thread];
          break;
 
        default:
@@ -10694,13 +10654,16 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
          && token->keyword != RID_CONSTEXPR)
        error ("decl-specifier invalid in condition");
 
+      if (ds != ds_last)
+       set_and_check_decl_spec_loc (decl_specs, ds, token->location);
+
       /* Constructors are a special case.  The `S' in `S()' is not a
         decl-specifier; it is the beginning of the declarator.  */
       constructor_p
        = (!found_decl_spec
           && constructor_possible_p
           && (cp_parser_constructor_declarator_p
-              (parser, decl_specs->specs[(int) ds_friend] != 0)));
+              (parser, decl_spec_seq_has_spec_p (decl_specs, ds_friend))));
 
       /* If we don't have a DECL_SPEC yet, then we must be looking at
         a type-specifier.  */
@@ -10777,12 +10740,10 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
       flags |= CP_PARSER_FLAGS_OPTIONAL;
     }
 
-  cp_parser_check_decl_spec (decl_specs, start_token->location);
-
   /* Don't allow a friend specifier with a class definition.  */
-  if (decl_specs->specs[(int) ds_friend] != 0
+  if (decl_spec_seq_has_spec_p (decl_specs, ds_friend)
       && (*declares_class_or_enum & 2))
-    error_at (start_token->location,
+    error_at (decl_specs->locations[ds_friend],
              "class definition may not be declared a friend");
 }
 
@@ -10843,8 +10804,7 @@ cp_parser_function_specifier_opt (cp_parser* parser,
   switch (token->keyword)
     {
     case RID_INLINE:
-      if (decl_specs)
-       ++decl_specs->specs[(int) ds_inline];
+      set_and_check_decl_spec_loc (decl_specs, ds_inline, token->location);
       break;
 
     case RID_VIRTUAL:
@@ -10853,13 +10813,11 @@ cp_parser_function_specifier_opt (cp_parser* parser,
         A member function template shall not be virtual.  */
       if (PROCESSING_REAL_TEMPLATE_DECL_P ())
        error_at (token->location, "templates may not be %<virtual%>");
-      else if (decl_specs)
-       ++decl_specs->specs[(int) ds_virtual];
+      set_and_check_decl_spec_loc (decl_specs, ds_virtual, token->location);
       break;
 
     case RID_EXPLICIT:
-      if (decl_specs)
-       ++decl_specs->specs[(int) ds_explicit];
+      set_and_check_decl_spec_loc (decl_specs, ds_explicit, token->location);
       break;
 
     default:
@@ -13170,14 +13128,16 @@ cp_parser_explicit_instantiation (cp_parser* parser)
       if (declares_class_or_enum & 2)
        cp_parser_check_for_definition_in_return_type (declarator,
                                                       decl_specifiers.type,
-                                                      decl_specifiers.type_location);
+                                                      decl_specifiers.locations[ds_type_spec]);
       if (declarator != cp_error_declarator)
        {
-         if (decl_specifiers.specs[(int)ds_inline])
-           permerror (input_location, "explicit instantiation shall not use"
+         if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_inline))
+           permerror (decl_specifiers.locations[ds_inline],
+                      "explicit instantiation shall not use"
                       " %<inline%> specifier");
-         if (decl_specifiers.specs[(int)ds_constexpr])
-           permerror (input_location, "explicit instantiation shall not use"
+         if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_constexpr))
+           permerror (decl_specifiers.locations[ds_constexpr],
+                      "explicit instantiation shall not use"
                       " %<constexpr%> specifier");
 
          decl = grokdeclarator (declarator, &decl_specifiers,
@@ -13399,7 +13359,7 @@ cp_parser_type_specifier (cp_parser* parser,
       type_spec
        = (cp_parser_elaborated_type_specifier
           (parser,
-           decl_specs && decl_specs->specs[(int) ds_friend],
+           decl_spec_seq_has_spec_p (decl_specs, ds_friend),
            is_declaration));
       if (decl_specs)
        cp_parser_set_decl_spec_type (decl_specs,
@@ -13440,7 +13400,7 @@ cp_parser_type_specifier (cp_parser* parser,
     {
       if (decl_specs)
        {
-         ++decl_specs->specs[(int)ds];
+         set_and_check_decl_spec_loc (decl_specs, ds, token->location);
          decl_specs->any_specifiers_p = true;
        }
       return cp_lexer_consume_token (parser->lexer)->u.value;
@@ -13531,8 +13491,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       type = boolean_type_node;
       break;
     case RID_SHORT:
-      if (decl_specs)
-       ++decl_specs->specs[(int) ds_short];
+      set_and_check_decl_spec_loc (decl_specs, ds_short, token->location);
       type = short_integer_type_node;
       break;
     case RID_INT:
@@ -13549,17 +13508,15 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       break;
     case RID_LONG:
       if (decl_specs)
-       ++decl_specs->specs[(int) ds_long];
+       set_and_check_decl_spec_loc (decl_specs, ds_long, token->location);
       type = long_integer_type_node;
       break;
     case RID_SIGNED:
-      if (decl_specs)
-       ++decl_specs->specs[(int) ds_signed];
+      set_and_check_decl_spec_loc (decl_specs, ds_signed, token->location);
       type = integer_type_node;
       break;
     case RID_UNSIGNED:
-      if (decl_specs)
-       ++decl_specs->specs[(int) ds_unsigned];
+      set_and_check_decl_spec_loc (decl_specs, ds_unsigned, token->location);
       type = unsigned_type_node;
       break;
     case RID_FLOAT:
@@ -15070,19 +15027,21 @@ static tree
 cp_parser_alias_declaration (cp_parser* parser)
 {
   tree id, type, decl, pushed_scope = NULL_TREE, attributes;
-  location_t id_location;
+  location_t id_location, using_location, attrs_location = 0;
   cp_declarator *declarator;
   cp_decl_specifier_seq decl_specs;
   bool member_p;
   const char *saved_message = NULL;
 
   /* Look for the `using' keyword.  */
+  using_location = cp_lexer_peek_token (parser->lexer)->location;
   cp_parser_require_keyword (parser, RID_USING, RT_USING);
   id_location = cp_lexer_peek_token (parser->lexer)->location;
   id = cp_parser_identifier (parser);
   if (id == error_mark_node)
     return error_mark_node;
 
+  attrs_location = cp_lexer_peek_token (parser->lexer)->location;
   attributes = cp_parser_attributes_opt (parser);
   if (attributes == error_mark_node)
     return error_mark_node;
@@ -15131,9 +15090,19 @@ cp_parser_alias_declaration (cp_parser* parser)
 
   clear_decl_specs (&decl_specs);
   decl_specs.type = type;
-  decl_specs.attributes = attributes;
-  ++decl_specs.specs[(int) ds_typedef];
-  ++decl_specs.specs[(int) ds_alias];
+  if (attributes != NULL_TREE)
+    {
+      decl_specs.attributes = attributes;
+      set_and_check_decl_spec_loc (&decl_specs,
+                                  ds_attribute,
+                                  attrs_location);
+    }
+  set_and_check_decl_spec_loc (&decl_specs,
+                              ds_typedef,
+                              using_location);
+  set_and_check_decl_spec_loc (&decl_specs,
+                              ds_alias,
+                              using_location);
 
   declarator = make_id_declarator (NULL_TREE, id, sfk_none);
   declarator->id_loc = id_location;
@@ -15515,7 +15484,7 @@ cp_parser_init_declarator (cp_parser* parser,
   if (declares_class_or_enum & 2)
     cp_parser_check_for_definition_in_return_type (declarator,
                                                   decl_specifiers->type,
-                                                  decl_specifiers->type_location);
+                                                  decl_specifiers->locations[ds_type_spec]);
 
   /* Figure out what scope the entity declared by the DECLARATOR is
      located in.  `grokdeclarator' sometimes changes the scope, so
@@ -16936,8 +16905,6 @@ cp_parser_type_specifier_seq (cp_parser* parser,
       if (is_declaration && !is_cv_qualifier)
        flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
     }
-
-  cp_parser_check_decl_spec (type_specifier_seq, start_token->location);
 }
 
 /* Parse a parameter-declaration-clause.
@@ -19042,7 +19009,7 @@ cp_parser_member_declaration (cp_parser* parser)
              if (declares_class_or_enum & 2)
                cp_parser_check_for_definition_in_return_type
                                            (declarator, decl_specifiers.type,
-                                            decl_specifiers.type_location);
+                                            decl_specifiers.locations[ds_type_spec]);
 
              /* Look for an asm-specification.  */
              asm_specification = cp_parser_asm_specification_opt (parser);
@@ -21301,7 +21268,7 @@ cp_parser_single_declaration (cp_parser* parser,
     *friend_p = cp_parser_friend_p (&decl_specifiers);
 
   /* There are no template typedefs.  */
-  if (decl_specifiers.specs[(int) ds_typedef])
+  if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_typedef))
     {
       error_at (decl_spec_token_start->location,
                "template declaration of %<typedef%>");
@@ -22049,10 +22016,11 @@ cp_parser_set_storage_class (cp_parser *parser,
     }
 
   if ((keyword == RID_EXTERN || keyword == RID_STATIC)
-      && decl_specs->specs[(int) ds_thread])
+      && decl_spec_seq_has_spec_p (decl_specs, ds_thread))
     {
-      error_at (location, "%<__thread%> before %qD", ridpointers[keyword]);
-      decl_specs->specs[(int) ds_thread] = 0;
+      error_at (decl_specs->locations[ds_thread],
+               "%<__thread%> before %qD", ridpointers[keyword]);
+      decl_specs->locations[ds_thread] = 0;
     }
 
   switch (keyword)
@@ -22076,12 +22044,13 @@ cp_parser_set_storage_class (cp_parser *parser,
       gcc_unreachable ();
     }
   decl_specs->storage_class = storage_class;
+  set_and_check_decl_spec_loc (decl_specs, ds_storage_class, location);
 
   /* A storage class specifier cannot be applied alongside a typedef 
      specifier. If there is a typedef specifier present then set 
      conflicting_specifiers_p which will trigger an error later
      on in grokdeclarator. */
-  if (decl_specs->specs[(int)ds_typedef])
+  if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef))
     decl_specs->conflicting_specifiers_p = true;
 }
 
@@ -22101,24 +22070,27 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs,
      this is what happened.  In system headers, we ignore these
      declarations so that G++ can work with system headers that are not
      C++-safe.  */
-  if (decl_specs->specs[(int) ds_typedef]
+  if (decl_spec_seq_has_spec_p (decl_specs, ds_typedef)
       && !type_definition_p
       && (type_spec == boolean_type_node
          || type_spec == char16_type_node
          || type_spec == char32_type_node
          || type_spec == wchar_type_node)
       && (decl_specs->type
-         || decl_specs->specs[(int) ds_long]
-         || decl_specs->specs[(int) ds_short]
-         || decl_specs->specs[(int) ds_unsigned]
-         || decl_specs->specs[(int) ds_signed]))
+         || decl_spec_seq_has_spec_p (decl_specs, ds_long)
+         || decl_spec_seq_has_spec_p (decl_specs, ds_short)
+         || decl_spec_seq_has_spec_p (decl_specs, ds_unsigned)
+         || decl_spec_seq_has_spec_p (decl_specs, ds_signed)))
     {
       decl_specs->redefined_builtin_type = type_spec;
+      set_and_check_decl_spec_loc (decl_specs,
+                                  ds_redefined_builtin_type_spec,
+                                  location);
       if (!decl_specs->type)
        {
          decl_specs->type = type_spec;
          decl_specs->type_definition_p = false;
-         decl_specs->type_location = location;
+         set_and_check_decl_spec_loc (decl_specs,ds_type_spec, location);
        }
     }
   else if (decl_specs->type)
@@ -22128,17 +22100,96 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs,
       decl_specs->type = type_spec;
       decl_specs->type_definition_p = type_definition_p;
       decl_specs->redefined_builtin_type = NULL_TREE;
-      decl_specs->type_location = location;
+      set_and_check_decl_spec_loc (decl_specs, ds_type_spec, location);
+    }
+}
+
+/* Set the location for a declarator specifier and check if it is
+   duplicated.
+
+   DECL_SPECS is the sequence of declarator specifiers onto which to
+   set the location.
+
+   DS is the single declarator specifier to set which location  is to
+   be set onto the existing sequence of declarators.
+
+   LOCATION is the location for the declarator specifier to
+   consider.  */
+
+static void
+set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
+                            cp_decl_spec ds, source_location location)
+{
+  gcc_assert (ds < ds_last);
+
+  if (decl_specs == NULL)
+    return;
+
+  if (decl_specs->locations[ds] == 0)
+    decl_specs->locations[ds] = location;
+  else
+    {
+      if (ds == ds_long)
+       {
+         if (decl_specs->locations[ds_long_long] != 0)
+           error_at (location,
+                     "%<long long long%> is too long for GCC");
+         else
+           {
+             decl_specs->locations[ds_long_long] = location;
+             pedwarn_cxx98 (location,
+                            OPT_Wlong_long, 
+                            "ISO C++ 1998 does not support %<long long%>");
+           }
+       }
+      else
+       {
+         static const char *const decl_spec_names[] = {
+           "signed",
+           "unsigned",
+           "short",
+           "long",
+           "const",
+           "volatile",
+           "restrict",
+           "inline",
+           "virtual",
+           "explicit",
+           "friend",
+           "typedef",
+           "using",
+            "constexpr",
+           "__complex",
+           "__thread"
+         };
+         error_at (location,
+                   "duplicate %qs", decl_spec_names[ds]);
+       }
     }
 }
 
+/* Return true iff the declarator specifier DS is present in the
+   sequence of declarator specifiers DECL_SPECS.  */
+
+bool
+decl_spec_seq_has_spec_p (const cp_decl_specifier_seq * decl_specs,
+                         cp_decl_spec ds)
+{
+  gcc_assert (ds < ds_last);
+
+  if (decl_specs == NULL)
+    return false;
+
+  return decl_specs->locations[ds] != 0;
+}
+
 /* DECL_SPECIFIERS is the representation of a decl-specifier-seq.
    Returns TRUE iff `friend' appears among the DECL_SPECIFIERS.  */
 
 static bool
 cp_parser_friend_p (const cp_decl_specifier_seq *decl_specifiers)
 {
-  return decl_specifiers->specs[(int) ds_friend] != 0;
+  return decl_spec_seq_has_spec_p (decl_specifiers, ds_friend);
 }
 
 /* Issue an error message indicating that TOKEN_DESC was expected.
@@ -23951,17 +24002,17 @@ cp_parser_objc_class_ivars (cp_parser* parser)
        }
 
       /* __thread.  */
-      if (declspecs.specs[(int) ds_thread])
+      if (decl_spec_seq_has_spec_p (&declspecs, ds_thread))
        {
          cp_parser_error (parser, "invalid type for instance variable");
-         declspecs.specs[(int) ds_thread] = 0;
+         declspecs.locations[ds_thread] = 0;
        }
       
       /* typedef.  */
-      if (declspecs.specs[(int) ds_typedef])
+      if (decl_spec_seq_has_spec_p (&declspecs, ds_typedef))
        {
          cp_parser_error (parser, "invalid type for instance variable");
-         declspecs.specs[(int) ds_typedef] = 0;
+         declspecs.locations[ds_thread] = 0;
        }
 
       prefix_attributes = declspecs.attributes;
@@ -24530,17 +24581,17 @@ cp_parser_objc_struct_declaration (cp_parser *parser)
     }
   
   /* __thread.  */
-  if (declspecs.specs[(int) ds_thread])
+  if (decl_spec_seq_has_spec_p (&declspecs, ds_thread))
     {
       cp_parser_error (parser, "invalid type for property");
-      declspecs.specs[(int) ds_thread] = 0;
+      declspecs.locations[ds_thread] = 0;
     }
   
   /* typedef.  */
-  if (declspecs.specs[(int) ds_typedef])
+  if (decl_spec_seq_has_spec_p (&declspecs, ds_typedef))
     {
       cp_parser_error (parser, "invalid type for property");
-      declspecs.specs[(int) ds_typedef] = 0;
+      declspecs.locations[ds_typedef] = 0;
     }
 
   prefix_attributes = declspecs.attributes;
index fdf43a9d99577e41a67d412f24d8dd6030669a56..ac4f287af0fd9a64cb2efe4452e732309432f874 100644 (file)
@@ -1,3 +1,23 @@
+2012-05-16  Dodji Seketeli  <dodji@redhat.com>
+
+       PR preprocessor/7263
+       * gcc.dg/binary-constants-2.c: Run without tracking locations
+       accross macro expansion.
+       * gcc.dg/binary-constants-3.c: Likewise.
+       * gcc.dg/cpp/sysmac2.c: Likewise.
+       * testsuite/gcc.dg/nofixed-point-2.c: Adjust for more precise
+       location.
+       * gcc.dg/cpp/syshdr3.c: New test.
+       * gcc.dg/cpp/syshdr3.h: New header for the new test above.
+       * gcc.dg/system-binary-constants-1.c: New test.
+       * gcc.dg/system-binary-constants-1.h: New header for the new test
+       above.
+       * g++.dg/cpp/syshdr3.C: New test.
+       * g++.dg/cpp/syshdr3.h: New header the new test above.
+       * g++.dg/system-binary-constants-1.C: New test.
+       * g++.dg/system-binary-constants-1.h: New header the new test
+       above.
+
 2012-05-15  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * g++.old-deja/g++.pt/crash10.C: Adjust post PR11586.
diff --git a/gcc/testsuite/g++.dg/cpp/syshdr3.C b/gcc/testsuite/g++.dg/cpp/syshdr3.C
new file mode 100644 (file)
index 0000000..3916823
--- /dev/null
@@ -0,0 +1,16 @@
+/* Contributed by Dodji Seketeli <dodji@redhat.com> */
+/* Origin: PR preprocessor/7263 */
+/* { dg-options "-pedantic -std=c++98 -ftrack-macro-expansion=1" } */
+/* { dg-do compile } */
+
+/* This tests the proprer suppression of warning coming from macro
+   defined in system headers and expanded in a non-system header
+   location.  */
+#include "syshdr3.h"
+
+static _Complex float c = _Complex_I + _Complex_I; /* These macros are defined in
+                                                   system header so we should
+                                                   have no warning here.  */
+U_LL u = ONE_ULL; /* Likewise here.  */
+
+unsigned long long v = 1ULL; /* { dg-warning "long long" } */
diff --git a/gcc/testsuite/g++.dg/cpp/syshdr3.h b/gcc/testsuite/g++.dg/cpp/syshdr3.h
new file mode 100644 (file)
index 0000000..e5d502a
--- /dev/null
@@ -0,0 +1,7 @@
+#pragma GCC system_header
+
+#define _Complex __complex__
+#define _Complex_I 1.0iF
+
+#define U_LL unsigned long long
+#define ONE_ULL 1ULL
diff --git a/gcc/testsuite/g++.dg/system-binary-constants-1.C b/gcc/testsuite/g++.dg/system-binary-constants-1.C
new file mode 100644 (file)
index 0000000..7ef26f7
--- /dev/null
@@ -0,0 +1,18 @@
+/* 
+   Origin: Dodji Seketeli <dodji@redhat.com>
+   { dg-options "-std=c++98 -pedantic" }
+   { dg-do compile } 
+ */
+
+#include "system-binary-constants-1.h"
+
+int
+foo (void)
+{
+#if BINARY_INT_CONSTANT_IN_SYSTEM_HEADER /* A binary constant defined
+                                           in system header.  No
+                                           warning.  */
+  return 23;
+#endif
+  return 0b1101; /* { dg-warning "binary constants are a GCC extension" } */
+}
diff --git a/gcc/testsuite/g++.dg/system-binary-constants-1.h b/gcc/testsuite/g++.dg/system-binary-constants-1.h
new file mode 100644 (file)
index 0000000..85f2917
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma GCC system_header
+
+#define BINARY_INT_CONSTANT_IN_SYSTEM_HEADER 0b1101
index 40d7636465668e234d521025898af88b1d561898..6c3928aa2a08a6511b308dcc43c1c8a8d3e834ab 100644 (file)
@@ -2,7 +2,7 @@
 
 /* Origin: Joerg Wunsch <j.gnu@uriah.heep.sax.de>.  */
 /* { dg-do compile } */
-/* { dg-options "-std=iso9899:1999 -pedantic" } */
+/* { dg-options "-std=iso9899:1999 -pedantic -ftrack-macro-expansion=0" } */
 
 #define FOO 0b1101
 
index 984477dca18162aaa47f749f7eea2e0d0aff04e8..410fc4cd7256f7c0dbce0dabc2b39150b899a4e5 100644 (file)
@@ -2,7 +2,7 @@
 
 /* Origin: Joerg Wunsch <j.gnu@uriah.heep.sax.de>.  */
 /* { dg-do compile } */
-/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors -ftrack-macro-expansion=0" } */
 
 #define FOO 0b1101
 
index efa619ad3cd392487d1db5a7495647e8a20093ba..225b659754c2f7a5581ce1f8893182f209bd87f5 100644 (file)
@@ -1,6 +1,6 @@
 /* PR 7263:  __extension__ keyword doesn't suppress warning on LL or ULL constants.  */
 /* { dg-do compile } */
-/* { dg-options "-std=c99 -pedantic-errors" } */
+/* { dg-options "-std=c99 -pedantic-errors -ftrack-macro-expansion=0" } */
 #include "pr7263-3.h"
 __complex__  bar () /* { dg-error "ISO C does not support plain .complex. meaning .double complex." } */
 {
diff --git a/gcc/testsuite/gcc.dg/cpp/syshdr3.c b/gcc/testsuite/gcc.dg/cpp/syshdr3.c
new file mode 100644 (file)
index 0000000..15749ff
--- /dev/null
@@ -0,0 +1,16 @@
+/* Contributed by Dodji Seketeli <dodji@redhat.com> */
+/* Origin: PR preprocessor/7263 */
+/* { dg-options "-pedantic -std=c89 -ftrack-macro-expansion=1" } */
+/* { dg-do compile } */
+
+/* This tests the proprer suppression of warning coming from macro
+   defined in system headers and expanded in a non-system header
+   location.  */
+#include "syshdr3.h"
+
+static _Complex float c = _Complex_I + _Complex_I; /* These macros are defined in
+                                                   system header so we should
+                                                   have no warning here.  */
+U_LL u = ONE_ULL; /* Likewise here.  */
+
+unsigned long long v = 1ULL; /* { dg-warning "long long" } */
diff --git a/gcc/testsuite/gcc.dg/cpp/syshdr3.h b/gcc/testsuite/gcc.dg/cpp/syshdr3.h
new file mode 100644 (file)
index 0000000..e5d502a
--- /dev/null
@@ -0,0 +1,7 @@
+#pragma GCC system_header
+
+#define _Complex __complex__
+#define _Complex_I 1.0iF
+
+#define U_LL unsigned long long
+#define ONE_ULL 1ULL
index fa741a4262daef461035935f74c8a77eb4adfa11..cc8469e18c71dc722e12d61b85185a0fb0c1b097 100644 (file)
@@ -1,7 +1,7 @@
 /* Copyright (C) 2001 Free Software Foundation, Inc.  */
 
 /* { dg-do preprocess } */
-/* { dg-options "-std=gnu99 -pedantic -Wtraditional" } */
+/* { dg-options "-std=gnu99 -pedantic -Wtraditional -ftrack-macro-expansion=0" } */
 
 /* Tests diagnostics are suppressed for some macros defined in system
    headers.  */
index 6d493a9ed1b1d1b2f605e6ba9c5e8f1d0d9e2bee..cdba668a03fc99d1dcf758630319b61ad4943fbb 100644 (file)
@@ -1,7 +1,7 @@
 /* Copyright (C) 2001 Free Software Foundation, Inc.  */
 
 /* { dg-do compile } */
-/* { dg-options "-std=gnu99 -pedantic -Wtraditional" } */
+/* { dg-options "-std=gnu99 -pedantic -Wtraditional -ftrack-macro-expansion=0" } */
 
 /* Tests diagnostics are suppressed for some macros defined in system
    headers.  */
index 5b2f209501889b502512e8f408fed28b99d93e00..8442a1984cfa48d1c8b937faa67d2e3673059097 100644 (file)
@@ -20,10 +20,10 @@ f3 (void)
   return 0k;                   /* { dg-error "not supported" "reject fixed-point" } */
 }
 
-_Sat
-f4 (void)                      /* { dg-error "not supported" "reject fixed-point" } */
+_Sat                            /* { dg-error "not supported" "reject fixed-point" } */
+f4 (void)
 {
   return 0k;                   /* { dg-error "not supported" "reject fixed-point" } */
 }
 
-/* { dg-error "is used without" "" { target *-*-* } 24 } */
+/* { dg-error "is used without" "" { target *-*-* } 23 } */
diff --git a/gcc/testsuite/gcc.dg/system-binary-constants-1.c b/gcc/testsuite/gcc.dg/system-binary-constants-1.c
new file mode 100644 (file)
index 0000000..921ee20
--- /dev/null
@@ -0,0 +1,18 @@
+/* 
+   Origin: Dodji Seketeli <dodji@redhat.com>
+   { dg-options "-std=iso9899:1999 -pedantic" } 
+   { dg-do compile } 
+ */
+
+#include "system-binary-constants-1.h"
+
+int
+foo (void)
+{
+#if BINARY_INT_CONSTANT_IN_SYSTEM_HEADER /* A binary constant defined
+                                           in system header.  No
+                                           warning.  */
+  return 23;
+#endif
+  return 0b1101; /* { dg-warning "binary constants are a GCC extension" } */
+}
diff --git a/gcc/testsuite/gcc.dg/system-binary-constants-1.h b/gcc/testsuite/gcc.dg/system-binary-constants-1.h
new file mode 100644 (file)
index 0000000..85f2917
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma GCC system_header
+
+#define BINARY_INT_CONSTANT_IN_SYSTEM_HEADER 0b1101
index 07ef2437834512ca60487e5c0f9bce0baf67458f..842f834aff17b55a8e11f3b2cc84bd0832b0a5a6 100644 (file)
@@ -1,3 +1,18 @@
+2012-05-16  Dodji Seketeli  <dodji@redhat.com>
+
+       PR preprocessor/7263
+       * include/cpplib.h (cpp_classify_number): Take a location
+       parameter.
+       * expr.c (SYNTAX_ERROR_AT, SYNTAX_ERROR2_AT): New diagnostic
+       macros that take a location parameter.
+       (cpp_classify_number): Take a (virtual) location parameter.  Use
+       it for diagnostics.  Adjust comments.
+       (eval_token): Take a location parameter.  Pass it to
+       cpp_classify_number and to diagnostic routines.
+       (_cpp_parse_expr): Use virtual locations of tokens when parsing
+       expressions.  Pass a virtual location to eval_token and to
+       diagnostic routines.
+
 2012-05-10  Tristan Gingold  <gingold@adacore.com>
 
        * expr.c (interpret_float_suffix): Add a guard.
index ca1c3d1928a9fa9c34baf9049b7baa8989d181a2..cd6e7d4eca67bb82db22b76e815a74078a6e01bb 100644 (file)
@@ -59,7 +59,7 @@ static cpp_num num_rshift (cpp_num, size_t, size_t);
 
 static cpp_num append_digit (cpp_num, int, int, size_t);
 static cpp_num parse_defined (cpp_reader *);
-static cpp_num eval_token (cpp_reader *, const cpp_token *);
+static cpp_num eval_token (cpp_reader *, const cpp_token *, source_location);
 static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype);
 static unsigned int interpret_float_suffix (const uchar *, size_t);
 static unsigned int interpret_int_suffix (const uchar *, size_t);
@@ -76,6 +76,12 @@ static void check_promotion (cpp_reader *, const struct op *);
 #define SYNTAX_ERROR2(msgid, arg) \
   do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \
   while(0)
+#define SYNTAX_ERROR_AT(loc, msgid) \
+  do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, msgid); goto syntax_error; } \
+  while(0)
+#define SYNTAX_ERROR2_AT(loc, msgid, arg)                                      \
+  do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, msgid, arg); goto syntax_error; } \
+  while(0)
 
 /* Subroutine of cpp_classify_number.  S points to a float suffix of
    length LEN, possibly zero.  Returns 0 for an invalid suffix, or a
@@ -359,11 +365,18 @@ cpp_get_userdef_suffix (const cpp_token *tok)
 
 /* Categorize numeric constants according to their field (integer,
    floating point, or invalid), radix (decimal, octal, hexadecimal),
-   and type suffixes.  In C++0X if UD_SUFFIX is non null it will be
-   assigned any unrecognized suffix for a user-defined literal.  */
+   and type suffixes.
+
+   TOKEN is the token that represents the numeric constant to
+   classify.
+
+   In C++0X if UD_SUFFIX is non null it will be assigned
+   any unrecognized suffix for a user-defined literal.
+
+   VIRTUAL_LOCATION is the virtual location for TOKEN.  */
 unsigned int
 cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
-                    const char **ud_suffix)
+                    const char **ud_suffix, source_location virtual_location)
 {
   const uchar *str = token->val.str.text;
   const uchar *limit;
@@ -422,7 +435,8 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
          if (float_flag == NOT_FLOAT)
            float_flag = AFTER_POINT;
          else
-           SYNTAX_ERROR ("too many decimal points in number");
+           SYNTAX_ERROR_AT (virtual_location,
+                            "too many decimal points in number");
        }
       else if ((radix <= 10 && (c == 'e' || c == 'E'))
               || (radix == 16 && (c == 'p' || c == 'P')))
@@ -450,8 +464,8 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
            radix = 10;
 
          if (CPP_PEDANTIC (pfile))
-           cpp_error (pfile, CPP_DL_PEDWARN,
-                      "fixed-point constants are a GCC extension");
+           cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
+                                "fixed-point constants are a GCC extension");
          goto syntax_ok;
        }
       else
@@ -464,26 +478,29 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
   if (max_digit >= radix)
     {
       if (radix == 2)
-       SYNTAX_ERROR2 ("invalid digit \"%c\" in binary constant", '0' + max_digit);
+       SYNTAX_ERROR2_AT (virtual_location,
+                         "invalid digit \"%c\" in binary constant", '0' + max_digit);
       else
-       SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit);
+       SYNTAX_ERROR2_AT (virtual_location,
+                         "invalid digit \"%c\" in octal constant", '0' + max_digit);
     }
 
   if (float_flag != NOT_FLOAT)
     {
       if (radix == 2)
        {
-         cpp_error (pfile, CPP_DL_ERROR,
-                    "invalid prefix \"0b\" for floating constant");
+         cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
+                              "invalid prefix \"0b\" for floating constant");
          return CPP_N_INVALID;
        }
 
       if (radix == 16 && !seen_digit)
-       SYNTAX_ERROR ("no digits in hexadecimal floating constant");
+       SYNTAX_ERROR_AT (virtual_location,
+                        "no digits in hexadecimal floating constant");
 
       if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99))
-       cpp_error (pfile, CPP_DL_PEDWARN,
-                  "use of C99 hexadecimal floating constant");
+       cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
+                            "use of C99 hexadecimal floating constant");
 
       if (float_flag == AFTER_EXPON)
        {
@@ -492,14 +509,15 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
 
          /* Exponent is decimal, even if string is a hex float.  */
          if (!ISDIGIT (*str))
-           SYNTAX_ERROR ("exponent has no digits");
+           SYNTAX_ERROR_AT (virtual_location, "exponent has no digits");
 
          do
            str++;
          while (ISDIGIT (*str));
        }
       else if (radix == 16)
-       SYNTAX_ERROR ("hexadecimal floating constants require an exponent");
+       SYNTAX_ERROR_AT (virtual_location,
+                        "hexadecimal floating constants require an exponent");
 
       result = interpret_float_suffix (str, limit - str);
       if (result == 0)
@@ -512,9 +530,9 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
            }
          else
            {
-             cpp_error (pfile, CPP_DL_ERROR,
-                        "invalid suffix \"%.*s\" on floating constant",
-                        (int) (limit - str), str);
+             cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
+                                  "invalid suffix \"%.*s\" on floating constant",
+                                  (int) (limit - str), str);
              return CPP_N_INVALID;
            }
        }
@@ -523,33 +541,33 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
       if (limit != str
          && CPP_WTRADITIONAL (pfile)
          && ! cpp_sys_macro_p (pfile))
-       cpp_warning (pfile, CPP_W_TRADITIONAL,
-                    "traditional C rejects the \"%.*s\" suffix",
-                    (int) (limit - str), str);
+       cpp_warning_with_line (pfile, CPP_W_TRADITIONAL, virtual_location, 0,
+                              "traditional C rejects the \"%.*s\" suffix",
+                              (int) (limit - str), str);
 
       /* A suffix for double is a GCC extension via decimal float support.
         If the suffix also specifies an imaginary value we'll catch that
         later.  */
       if ((result == CPP_N_MEDIUM) && CPP_PEDANTIC (pfile))
-       cpp_error (pfile, CPP_DL_PEDWARN,
-                  "suffix for double constant is a GCC extension");
+       cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
+                            "suffix for double constant is a GCC extension");
 
       /* Radix must be 10 for decimal floats.  */
       if ((result & CPP_N_DFLOAT) && radix != 10)
         {
-          cpp_error (pfile, CPP_DL_ERROR,
-                     "invalid suffix \"%.*s\" with hexadecimal floating constant",
-                     (int) (limit - str), str);
+          cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
+                              "invalid suffix \"%.*s\" with hexadecimal floating constant",
+                              (int) (limit - str), str);
           return CPP_N_INVALID;
         }
 
       if ((result & (CPP_N_FRACT | CPP_N_ACCUM)) && CPP_PEDANTIC (pfile))
-       cpp_error (pfile, CPP_DL_PEDWARN,
-                  "fixed-point constants are a GCC extension");
+       cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
+                            "fixed-point constants are a GCC extension");
 
       if ((result & CPP_N_DFLOAT) && CPP_PEDANTIC (pfile))
-       cpp_error (pfile, CPP_DL_PEDWARN,
-                  "decimal float constants are a GCC extension");
+       cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
+                            "decimal float constants are a GCC extension");
 
       result |= CPP_N_FLOATING;
     }
@@ -566,9 +584,9 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
            }
          else
            {
-             cpp_error (pfile, CPP_DL_ERROR,
-                        "invalid suffix \"%.*s\" on integer constant",
-                        (int) (limit - str), str);
+             cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
+                                  "invalid suffix \"%.*s\" on integer constant",
+                                  (int) (limit - str), str);
              return CPP_N_INVALID;
            }
        }
@@ -582,9 +600,10 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
                       && CPP_OPTION (pfile, cpp_warn_long_long);
 
          if (u_or_i || large)
-           cpp_warning (pfile, large ? CPP_W_LONG_LONG : CPP_W_TRADITIONAL,
-                        "traditional C rejects the \"%.*s\" suffix",
-                        (int) (limit - str), str);
+           cpp_warning_with_line (pfile, large ? CPP_W_LONG_LONG : CPP_W_TRADITIONAL,
+                                  virtual_location, 0,
+                                  "traditional C rejects the \"%.*s\" suffix",
+                                  (int) (limit - str), str);
        }
 
       if ((result & CPP_N_WIDTH) == CPP_N_LARGE
@@ -595,9 +614,11 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
                                : N_("use of C99 long long integer constant");
 
          if (CPP_OPTION (pfile, c99))
-            cpp_warning (pfile, CPP_W_LONG_LONG, message);
+            cpp_warning_with_line (pfile, CPP_W_LONG_LONG, virtual_location,
+                                  0, message);
           else
-            cpp_pedwarning (pfile, CPP_W_LONG_LONG, message);
+            cpp_pedwarning_with_line (pfile, CPP_W_LONG_LONG,
+                                     virtual_location, 0, message);
         }
 
       result |= CPP_N_INTEGER;
@@ -605,11 +626,11 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
 
  syntax_ok:
   if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile))
-    cpp_error (pfile, CPP_DL_PEDWARN,
-              "imaginary constants are a GCC extension");
+    cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
+                        "imaginary constants are a GCC extension");
   if (radix == 2 && CPP_PEDANTIC (pfile))
-    cpp_error (pfile, CPP_DL_PEDWARN,
-              "binary constants are a GCC extension");
+    cpp_error_with_line (pfile, CPP_DL_PEDWARN, virtual_location, 0,
+                        "binary constants are a GCC extension");
 
   if (radix == 10)
     result |= CPP_N_DECIMAL;
@@ -897,7 +918,8 @@ parse_defined (cpp_reader *pfile)
    number or character constant, or the result of the "defined" or "#"
    operators).  */
 static cpp_num
-eval_token (cpp_reader *pfile, const cpp_token *token)
+eval_token (cpp_reader *pfile, const cpp_token *token,
+           source_location virtual_location)
 {
   cpp_num result;
   unsigned int temp;
@@ -909,21 +931,21 @@ eval_token (cpp_reader *pfile, const cpp_token *token)
   switch (token->type)
     {
     case CPP_NUMBER:
-      temp = cpp_classify_number (pfile, token, NULL);
+      temp = cpp_classify_number (pfile, token, NULL, virtual_location);
       if (temp & CPP_N_USERDEF)
        cpp_error (pfile, CPP_DL_ERROR,
                   "user-defined literal in preprocessor expression");
       switch (temp & CPP_N_CATEGORY)
        {
        case CPP_N_FLOATING:
-         cpp_error (pfile, CPP_DL_ERROR,
-                    "floating constant in preprocessor expression");
+         cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
+                              "floating constant in preprocessor expression");
          break;
        case CPP_N_INTEGER:
          if (!(temp & CPP_N_IMAGINARY))
            return cpp_interpret_integer (pfile, token, temp);
-         cpp_error (pfile, CPP_DL_ERROR,
-                    "imaginary number in preprocessor expression");
+         cpp_error_with_line (pfile, CPP_DL_ERROR, virtual_location, 0,
+                              "imaginary number in preprocessor expression");
          break;
 
        case CPP_N_INVALID:
@@ -970,8 +992,9 @@ eval_token (cpp_reader *pfile, const cpp_token *token)
          result.high = 0;
          result.low = 0;
          if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
-           cpp_warning (pfile, CPP_W_UNDEF, "\"%s\" is not defined",
-                        NODE_NAME (token->val.node.node));
+           cpp_warning_with_line (pfile, CPP_W_UNDEF, virtual_location, 0,
+                                  "\"%s\" is not defined",
+                                  NODE_NAME (token->val.node.node));
        }
       break;
 
@@ -981,11 +1004,12 @@ eval_token (cpp_reader *pfile, const cpp_token *token)
          /* A pedantic warning takes precedence over a deprecated
             warning here.  */
          if (CPP_PEDANTIC (pfile))
-           cpp_error (pfile, CPP_DL_PEDWARN,
-                      "assertions are a GCC extension");
+           cpp_error_with_line (pfile, CPP_DL_PEDWARN,
+                                virtual_location, 0,
+                                "assertions are a GCC extension");
          else if (CPP_OPTION (pfile, cpp_warn_deprecated))
-           cpp_warning (pfile, CPP_W_DEPRECATED,
-                        "assertions are a deprecated extension");
+           cpp_warning_with_line (pfile, CPP_W_DEPRECATED, virtual_location, 0,
+                                  "assertions are a deprecated extension");
        }
       _cpp_test_assertion (pfile, &temp);
       result.high = 0;
@@ -1087,6 +1111,7 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if)
   struct op *top = pfile->op_stack;
   unsigned int lex_count;
   bool saw_leading_not, want_value = true;
+  source_location virtual_location = 0;
 
   pfile->state.skip_eval = 0;
 
@@ -1103,9 +1128,9 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if)
       struct op op;
 
       lex_count++;
-      op.token = cpp_get_token (pfile);
+      op.token = cpp_get_token_with_location (pfile, &virtual_location);
       op.op = op.token->type;
-      op.loc = op.token->src_loc;
+      op.loc = virtual_location;
 
       switch (op.op)
        {
@@ -1118,10 +1143,11 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if)
        case CPP_NAME:
        case CPP_HASH:
          if (!want_value)
-           SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
-                          cpp_token_as_text (pfile, op.token));
+           SYNTAX_ERROR2_AT (op.loc,
+                             "missing binary operator before token \"%s\"",
+                             cpp_token_as_text (pfile, op.token));
          want_value = false;
-         top->value = eval_token (pfile, op.token);
+         top->value = eval_token (pfile, op.token, op.loc);
          continue;
 
        case CPP_NOT:
@@ -1138,8 +1164,9 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if)
 
        default:
          if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
-           SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions",
-                          cpp_token_as_text (pfile, op.token));
+           SYNTAX_ERROR2_AT (op.loc,
+                             "token \"%s\" is not valid in preprocessor expressions",
+                             cpp_token_as_text (pfile, op.token));
          break;
        }
 
@@ -1147,27 +1174,32 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if)
       if (optab[op.op].flags & NO_L_OPERAND)
        {
          if (!want_value)
-           SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
-                          cpp_token_as_text (pfile, op.token));
+           SYNTAX_ERROR2_AT (op.loc,
+                             "missing binary operator before token \"%s\"",
+                             cpp_token_as_text (pfile, op.token));
        }
       else if (want_value)
        {
          /* We want a number (or expression) and haven't got one.
             Try to emit a specific diagnostic.  */
          if (op.op == CPP_CLOSE_PAREN && top->op == CPP_OPEN_PAREN)
-           SYNTAX_ERROR ("missing expression between '(' and ')'");
+           SYNTAX_ERROR_AT (op.loc,
+                            "missing expression between '(' and ')'");
 
          if (op.op == CPP_EOF && top->op == CPP_EOF)
-           SYNTAX_ERROR2 ("%s with no expression", is_if ? "#if" : "#elif");
+           SYNTAX_ERROR2_AT (op.loc,
+                             "%s with no expression", is_if ? "#if" : "#elif");
 
          if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN)
-           SYNTAX_ERROR2 ("operator '%s' has no right operand",
-                          cpp_token_as_text (pfile, top->token));
+           SYNTAX_ERROR2_AT (op.loc,
+                             "operator '%s' has no right operand",
+                             cpp_token_as_text (pfile, top->token));
          else if (op.op == CPP_CLOSE_PAREN || op.op == CPP_EOF)
            /* Complain about missing paren during reduction.  */;
          else
-           SYNTAX_ERROR2 ("operator '%s' has no left operand",
-                          cpp_token_as_text (pfile, op.token));
+           SYNTAX_ERROR2_AT (op.loc,
+                             "operator '%s' has no left operand",
+                             cpp_token_as_text (pfile, op.token));
        }
 
       top = reduce (pfile, top, op.op);
@@ -1192,7 +1224,8 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if)
          break;
        case CPP_COLON:
          if (top->op != CPP_QUERY)
-           SYNTAX_ERROR (" ':' without preceding '?'");
+           SYNTAX_ERROR_AT (op.loc,
+                            " ':' without preceding '?'");
          if (!num_zerop (top[-1].value)) /* Was '?' condition true?  */
            pfile->state.skip_eval++;
          else
@@ -1209,7 +1242,7 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if)
 
       top->op = op.op;
       top->token = op.token;
-      top->loc = op.token->src_loc;
+      top->loc = op.loc;
     }
 
   /* The controlling macro expression is only valid if we called lex 3
@@ -1220,8 +1253,9 @@ _cpp_parse_expr (cpp_reader *pfile, bool is_if)
 
   if (top != pfile->op_stack)
     {
-      cpp_error (pfile, CPP_DL_ICE, "unbalanced stack in %s",
-                is_if ? "#if" : "#elif");
+      cpp_error_with_line (pfile, CPP_DL_ICE, top->loc, 0,
+                          "unbalanced stack in %s",
+                          is_if ? "#if" : "#elif");
     syntax_error:
       return false;  /* Return false on syntax error.  */
     }
index 9dbc477b61e88cd220464847b33786f88b193c2a..2ec7eaaae2f95b8a8379134421e67c5a7bf2de45 100644 (file)
@@ -851,7 +851,7 @@ struct cpp_num
 /* Classify a CPP_NUMBER token.  The return value is a combination of
    the flags from the above sets.  */
 extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *,
-                                    const char **);
+                                    const char **, source_location);
 
 /* Return the classification flags for a float suffix.  */
 extern unsigned int cpp_interpret_float_suffix (const char *, size_t);