@@ -175,24 +175,27 @@ pub enum DocStyle {
175175/// `rustc_ast::ast::LitKind`).
176176#[ derive( Clone , Copy , Debug , PartialEq , Eq , PartialOrd , Ord ) ]
177177pub enum LiteralKind {
178- /// " 12_u8", " 0o100", " 0b120i99", " 1f32" .
178+ /// ` 12_u8`, ` 0o100`, ` 0b120i99`, ` 1f32` .
179179 Int { base : Base , empty_int : bool } ,
180- /// " 12.34f32", " 1e3" , but not " 1f32" .
180+ /// ` 12.34f32`, ` 1e3` , but not ` 1f32` .
181181 Float { base : Base , empty_exponent : bool } ,
182- /// " 'a'", " '\\'", " '''", "';"
182+ /// ` 'a'`, ` '\\'`, ` '''`, `';`
183183 Char { terminated : bool } ,
184- /// " b'a'", " b'\\'", " b'''", " b';"
184+ /// ` b'a'`, ` b'\\'`, ` b'''`, ` b';`
185185 Byte { terminated : bool } ,
186- /// "" abc"", "" abc"
186+ /// `" abc"`, `" abc`
187187 Str { terminated : bool } ,
188- /// " b"abc"", " b"abc"
188+ /// ` b"abc"`, ` b"abc`
189189 ByteStr { terminated : bool } ,
190190 /// `c"abc"`, `c"abc`
191191 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
193196 /// an invalid literal.
194197 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`
196199 /// indicates an invalid literal.
197200 RawByteStr { n_hashes : Option < u8 > } ,
198201 /// `cr"abc"`, "cr#"abc"#", `cr#"a`. `None` indicates an invalid literal.
@@ -361,6 +364,36 @@ impl Cursor<'_> {
361364 _ => self . ident_or_unknown_prefix ( ) ,
362365 } ,
363366
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+
364397 // Byte literal, byte string literal, raw byte string literal or identifier.
365398 'b' => self . c_or_byte_string (
366399 |terminated| ByteStr { terminated } ,
@@ -754,6 +787,36 @@ impl Cursor<'_> {
754787 false
755788 }
756789
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+
757820 /// Eats the double-quoted string and returns `n_hashes` and an error if encountered.
758821 fn raw_double_quoted_string ( & mut self , prefix_len : u32 ) -> Result < u8 , RawStrError > {
759822 // Wrap the actual function to handle the error with too many hashes.
0 commit comments