@@ -17,6 +17,7 @@ use rustc_ast::token::{self, Delimiter, Token, TokenKind};
17
17
use rustc_ast:: tokenstream:: Spacing ;
18
18
use rustc_ast:: util:: case:: Case ;
19
19
use rustc_ast:: util:: classify;
20
+ use rustc_ast:: util:: literal:: LitError ;
20
21
use rustc_ast:: util:: parser:: { prec_let_scrutinee_needs_par, AssocOp , Fixity } ;
21
22
use rustc_ast:: visit:: Visitor ;
22
23
use rustc_ast:: { self as ast, AttrStyle , AttrVec , CaptureBy , ExprField , UnOp , DUMMY_NODE_ID } ;
@@ -30,9 +31,10 @@ use rustc_errors::{
30
31
PResult , StashKey ,
31
32
} ;
32
33
use rustc_macros:: Subdiagnostic ;
33
- use rustc_session:: errors:: { report_lit_error , ExprParenthesesNeeded } ;
34
+ use rustc_session:: errors:: ExprParenthesesNeeded ;
34
35
use rustc_session:: lint:: builtin:: BREAK_WITH_LABEL_AND_LOOP ;
35
36
use rustc_session:: lint:: BuiltinLintDiagnostics ;
37
+ use rustc_session:: parse:: ParseSess ;
36
38
use rustc_span:: source_map:: { self , Spanned } ;
37
39
use rustc_span:: symbol:: kw:: PathRoot ;
38
40
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
@@ -3672,6 +3674,90 @@ impl<'a> Parser<'a> {
3672
3674
}
3673
3675
}
3674
3676
3677
+ pub fn report_lit_error ( sess : & ParseSess , err : LitError , lit : token:: Lit , span : Span ) {
3678
+ // Checks if `s` looks like i32 or u1234 etc.
3679
+ fn looks_like_width_suffix ( first_chars : & [ char ] , s : & str ) -> bool {
3680
+ s. len ( ) > 1 && s. starts_with ( first_chars) && s[ 1 ..] . chars ( ) . all ( |c| c. is_ascii_digit ( ) )
3681
+ }
3682
+
3683
+ // Try to lowercase the prefix if the prefix and suffix are valid.
3684
+ fn fix_base_capitalisation ( prefix : & str , suffix : & str ) -> Option < String > {
3685
+ let mut chars = suffix. chars ( ) ;
3686
+
3687
+ let base_char = chars. next ( ) . unwrap ( ) ;
3688
+ let base = match base_char {
3689
+ 'B' => 2 ,
3690
+ 'O' => 8 ,
3691
+ 'X' => 16 ,
3692
+ _ => return None ,
3693
+ } ;
3694
+
3695
+ // check that the suffix contains only base-appropriate characters
3696
+ let valid = prefix == "0"
3697
+ && chars
3698
+ . filter ( |c| * c != '_' )
3699
+ . take_while ( |c| * c != 'i' && * c != 'u' )
3700
+ . all ( |c| c. to_digit ( base) . is_some ( ) ) ;
3701
+
3702
+ valid. then ( || format ! ( "0{}{}" , base_char. to_ascii_lowercase( ) , & suffix[ 1 ..] ) )
3703
+ }
3704
+
3705
+ let token:: Lit { kind, symbol, suffix, .. } = lit;
3706
+ match err {
3707
+ // `LexerError` is an error, but it was already reported
3708
+ // by lexer, so here we don't report it the second time.
3709
+ LitError :: LexerError => { }
3710
+ LitError :: InvalidSuffix => {
3711
+ if let Some ( suffix) = suffix {
3712
+ sess. emit_err ( errors:: InvalidLiteralSuffix { span, kind : kind. descr ( ) , suffix } ) ;
3713
+ }
3714
+ }
3715
+ LitError :: InvalidIntSuffix => {
3716
+ let suf = suffix. expect ( "suffix error with no suffix" ) ;
3717
+ let suf = suf. as_str ( ) ;
3718
+ if looks_like_width_suffix ( & [ 'i' , 'u' ] , suf) {
3719
+ // If it looks like a width, try to be helpful.
3720
+ sess. emit_err ( errors:: InvalidIntLiteralWidth { span, width : suf[ 1 ..] . into ( ) } ) ;
3721
+ } else if let Some ( fixed) = fix_base_capitalisation ( symbol. as_str ( ) , suf) {
3722
+ sess. emit_err ( errors:: InvalidNumLiteralBasePrefix { span, fixed } ) ;
3723
+ } else {
3724
+ sess. emit_err ( errors:: InvalidNumLiteralSuffix { span, suffix : suf. to_string ( ) } ) ;
3725
+ }
3726
+ }
3727
+ LitError :: InvalidFloatSuffix => {
3728
+ let suf = suffix. expect ( "suffix error with no suffix" ) ;
3729
+ let suf = suf. as_str ( ) ;
3730
+ if looks_like_width_suffix ( & [ 'f' ] , suf) {
3731
+ // If it looks like a width, try to be helpful.
3732
+ sess. emit_err ( errors:: InvalidFloatLiteralWidth {
3733
+ span,
3734
+ width : suf[ 1 ..] . to_string ( ) ,
3735
+ } ) ;
3736
+ } else {
3737
+ sess. emit_err ( errors:: InvalidFloatLiteralSuffix { span, suffix : suf. to_string ( ) } ) ;
3738
+ }
3739
+ }
3740
+ LitError :: NonDecimalFloat ( base) => {
3741
+ match base {
3742
+ 16 => sess. emit_err ( errors:: HexadecimalFloatLiteralNotSupported { span } ) ,
3743
+ 8 => sess. emit_err ( errors:: OctalFloatLiteralNotSupported { span } ) ,
3744
+ 2 => sess. emit_err ( errors:: BinaryFloatLiteralNotSupported { span } ) ,
3745
+ _ => unreachable ! ( ) ,
3746
+ } ;
3747
+ }
3748
+ LitError :: IntTooLarge ( base) => {
3749
+ let max = u128:: MAX ;
3750
+ let limit = match base {
3751
+ 2 => format ! ( "{max:#b}" ) ,
3752
+ 8 => format ! ( "{max:#o}" ) ,
3753
+ 16 => format ! ( "{max:#x}" ) ,
3754
+ _ => format ! ( "{max}" ) ,
3755
+ } ;
3756
+ sess. emit_err ( errors:: IntLiteralTooLarge { span, limit } ) ;
3757
+ }
3758
+ }
3759
+ }
3760
+
3675
3761
/// Used to forbid `let` expressions in certain syntactic locations.
3676
3762
#[ derive( Clone , Copy , Subdiagnostic ) ]
3677
3763
pub ( crate ) enum ForbiddenLetReason {
0 commit comments