diff mbox

PR preprocessor/7263 - Avoid pedantic warnings on system headers macro tokens

Message ID m3txznx6qf.fsf@redhat.com
State New
Headers show

Commit Message

Dodji Seketeli May 10, 2012, 5:53 p.m. UTC
Jason Merrill <jason@redhat.com> writes:

> It seems like for most of the declspecs, having both the location and
> a flag/count is unnecessary; instead of checking the flag, we can
> check whether the location is set.  That won't work for the "long long
> long" check, but it should work for the others.  You'll need to change
> _check_decl_spec to take the new declspec and location rather than
> have it iterate every time, but that seems worth doing anyway.
>
> So I don't think we need both cp_decl_spec and cp_decl_spec_word.

OK.  I have done this.

I have removed cp_parser_check_decl_spec completely, and instead,
introduced a new function set_and_check_decl_spec_loc that sets the
location for a given decl spec, and does the check there.  I hope this
does what you had in mind.

>
>>        error_at (location, "%<__thread%> before %qD", ridpointers[keyword]);
>>        decl_specs->specs[(int) ds_thread] = 0;
>> +      decl_specs->locations[cpdw_thread] = location;
>
> This error should use the stored __thread location, and then set it to
> 0 rather than the location argument.

Oops, right.  Fixed.

>
>> +      decl_specs->locations[cpdw_builtin_type_spec] = location;
>>        if (!decl_specs->type)
>>  	{
>>  	  decl_specs->type = type_spec;
>>  	  decl_specs->type_definition_p = false;
>> -	  decl_specs->type_location = location;
>> +	  decl_specs->locations[cpdw_type_spec] = location;
>
> Why do we need cpdw_builtin_type_spec?

[... ]

> I agree that cpdw_type_spec makes sense.  I just don't see why we need
> the _builtin_ variant.

Oops.  My bad.  I didn't finish what I wanted to do.

I wanted to be able to use the precise location of the redefined type
when we permerror about that redefinition, in check_tag_decl.

Finished in the patch below.

Is it a bit better?

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

Thanks.

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.
---
 gcc/c-decl.c                                     |  127 +++++++++---
 gcc/c-family/c-lex.c                             |    4 +-
 gcc/c-parser.c                                   |   22 +-
 gcc/c-tree.h                                     |   54 ++++-
 gcc/cp/cp-tree.h                                 |   21 ++-
 gcc/cp/decl.c                                    |   80 ++++----
 gcc/cp/decl2.c                                   |    2 +-
 gcc/cp/parser.c                                  |  255 +++++++++++++---------
 gcc/testsuite/g++.dg/cpp/syshdr3.C               |   16 ++
 gcc/testsuite/g++.dg/cpp/syshdr3.h               |    7 +
 gcc/testsuite/g++.dg/system-binary-constants-1.C |   18 ++
 gcc/testsuite/g++.dg/system-binary-constants-1.h |    3 +
 gcc/testsuite/gcc.dg/binary-constants-2.c        |    2 +-
 gcc/testsuite/gcc.dg/binary-constants-3.c        |    2 +-
 gcc/testsuite/gcc.dg/cpp/pr7263-3.c              |    2 +-
 gcc/testsuite/gcc.dg/cpp/syshdr3.c               |   16 ++
 gcc/testsuite/gcc.dg/cpp/syshdr3.h               |    7 +
 gcc/testsuite/gcc.dg/cpp/sysmac1.c               |    2 +-
 gcc/testsuite/gcc.dg/cpp/sysmac2.c               |    2 +-
 gcc/testsuite/gcc.dg/nofixed-point-2.c           |    6 +-
 gcc/testsuite/gcc.dg/system-binary-constants-1.c |   18 ++
 gcc/testsuite/gcc.dg/system-binary-constants-1.h |    3 +
 libcpp/expr.c                                    |  182 +++++++++-------
 libcpp/include/cpplib.h                          |    2 +-
 24 files changed, 573 insertions(+), 280 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp/syshdr3.C
 create mode 100644 gcc/testsuite/g++.dg/cpp/syshdr3.h
 create mode 100644 gcc/testsuite/g++.dg/system-binary-constants-1.C
 create mode 100644 gcc/testsuite/g++.dg/system-binary-constants-1.h
 create mode 100644 gcc/testsuite/gcc.dg/cpp/syshdr3.c
 create mode 100644 gcc/testsuite/gcc.dg/cpp/syshdr3.h
 create mode 100644 gcc/testsuite/gcc.dg/system-binary-constants-1.c
 create mode 100644 gcc/testsuite/gcc.dg/system-binary-constants-1.h

Comments

Jason Merrill May 14, 2012, 6:08 p.m. UTC | #1
On 05/10/2012 01:53 PM, Dodji Seketeli wrote:
> +      if (found_decl_spec && ds != ds_last)

Do we still need found_decl_spec?

> +	  if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_inline))
>  	    permerror (input_location, "explicit instantiation shall not use"
>  		       " %<inline%> specifier");
> -	  if (decl_specifiers.specs[(int)ds_constexpr])
> +	  if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_constexpr))
>  	    permerror (input_location, "explicit instantiation shall not use"

These can use the specifier locations, right?

Jason
diff mbox

Patch

diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index e34c843..605f0b4 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -8785,6 +8785,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;
@@ -8822,7 +8823,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;
@@ -8833,7 +8835,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;
 }
 
