diff mbox

[6/7] Kill pedantic warnings on system headers macros

Message ID eb911fb157ccaa1a8822486fde0dac2feca750ac.1310824121.git.dodji@redhat.com
State New
Headers show

Commit Message

Dodji Seketeli July 16, 2011, 2:37 p.m. UTC
This patch leverages the virtual location infrastructure to avoid
emitting pedantic warnings related to macros defined in system headers
but expanded in normal TUs.

The point is to make diagnostic routines use virtual locations of
tokens instead of their spelling locations. The diagnostic routines in
turn indirectly use linemap_location_in_system_header_p to know if a
given virtual location originated from a system header.

The patch has two main parts.

The libcpp part makes diagnostic routines called from the preprocessor
expression parsing and number conversion code use virtual
locations.

The C FE part makes diagnostic routines called from the type
specifiers validation code use virtual locations.

This fixes the relevant examples presented in the comments of the bug
but I guess, as usual, libcpp and the FEs will need on-going care to
use more and more virtual locations of tokens instead of spelling
locations.

The combination of the patch and the previous ones boostrapped with
--enable-languages=all,ada and passed regression tests on
x86_64-unknown-linux-gnu.

libcpp/

	* include/cpplib.h (cpp_classify_number): Add a location parameter
	to the declaration.
	* internal.h (_cpp_get_prev_token_spelling_loc): Declare.
	* lex.c (_cpp_get_prev_token_spelling_loc): Factorize this from ...
	* errors.c (cpp_diagnostic): ... here.
	* expr.c (SYNTAX_ERROR_AT, SYNTAX_ERROR2_AT): New macros to emit
	syntax error using a virtual location.
	(cpp_classify_number): Add a virtual location parameter. Use
	SYNTAX_ERROR_AT instead of SYNTAX_ERROR, cpp_error_with_line
	instead of cpp_error and cpp_warning_with_line instead of
	cpp_warning. Pass the new virtual location parameter to those
	diagnostic routines.
	(eval_token): Add a virtual location parameter. Pass it down to
	cpp_classify_number. Use cpp_error_with_line instead of cpp_error,
	cpp_warning_with_line instead of cpp_warning, and pass the new
	virtual location parameter to these.
	(_cpp_parse_expr): Use cpp_get_token_with_location instead of
	cpp_get_token, to get the virtual location of the token. Use
	SYNTAX_ERROR2_AT instead of SYNTAX_ERROR2, cpp_error_with_line
	instead of cpp_error. Use the virtual location instead of the
	spelling location.
	* macro.c (maybe_adjust_loc_for_trad_cpp): Define new static
	function.
	(cpp_get_token_with_location): Use it.

gcc/c-family

	* c-lex.c (c_lex_with_flags): Adjust to pass the virtual location
	to cpp_classify_number.

gcc/

	* c-tree.h (finish_declspecs): Add a virtual location parameter.
	* c-decl.c (finish_declspecs): Add a virtual location
	parameter. Use error_at instead of error and pass down the virtual
	location to pewarn and error_at.
	(declspecs_add_type): Use in_system_header_at instead of
	in_system_header.
	* c-parser.c (c_parser_declaration_or_fndef): Pass virtual
	location of the relevant token to finish_declspecs.
	(c_parser_struct_declaration, c_parser_parameter_declaration):
	Likewise.
	(c_parser_type_name): Likewise.

gcc/testsuite/

	* gcc.dg/cpp/syshdr3.h: New test header.
	* gcc.dg/cpp/syshdr3.c: New test file.
	* gcc.dg/nofixed-point-2.c: Adjust to more precise location.
---
 gcc/c-decl.c                           |   17 ++--
 gcc/c-family/c-lex.c                   |    4 +-
 gcc/c-parser.c                         |   12 ++-
 gcc/c-tree.h                           |    2 +-
 gcc/testsuite/gcc.dg/cpp/syshdr3.c     |   16 +++
 gcc/testsuite/gcc.dg/cpp/syshdr3.h     |    7 ++
 gcc/testsuite/gcc.dg/nofixed-point-2.c |    6 +-
 libcpp/errors.c                        |   21 +----
 libcpp/expr.c                          |  176 +++++++++++++++++++-------------
 libcpp/include/cpplib.h                |    3 +-
 libcpp/internal.h                      |    1 +
 libcpp/lex.c                           |   29 +++++
 12 files changed, 183 insertions(+), 111 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/cpp/syshdr3.c
 create mode 100644 gcc/testsuite/gcc.dg/cpp/syshdr3.h

