@@ -10,13 +10,13 @@ use crate::errors::{
10
10
ConstGenericWithoutBracesSugg , DocCommentDoesNotDocumentAnything , DocCommentOnParamType ,
11
11
DoubleColonInBound , ExpectedIdentifier , ExpectedSemi , ExpectedSemiSugg ,
12
12
GenericParamsWithoutAngleBrackets , GenericParamsWithoutAngleBracketsSugg ,
13
- HelpIdentifierStartsWithNumber , InInTypo , IncorrectAwait , IncorrectSemicolon ,
14
- IncorrectUseOfAwait , PatternMethodParamWithoutBody , QuestionMarkInType , QuestionMarkInTypeSugg ,
15
- SelfParamNotFirst , StructLiteralBodyWithoutPath , StructLiteralBodyWithoutPathSugg ,
16
- StructLiteralNeedingParens , StructLiteralNeedingParensSugg , SuggAddMissingLetStmt ,
17
- SuggEscapeIdentifier , SuggRemoveComma , TernaryOperator , UnexpectedConstInGenericParam ,
18
- UnexpectedConstParamDeclaration , UnexpectedConstParamDeclarationSugg , UnmatchedAngleBrackets ,
19
- UseEqInstead , WrapType ,
13
+ HelpIdentifierStartsWithNumber , HelpUseLatestEdition , InInTypo , IncorrectAwait ,
14
+ IncorrectSemicolon , IncorrectUseOfAwait , PatternMethodParamWithoutBody , QuestionMarkInType ,
15
+ QuestionMarkInTypeSugg , SelfParamNotFirst , StructLiteralBodyWithoutPath ,
16
+ StructLiteralBodyWithoutPathSugg , StructLiteralNeedingParens , StructLiteralNeedingParensSugg ,
17
+ SuggAddMissingLetStmt , SuggEscapeIdentifier , SuggRemoveComma , TernaryOperator ,
18
+ UnexpectedConstInGenericParam , UnexpectedConstParamDeclaration ,
19
+ UnexpectedConstParamDeclarationSugg , UnmatchedAngleBrackets , UseEqInstead , WrapType ,
20
20
} ;
21
21
use crate :: fluent_generated as fluent;
22
22
use crate :: parser;
@@ -640,6 +640,28 @@ impl<'a> Parser<'a> {
640
640
}
641
641
}
642
642
643
+ // Try to detect an intended c-string literal while using a pre-2021 edition. The heuristic
644
+ // here is to identify a cooked, uninterpolated `c` id immediately followed by a string, or
645
+ // a cooked, uninterpolated `cr` id immediately followed by a string or a `#`, in an edition
646
+ // where c-string literals are not allowed. There is the very slight possibility of a false
647
+ // positive for a `cr#` that wasn't intended to start a c-string literal, but identifying
648
+ // that in the parser requires unbounded lookahead, so we only add a hint to the existing
649
+ // error rather than replacing it entirely.
650
+ if ( ( self . prev_token . kind == TokenKind :: Ident ( sym:: c, false )
651
+ && matches ! ( & self . token. kind, TokenKind :: Literal ( token:: Lit { kind: token:: Str , .. } ) ) )
652
+ || ( self . prev_token . kind == TokenKind :: Ident ( sym:: cr, false )
653
+ && matches ! (
654
+ & self . token. kind,
655
+ TokenKind :: Literal ( token:: Lit { kind: token:: Str , .. } ) | token:: Pound
656
+ ) ) )
657
+ && self . prev_token . span . hi ( ) == self . token . span . lo ( )
658
+ && !self . token . span . at_least_rust_2021 ( )
659
+ {
660
+ err. note ( "you may be trying to write a c-string literal" ) ;
661
+ err. note ( "c-string literals require Rust 2021 or later" ) ;
662
+ HelpUseLatestEdition :: new ( ) . add_to_diagnostic ( & mut err) ;
663
+ }
664
+
643
665
// `pub` may be used for an item or `pub(crate)`
644
666
if self . prev_token . is_ident_named ( sym:: public)
645
667
&& ( self . token . can_begin_item ( )
0 commit comments