@@ -8841,7 +8846,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;
@@ -8855,20 +8861,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;
 }
 
@@ -8921,6 +8930,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)
@@ -8960,7 +8970,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;
@@ -9005,7 +9018,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;
@@ -9042,7 +9058,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;
@@ -9079,11 +9098,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)
@@ -9119,7 +9141,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;
@@ -9172,7 +9197,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 ();
@@ -9218,7 +9246,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)
@@ -9246,7 +9277,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)
@@ -9274,7 +9308,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)
@@ -9290,7 +9327,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)
@@ -9298,7 +9338,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)
@@ -9322,7 +9365,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)
@@ -9346,7 +9392,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:
@@ -9400,6 +9449,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,
@@ -9425,6 +9475,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,
@@ -9458,6 +9509,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.  */
@@ -9481,13 +9533,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)
@@ -9508,7 +9564,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;
@@ -9529,11 +9587,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;
@@ -9544,7 +9604,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;
@@ -9583,6 +9646,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);
@@ -9597,9 +9661,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;
 }
@@ -9608,10 +9673,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);
@@ -9652,9 +9719,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
@@ -9665,7 +9734,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%>");
 	}
@@ -9710,7 +9779,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);
 	}
@@ -9723,7 +9792,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);
 	}
@@ -9749,7 +9818,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);
 	}
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index 2a605f6..b122dab 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -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;
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index 87e43dc..85e12eb 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -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);
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index db60935..151e533 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -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 */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5a7ebae..b450e52 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4643,7 +4643,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,
@@ -4663,17 +4665,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
@@ -4823,6 +4828,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
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 40818a3..de89ae3 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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)
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 34c969c..4f7b996 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index f0f7e98..1bb47ee 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2221,6 +2221,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
@@ -2492,53 +2495,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.  */
@@ -10544,6 +10500,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);
@@ -10557,6 +10514,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);
@@ -10572,6 +10530,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.  */
@@ -10591,14 +10551,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;
 
@@ -10615,7 +10575,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.  */
@@ -10668,8 +10628,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:
@@ -10683,13 +10643,16 @@  cp_parser_decl_specifier_seq (cp_parser* parser,
 	  && token->keyword != RID_CONSTEXPR)
 	error ("decl-specifier invalid in condition");
 
+      if (found_decl_spec && 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.  */
@@ -10766,12 +10729,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");
 }
 
@@ -10832,8 +10793,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:
@@ -10842,13 +10802,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:
@@ -13155,13 +13113,13 @@  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])
+	  if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_inline))
 	    permerror (input_location, "explicit instantiation shall not use"
 		       " %<inline%> specifier");
-	  if (decl_specifiers.specs[(int)ds_constexpr])
+	  if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_constexpr))
 	    permerror (input_location, "explicit instantiation shall not use"
 		       " %<constexpr%> specifier");
 
@@ -13384,7 +13342,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,
@@ -13425,7 +13383,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;
@@ -13516,8 +13474,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:
@@ -13534,17 +13491,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:
@@ -15055,19 +15010,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;
@@ -15116,9 +15073,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;
@@ -15500,7 +15467,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
@@ -16921,8 +16888,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.
@@ -19027,7 +18992,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);
@@ -21286,7 +21251,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%>");
@@ -22031,10 +21996,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)
@@ -22058,12 +22024,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;
 }
 