Comments

Jason Merrill Sept. 12, 2011, 9:53 p.m. UTC | #1
On 07/16/2011 10:37 AM, Dodji Seketeli wrote:
> +  location_t here = c_parser_peek_token (parser)->location;

Perhaps "first_token_loc"?  It's unfortunate that we don't retain the 
locations of the individual declspecs, but I don't expect you to fix that.

> +           SYNTAX_ERROR2_AT (prev_virtual_location,
> +                             "missing binary operator before token \"%s\"",
> +                             cpp_token_as_text (pfile, op.token));

It seems to me that the "missing X before" errors should point to the 
current token, not the previous one.  So you can drop prev_virtual_location.

Jason
diff mbox

Patch

diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 3ed3c46..d2f013b 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -8910,7 +8910,7 @@  declspecs_add_type (location_t loc, struct c_declspecs *specs,
 	      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_pedantic,
 			 "ISO C90 does not support complex types");
 	      if (specs->typespec_word == cts_void)
@@ -9433,7 +9433,8 @@  declspecs_add_attrs (struct c_declspecs *specs, tree attrs)
    double".  */
 
 struct c_declspecs *
-finish_declspecs (struct c_declspecs *specs)
+finish_declspecs (struct c_declspecs *specs,
+		  location_t where)
 {
   /* If a type was specified as a whole, we have no modifiers and are
      done.  */
@@ -9458,9 +9459,9 @@  finish_declspecs (struct c_declspecs *specs)
     {
       if (specs->saturating_p)
 	{
-	  error ("%<_Sat%> is used without %<_Fract%> or %<_Accum%>");
+	  error_at (where, "%<_Sat%> is used without %<_Fract%> or %<_Accum%>");
 	  if (!targetm.fixed_point_supported_p ())
-	    error ("fixed-point types not supported for this target");
+	    error_at (where, "fixed-point types not supported for this target");
 	  specs->typespec_word = cts_fract;
 	}
       else if (specs->long_p || specs->short_p
@@ -9471,7 +9472,7 @@  finish_declspecs (struct c_declspecs *specs)
       else if (specs->complex_p)
 	{
 	  specs->typespec_word = cts_double;
-	  pedwarn (input_location, OPT_pedantic,
+	  pedwarn (where, OPT_pedantic,
 		   "ISO C does not support plain %<complex%> meaning "
 		   "%<double complex%>");
 	}
@@ -9516,7 +9517,7 @@  finish_declspecs (struct c_declspecs *specs)
 	specs->type = char_type_node;
       if (specs->complex_p)
 	{
-	  pedwarn (input_location, OPT_pedantic,
+	  pedwarn (where, OPT_pedantic,
 		   "ISO C does not support complex integer types");
 	  specs->type = build_complex_type (specs->type);
 	}
@@ -9529,7 +9530,7 @@  finish_declspecs (struct c_declspecs *specs)
 		     : int128_integer_type_node);
       if (specs->complex_p)
 	{
-	  pedwarn (input_location, OPT_pedantic,
+	  pedwarn (where, OPT_pedantic,
 		   "ISO C does not support complex integer types");
 	  specs->type = build_complex_type (specs->type);
 	}
@@ -9555,7 +9556,7 @@  finish_declspecs (struct c_declspecs *specs)
 		       : integer_type_node);
       if (specs->complex_p)
 	{
-	  pedwarn (input_location, OPT_pedantic,
+	  pedwarn (where, OPT_pedantic,
 		   "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 be83b61..ca088a8 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -314,7 +314,7 @@  c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags,
 
     case CPP_NUMBER:
       {
-	unsigned int flags = cpp_classify_number (parse_in, tok);
+	unsigned int flags = cpp_classify_number (parse_in, tok, *loc);
 
 	switch (flags & CPP_N_CATEGORY)
 	  {
@@ -397,7 +397,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 65966a9..7c5755d 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -1459,7 +1459,7 @@  c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       c_parser_skip_to_end_of_block_or_statement (parser);
       return;
     }
-  finish_declspecs (specs);
+  finish_declspecs (specs, here);
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
     {
       if (empty_ok)
@@ -2555,7 +2555,7 @@  c_parser_struct_declaration (c_parser *parser)
       c_parser_error (parser, "expected specifier-qualifier-list");
       return NULL_TREE;
     }
-  finish_declspecs (specs);
+  finish_declspecs (specs, decl_loc);
   if (c_parser_next_token_is (parser, CPP_SEMICOLON)
       || c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
     {
@@ -3218,6 +3218,8 @@  c_parser_parameter_declaration (c_parser *parser, tree attrs)
   tree prefix_attrs;
   tree postfix_attrs = NULL_TREE;
   bool dummy = false;
+  location_t here = c_parser_peek_token (parser)->location;
+
   if (!c_parser_next_token_starts_declspecs (parser))
     {
       c_token *token = c_parser_peek_token (parser);
@@ -3244,7 +3246,7 @@  c_parser_parameter_declaration (c_parser *parser, tree attrs)
       attrs = NULL_TREE;
     }
   c_parser_declspecs (parser, specs, true, true, true, cla_nonabstract_decl);
-  finish_declspecs (specs);
+  finish_declspecs (specs, here);
   pending_xref_error ();
   prefix_attrs = specs->attrs;
   specs->attrs = NULL_TREE;
@@ -3536,6 +3538,8 @@  c_parser_type_name (c_parser *parser)
   struct c_declarator *declarator;
   struct c_type_name *ret;
   bool dummy = false;
+  location_t here = c_parser_peek_token (parser)->location;
+
   c_parser_declspecs (parser, specs, false, true, true, cla_prefer_type);
   if (!specs->declspecs_seen_p)
     {
@@ -3545,7 +3549,7 @@  c_parser_type_name (c_parser *parser)
   if (specs->type != error_mark_node)
     {
       pending_xref_error ();
-      finish_declspecs (specs);
+      finish_declspecs (specs, here);
     }
   declarator = c_parser_declarator (parser,
 				    specs->typespec_kind != ctsk_none,
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index 95a0ba2..a5deb05 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -492,7 +492,7 @@  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 *,
 						    addr_space_t);
-extern struct c_declspecs *finish_declspecs (struct c_declspecs *);
+extern struct c_declspecs *finish_declspecs (struct c_declspecs *, location_t);
 
 /* in c-objc-common.c */
 extern bool c_objc_common_init (void);
diff --git a/gcc/testsuite/gcc.dg/cpp/syshdr3.c b/gcc/testsuite/gcc.dg/cpp/syshdr3.c
new file mode 100644
index 0000000..8850410
--- /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"
+
+_Complex 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/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/libcpp/errors.c b/libcpp/errors.c
index 13804f0..4139183 100644
--- a/libcpp/errors.c
+++ b/libcpp/errors.c
@@ -38,26 +38,7 @@  cpp_diagnostic (cpp_reader * pfile, int level, int reason,
   source_location src_loc;
   bool ret;
 
-  if (CPP_OPTION (pfile, traditional))
-    {
-      if (pfile->state.in_directive)
-	src_loc = pfile->directive_line;
-      else
-	src_loc = LINEMAPS_ORDINARY_HIGHEST_LINE (pfile->line_table);
-    }
-  /* We don't want to refer to a token before the beginning of the
-     current run -- that is invalid.  */
-  else if (pfile->cur_token == pfile->cur_run->base)
-    {
-      if (pfile->cur_run->prev != NULL)
-	src_loc = pfile->cur_run->prev->limit->src_loc;
-      else
-	src_loc = 0;
-    }
-  else
-    {
-      src_loc = pfile->cur_token[-1].src_loc;
-    }
+  src_loc = _cpp_get_prev_token_spelling_loc (pfile);
 
   if (!pfile->cb.error)
     abort ();
diff --git a/libcpp/expr.c b/libcpp/expr.c
index 3c36127..953dbc5 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
@@ -223,7 +229,8 @@  interpret_int_suffix (const uchar *s, size_t len)
    floating point, or invalid), radix (decimal, octal, hexadecimal),
    and type suffixes.  */
 unsigned int
-cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
+cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
+		     source_location virtual_location)
 {
   const uchar *str = token->val.str.text;
   const uchar *limit;
@@ -279,7 +286,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')))
@@ -307,8 +315,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
@@ -321,26 +329,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)
 	{
@@ -349,21 +360,22 @@  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)
 	{
-	  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;
 	}
 
@@ -371,33 +383,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;
     }
@@ -406,9 +418,9 @@  cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
       result = interpret_int_suffix (str, limit - str);
       if (result == 0)
 	{
-	  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;
 	}
 
@@ -421,9 +433,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
@@ -434,9 +447,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;
@@ -444,11 +459,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;
@@ -736,7 +751,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;
@@ -748,18 +764,18 @@  eval_token (cpp_reader *pfile, const cpp_token *token)
   switch (token->type)
     {
     case CPP_NUMBER:
-      temp = cpp_classify_number (pfile, token);
+      temp = cpp_classify_number (pfile, token, virtual_location);
       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:
@@ -806,8 +822,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;
 
@@ -817,11 +834,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;
@@ -923,6 +941,8 @@  _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,
+    prev_virtual_location = _cpp_get_prev_token_spelling_loc (pfile);
 
   pfile->state.skip_eval = 0;
 
@@ -939,9 +959,12 @@  _cpp_parse_expr (cpp_reader *pfile, bool is_if)
       struct op op;
 
       lex_count++;
-      op.token = cpp_get_token (pfile);
+
+      if (virtual_location)
+	prev_virtual_location = virtual_location;
+      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)
 	{
@@ -954,10 +977,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 (prev_virtual_location,
+			      "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, virtual_location);
 	  continue;
 
 	case CPP_NOT:
@@ -974,8 +998,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;
 	}
 
@@ -983,27 +1008,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 (prev_virtual_location,
+			      "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);
@@ -1028,7 +1058,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
@@ -1045,7 +1076,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
@@ -1056,8 +1087,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 9e1bf67..a295267 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -827,7 +827,8 @@  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 *);
+extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *,
+				     source_location);
 
 /* Evaluate a token classified as category CPP_N_INTEGER.  */
 extern cpp_num cpp_interpret_integer (cpp_reader *, const cpp_token *,
diff --git a/libcpp/internal.h b/libcpp/internal.h
index 7470508..d7f4c78 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -645,6 +645,7 @@  extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
 extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
 extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
 extern int _cpp_remaining_tokens_num_in_context (cpp_reader *);
+extern source_location _cpp_get_prev_token_spelling_loc (cpp_reader *);
 
 /* In init.c.  */
 extern void _cpp_maybe_push_include_file (cpp_reader *);
diff --git a/libcpp/lex.c b/libcpp/lex.c
index 4bd8e71..8562805 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -2877,3 +2877,32 @@  cpp_token_val_index (cpp_token *tok)
       return CPP_TOKEN_FLD_NONE;
     }
 }
+
+/* Return the location of the previous token in the token stream.  */
+
+source_location
+_cpp_get_prev_token_spelling_loc (cpp_reader *pfile)
+{
+  source_location spelling_loc;
+
+  if (CPP_OPTION (pfile, traditional))
+    {
+      if (pfile->state.in_directive)
+	spelling_loc = pfile->directive_line;
+      else
+	spelling_loc = LINEMAPS_ORDINARY_HIGHEST_LINE (pfile->line_table);
+    }
+  /* We don't want to refer to a token before the beginning of the
+     current run -- that is invalid.  */
+  else if (pfile->cur_token == pfile->cur_run->base)
+    {
+      if (pfile->cur_run->prev != NULL)
+	spelling_loc = pfile->cur_run->prev->limit->src_loc;
+      else
+	spelling_loc = 0;
+    }
+  else
+    spelling_loc = pfile->cur_token[-1].src_loc;
+
+  return spelling_loc;
+}