@@ -20,6 +20,7 @@ pub use Flag::*;
2020pub use Piece :: * ;
2121pub use Position :: * ;
2222
23+ use rustc_lexer:: unescape;
2324use std:: iter;
2425use std:: str;
2526use std:: string;
@@ -306,7 +307,7 @@ impl<'a> Parser<'a> {
306307 append_newline : bool ,
307308 mode : ParseMode ,
308309 ) -> Parser < ' a > {
309- let ( width_map, is_literal) = find_width_map_from_snippet ( snippet, style) ;
310+ let ( width_map, is_literal) = find_width_map_from_snippet ( s , snippet, style) ;
310311 Parser {
311312 mode,
312313 input : s,
@@ -844,6 +845,7 @@ impl<'a> Parser<'a> {
844845/// written code (code snippet) and the `InternedString` that gets processed in the `Parser`
845846/// in order to properly synthesise the intra-string `Span`s for error diagnostics.
846847fn find_width_map_from_snippet (
848+ input : & str ,
847849 snippet : Option < string:: String > ,
848850 str_style : Option < usize > ,
849851) -> ( Vec < InnerWidthMapping > , bool ) {
@@ -856,8 +858,27 @@ fn find_width_map_from_snippet(
856858 return ( vec ! [ ] , true ) ;
857859 }
858860
861+ // Strip quotes.
859862 let snippet = & snippet[ 1 ..snippet. len ( ) - 1 ] ;
860863
864+ // Macros like `println` add a newline at the end. That technically doens't make them "literals" anymore, but it's fine
865+ // since we will never need to point our spans there, so we lie about it here by ignoring it.
866+ // Since there might actually be newlines in the source code, we need to normalize away all trailing newlines.
867+ // If we only trimmed it off the input, `format!("\n")` would cause a mismatch as here we they actually match up.
868+ // Alternatively, we could just count the trailing newlines and only trim one from the input if they don't match up.
869+ let input_no_nl = input. trim_end_matches ( '\n' ) ;
870+ let Ok ( unescaped) = unescape_string ( snippet) else {
871+ return ( vec ! [ ] , false ) ;
872+ } ;
873+
874+ let unescaped_no_nl = unescaped. trim_end_matches ( '\n' ) ;
875+
876+ if unescaped_no_nl != input_no_nl {
877+ // The source string that we're pointing at isn't our input, so spans pointing at it will be incorrect.
878+ // This can for example happen with proc macros that respan generated literals.
879+ return ( vec ! [ ] , false ) ;
880+ }
881+
861882 let mut s = snippet. char_indices ( ) ;
862883 let mut width_mappings = vec ! [ ] ;
863884 while let Some ( ( pos, c) ) = s. next ( ) {
@@ -936,9 +957,23 @@ fn find_width_map_from_snippet(
936957 _ => { }
937958 }
938959 }
960+
939961 ( width_mappings, true )
940962}
941963
964+ fn unescape_string ( string : & str ) -> Result < string:: String , unescape:: EscapeError > {
965+ let mut buf = string:: String :: new ( ) ;
966+ let mut error = Ok ( ( ) ) ;
967+ unescape:: unescape_literal ( string, unescape:: Mode :: Str , & mut |_, unescaped_char| {
968+ match unescaped_char {
969+ Ok ( c) => buf. push ( c) ,
970+ Err ( err) => error = Err ( err) ,
971+ }
972+ } ) ;
973+
974+ error. map ( |_| buf)
975+ }
976+
942977// Assert a reasonable size for `Piece`
943978#[ cfg( all( target_arch = "x86_64" , target_pointer_width = "64" ) ) ]
944979rustc_data_structures:: static_assert_size!( Piece <' _>, 16 ) ;
0 commit comments