@@ -149,6 +149,24 @@ impl<'a> Converter<'a> {
149149 }
150150 }
151151
152+ /// Check for likely unterminated string by analyzing STRING token content
153+ fn has_likely_unterminated_string ( & self ) -> bool {
154+ let Some ( last_idx) = self . res . kind . len ( ) . checked_sub ( 1 ) else { return false } ;
155+
156+ for i in ( 0 ..=last_idx) . rev ( ) . take ( 5 ) {
157+ if self . res . kind [ i] == STRING {
158+ let start = self . res . start [ i] as usize ;
159+ let end = self . res . start . get ( i + 1 ) . map ( |& s| s as usize ) . unwrap_or ( self . offset ) ;
160+ let content = & self . res . text [ start..end] ;
161+
162+ if content. contains ( '(' ) && ( content. contains ( "//" ) || content. contains ( ";\n " ) ) {
163+ return true ;
164+ }
165+ }
166+ }
167+ false
168+ }
169+
152170 fn finalize_with_eof ( mut self ) -> LexedStr < ' a > {
153171 self . res . push ( EOF , self . offset ) ;
154172 self . res
@@ -267,7 +285,17 @@ impl<'a> Converter<'a> {
267285 rustc_lexer:: TokenKind :: Unknown => ERROR ,
268286 rustc_lexer:: TokenKind :: UnknownPrefix if token_text == "builtin" => IDENT ,
269287 rustc_lexer:: TokenKind :: UnknownPrefix => {
270- errors. push ( "unknown literal prefix" . into ( ) ) ;
288+ let has_unterminated = self . has_likely_unterminated_string ( ) ;
289+
290+ let error_msg = if has_unterminated {
291+ format ! (
292+ "unknown literal prefix `{}` (note: check for unterminated string literal)" ,
293+ token_text
294+ )
295+ } else {
296+ "unknown literal prefix" . to_owned ( )
297+ } ;
298+ errors. push ( error_msg) ;
271299 IDENT
272300 }
273301 rustc_lexer:: TokenKind :: Eof => EOF ,
0 commit comments