@@ -175,24 +175,27 @@ pub enum DocStyle {
175
175
/// `rustc_ast::ast::LitKind`).
176
176
#[ derive( Clone , Copy , Debug , PartialEq , Eq , PartialOrd , Ord ) ]
177
177
pub enum LiteralKind {
178
- /// " 12_u8", " 0o100", " 0b120i99", " 1f32" .
178
+ /// ` 12_u8`, ` 0o100`, ` 0b120i99`, ` 1f32` .
179
179
Int { base : Base , empty_int : bool } ,
180
- /// " 12.34f32", " 1e3" , but not " 1f32" .
180
+ /// ` 12.34f32`, ` 1e3` , but not ` 1f32` .
181
181
Float { base : Base , empty_exponent : bool } ,
182
- /// " 'a'", " '\\'", " '''", "';"
182
+ /// ` 'a'`, ` '\\'`, ` '''`, `';`
183
183
Char { terminated : bool } ,
184
- /// " b'a'", " b'\\'", " b'''", " b';"
184
+ /// ` b'a'`, ` b'\\'`, ` b'''`, ` b';`
185
185
Byte { terminated : bool } ,
186
- /// "" abc"", "" abc"
186
+ /// `" abc"`, `" abc`
187
187
Str { terminated : bool } ,
188
- /// " b"abc"", " b"abc"
188
+ /// ` b"abc"`, ` b"abc`
189
189
ByteStr { terminated : bool } ,
190
190
/// `c"abc"`, `c"abc`
191
191
CStr { terminated : bool } ,
192
- /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a". `None` indicates
192
+ /// `#"abc"#`, `####"ab"###"c"####`, `#"a`, `##"a"#`. `None` indicates
193
+ /// no closing quote.
194
+ GuardedStr { n_hashes : Option < u8 > } ,
195
+ /// `r"abc"`, `r#"abc"#`, `r####"ab"###"c"####`, `r#"a`. `None` indicates
193
196
/// an invalid literal.
194
197
RawStr { n_hashes : Option < u8 > } ,
195
- /// " br"abc"", " br#"abc"#", " br####"ab"###"c"####", " br#"a" . `None`
198
+ /// ` br"abc"`, ` br#"abc"#`, ` br####"ab"###"c"####`, ` br#"a` . `None`
196
199
/// indicates an invalid literal.
197
200
RawByteStr { n_hashes : Option < u8 > } ,
198
201
/// `cr"abc"`, "cr#"abc"#", `cr#"a`. `None` indicates an invalid literal.
@@ -361,6 +364,36 @@ impl Cursor<'_> {
361
364
_ => self . ident_or_unknown_prefix ( ) ,
362
365
} ,
363
366
367
+ // Guarded string literal (reserved syntax).
368
+ '#' if matches ! ( self . first( ) , '"' | '#' ) => {
369
+ // Create a backup to restore later if this
370
+ // turns out to not be a guarded literal.
371
+ let backup = self . clone ( ) ;
372
+
373
+ let mut n_start_hashes: u32 = 1 ; // Already captured one `#`.
374
+ while self . first ( ) == '#' {
375
+ n_start_hashes += 1 ;
376
+ self . bump ( ) ;
377
+ }
378
+
379
+ if self . first ( ) == '"' {
380
+ self . bump ( ) ;
381
+
382
+ let res = self . guarded_double_quoted_string ( n_start_hashes) ;
383
+ let suffix_start = self . pos_within_token ( ) ;
384
+ if res. is_ok ( ) {
385
+ self . eat_literal_suffix ( ) ;
386
+ }
387
+ let kind = GuardedStr { n_hashes : n_start_hashes. try_into ( ) . ok ( ) } ;
388
+ Literal { kind, suffix_start }
389
+ } else {
390
+ // Not a guarded string, so restore old state.
391
+ * self = backup;
392
+ // Return a pound token.
393
+ Pound
394
+ }
395
+ }
396
+
364
397
// Byte literal, byte string literal, raw byte string literal or identifier.
365
398
'b' => self . c_or_byte_string (
366
399
|terminated| ByteStr { terminated } ,
@@ -754,6 +787,36 @@ impl Cursor<'_> {
754
787
false
755
788
}
756
789
790
+ /// Eats the double-quoted string and returns `n_hashes` and an error if encountered.
791
+ fn guarded_double_quoted_string ( & mut self , n_start_hashes : u32 ) -> Result < u32 , RawStrError > {
792
+ debug_assert ! ( self . prev( ) == '"' ) ;
793
+
794
+ // Lex the string itself as a normal string literal
795
+ // so we can recover that for older editions later.
796
+ if !self . double_quoted_string ( ) {
797
+ return Err ( RawStrError :: NoTerminator {
798
+ expected : n_start_hashes,
799
+ found : 0 ,
800
+ possible_terminator_offset : None ,
801
+ } ) ;
802
+ }
803
+
804
+ // Check that amount of closing '#' symbols
805
+ // is equal to the amount of opening ones.
806
+ // Note that this will not consume extra trailing `#` characters:
807
+ // `###"abcde"####` is lexed as a `GuardedStr { n_end_hashes: 3 }`
808
+ // followed by a `#` token.
809
+ let mut n_end_hashes = 0 ;
810
+ while self . first ( ) == '#' && n_end_hashes < n_start_hashes {
811
+ n_end_hashes += 1 ;
812
+ self . bump ( ) ;
813
+ }
814
+
815
+ // We could handle `n_end_hashes < n_start_hashes` here
816
+ // but this whole token is an error anyways.
817
+ Ok ( n_end_hashes)
818
+ }
819
+
757
820
/// Eats the double-quoted string and returns `n_hashes` and an error if encountered.
758
821
fn raw_double_quoted_string ( & mut self , prefix_len : u32 ) -> Result < u8 , RawStrError > {
759
822
// Wrap the actual function to handle the error with too many hashes.
0 commit comments