@@ -22083,24 +22050,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)
@@ -22110,17 +22080,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.
@@ -23933,17 +23982,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;
@@ -24512,17 +24561,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;
diff --git a/gcc/testsuite/g++.dg/cpp/syshdr3.C b/gcc/testsuite/g++.dg/cpp/syshdr3.C
new file mode 100644
index 0000000..3916823
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp/syshdr3.C
@@ -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
index 0000000..e5d502a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp/syshdr3.h
@@ -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
index 0000000..7ef26f7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/system-binary-constants-1.C
@@ -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
index 0000000..85f2917
--- /dev/null
+++ b/gcc/testsuite/g++.dg/system-binary-constants-1.h
@@ -0,0 +1,3 @@ 
+#pragma GCC system_header
+
+#define BINARY_INT_CONSTANT_IN_SYSTEM_HEADER 0b1101
diff --git a/gcc/testsuite/gcc.dg/binary-constants-2.c b/gcc/testsuite/gcc.dg/binary-constants-2.c
index 40d7636..6c3928a 100644
--- a/gcc/testsuite/gcc.dg/binary-constants-2.c
+++ b/gcc/testsuite/gcc.dg/binary-constants-2.c
@@ -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
 
diff --git a/gcc/testsuite/gcc.dg/binary-constants-3.c b/gcc/testsuite/gcc.dg/binary-constants-3.c
index 984477d..410fc4c 100644
--- a/gcc/testsuite/gcc.dg/binary-constants-3.c
+++ b/gcc/testsuite/gcc.dg/binary-constants-3.c
@@ -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
 
diff --git a/gcc/testsuite/gcc.dg/cpp/pr7263-3.c b/gcc/testsuite/gcc.dg/cpp/pr7263-3.c
index efa619a..225b659 100644
--- a/gcc/testsuite/gcc.dg/cpp/pr7263-3.c
+++ b/gcc/testsuite/gcc.dg/cpp/pr7263-3.c
@@ -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
index 0000000..15749ff
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/syshdr3.c
@@ -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
index 0000000..e5d502a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/syshdr3.h
@@ -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/gcc.dg/cpp/sysmac1.c b/gcc/testsuite/gcc.dg/cpp/sysmac1.c
index fa741a4..cc8469e 100644
--- a/gcc/testsuite/gcc.dg/cpp/sysmac1.c
+++ b/gcc/testsuite/gcc.dg/cpp/sysmac1.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.dg/cpp/sysmac2.c b/gcc/testsuite/gcc.dg/cpp/sysmac2.c
index 6d493a9..cdba668 100644
--- a/gcc/testsuite/gcc.dg/cpp/sysmac2.c
+++ b/gcc/testsuite/gcc.dg/cpp/sysmac2.c
@@ -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.  */
diff --git a/gcc/testsuite/gcc.dg/nofixed-point-2.c b/gcc/testsuite/gcc.dg/nofixed-point-2.c
index 5b2f209..8442a19 100644
--- a/gcc/testsuite/gcc.dg/nofixed-point-2.c
+++ b/gcc/testsuite/gcc.dg/nofixed-point-2.c
@@ -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
index 0000000..921ee20
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/system-binary-constants-1.c
@@ -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
index 0000000..85f2917
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/system-binary-constants-1.h
@@ -0,0 +1,3 @@ 
+#pragma GCC system_header
+
+#define BINARY_INT_CONSTANT_IN_SYSTEM_HEADER 0b1101
diff --git a/libcpp/expr.c b/libcpp/expr.c
index d56e56a..41c9880 100644
--- a/libcpp/expr.c
+++ b/libcpp/expr.c
@@ -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
@@ -358,11 +364,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;
@@ -421,7 +434,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')))
@@ -449,8 +463,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
@@ -463,26 +477,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)
 	{
@@ -491,14 +508,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)
@@ -511,9 +529,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;
 	    }
 	}
@@ -522,33 +540,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;
     }
@@ -565,9 +583,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;
 	    }
 	}
@@ -581,9 +599,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
@@ -594,9 +613,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;
@@ -604,11 +625,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;
@@ -896,7 +917,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;
@@ -908,21 +930,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:
@@ -969,8 +991,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;
 
@@ -980,11 +1003,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;
@@ -1086,6 +1110,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;
 
@@ -1102,9 +1127,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)
 	{
@@ -1117,10 +1142,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:
@@ -1137,8 +1163,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;
 	}
 
@@ -1146,27 +1173,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);
@@ -1191,7 +1223,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
@@ -1208,7 +1241,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
@@ -1219,8 +1252,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.  */
     }
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 9dbc477..2ec7eaa 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -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);