Rollup merge of #118691 - chfogelman:improve-cstr-error, r=fmease
Add check for possible CStr literals in pre-2021 Fixes [#118654](https://github.com/rust-lang/rust/issues/118654) Adds information to errors caused by possible CStr literals in pre-2021. The lexer separates `c"str"` into two tokens if the edition is less than 2021, which later causes an error when parsing. This error now has a more helpful message that directs them to information about editions. However, the user might also have written `c "str"` in a later edition, so to not confuse people who _are_ using a recent edition, I also added a note about whitespace. We could probably figure out exactly which scenario has been encountered by examining spans and editions, but I figured it would be better not to overcomplicate the creation of the error too much. This is my first code PR and I tried to follow existing conventions as much as possible, but I probably missed something, so let me know!
This commit is contained in:
commit
f3f9b3043e
@ -10,13 +10,13 @@ use crate::errors::{
|
|||||||
ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
|
ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
|
||||||
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
||||||
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
|
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
|
||||||
HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
|
HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
|
||||||
IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg,
|
IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType,
|
||||||
SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg,
|
QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
|
||||||
StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt,
|
StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
|
||||||
SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, UnexpectedConstInGenericParam,
|
SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
|
||||||
UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
|
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
|
||||||
UseEqInstead, WrapType,
|
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
|
||||||
};
|
};
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
use crate::parser;
|
use crate::parser;
|
||||||
@ -640,6 +640,28 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to detect an intended c-string literal while using a pre-2021 edition. The heuristic
|
||||||
|
// here is to identify a cooked, uninterpolated `c` id immediately followed by a string, or
|
||||||
|
// a cooked, uninterpolated `cr` id immediately followed by a string or a `#`, in an edition
|
||||||
|
// where c-string literals are not allowed. There is the very slight possibility of a false
|
||||||
|
// positive for a `cr#` that wasn't intended to start a c-string literal, but identifying
|
||||||
|
// that in the parser requires unbounded lookahead, so we only add a hint to the existing
|
||||||
|
// error rather than replacing it entirely.
|
||||||
|
if ((self.prev_token.kind == TokenKind::Ident(sym::c, false)
|
||||||
|
&& matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. })))
|
||||||
|
|| (self.prev_token.kind == TokenKind::Ident(sym::cr, false)
|
||||||
|
&& matches!(
|
||||||
|
&self.token.kind,
|
||||||
|
TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound
|
||||||
|
)))
|
||||||
|
&& self.prev_token.span.hi() == self.token.span.lo()
|
||||||
|
&& !self.token.span.at_least_rust_2021()
|
||||||
|
{
|
||||||
|
err.note("you may be trying to write a c-string literal");
|
||||||
|
err.note("c-string literals require Rust 2021 or later");
|
||||||
|
HelpUseLatestEdition::new().add_to_diagnostic(&mut err);
|
||||||
|
}
|
||||||
|
|
||||||
// `pub` may be used for an item or `pub(crate)`
|
// `pub` may be used for an item or `pub(crate)`
|
||||||
if self.prev_token.is_ident_named(sym::public)
|
if self.prev_token.is_ident_named(sym::public)
|
||||||
&& (self.token.can_begin_item()
|
&& (self.token.can_begin_item()
|
||||||
|
62
tests/ui/editions/edition-cstr-2015-2018.rs
Normal file
62
tests/ui/editions/edition-cstr-2015-2018.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
macro_rules! construct { ($x:ident) => { $x"str" } }
|
||||||
|
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||||
|
//~| NOTE expected one of 8 possible tokens
|
||||||
|
|
||||||
|
macro_rules! contain { () => { c"str" } }
|
||||||
|
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||||
|
//~| NOTE expected one of 8 possible tokens
|
||||||
|
//~| NOTE you may be trying to write a c-string literal
|
||||||
|
//~| NOTE c-string literals require Rust 2021 or later
|
||||||
|
//~| HELP pass `--edition 2021` to `rustc`
|
||||||
|
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||||
|
|
||||||
|
fn check_macro_construct() {
|
||||||
|
construct!(c); //~ NOTE in this expansion of construct!
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_macro_contain() {
|
||||||
|
contain!();
|
||||||
|
//~^ NOTE in this expansion of contain!
|
||||||
|
//~| NOTE in this expansion of contain!
|
||||||
|
//~| NOTE in this expansion of contain!
|
||||||
|
//~| NOTE in this expansion of contain!
|
||||||
|
//~| NOTE in this expansion of contain!
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_basic() {
|
||||||
|
c"str";
|
||||||
|
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||||
|
//~| NOTE expected one of 8 possible tokens
|
||||||
|
//~| NOTE you may be trying to write a c-string literal
|
||||||
|
//~| NOTE c-string literals require Rust 2021 or later
|
||||||
|
//~| HELP pass `--edition 2021` to `rustc`
|
||||||
|
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_craw() {
|
||||||
|
cr"str";
|
||||||
|
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||||
|
//~| NOTE expected one of 8 possible tokens
|
||||||
|
//~| NOTE you may be trying to write a c-string literal
|
||||||
|
//~| NOTE c-string literals require Rust 2021 or later
|
||||||
|
//~| HELP pass `--edition 2021` to `rustc`
|
||||||
|
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_craw_hash() {
|
||||||
|
cr##"str"##;
|
||||||
|
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `#`
|
||||||
|
//~| NOTE expected one of 8 possible tokens
|
||||||
|
//~| NOTE you may be trying to write a c-string literal
|
||||||
|
//~| NOTE c-string literals require Rust 2021 or later
|
||||||
|
//~| HELP pass `--edition 2021` to `rustc`
|
||||||
|
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_cstr_space() {
|
||||||
|
c "str";
|
||||||
|
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||||
|
//~| NOTE expected one of 8 possible tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
67
tests/ui/editions/edition-cstr-2015-2018.stderr
Normal file
67
tests/ui/editions/edition-cstr-2015-2018.stderr
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||||
|
--> $DIR/edition-cstr-2015-2018.rs:27:6
|
||||||
|
|
|
||||||
|
LL | c"str";
|
||||||
|
| ^^^^^ expected one of 8 possible tokens
|
||||||
|
|
|
||||||
|
= note: you may be trying to write a c-string literal
|
||||||
|
= note: c-string literals require Rust 2021 or later
|
||||||
|
= help: pass `--edition 2021` to `rustc`
|
||||||
|
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||||
|
|
||||||
|
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||||
|
--> $DIR/edition-cstr-2015-2018.rs:37:7
|
||||||
|
|
|
||||||
|
LL | cr"str";
|
||||||
|
| ^^^^^ expected one of 8 possible tokens
|
||||||
|
|
|
||||||
|
= note: you may be trying to write a c-string literal
|
||||||
|
= note: c-string literals require Rust 2021 or later
|
||||||
|
= help: pass `--edition 2021` to `rustc`
|
||||||
|
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||||
|
|
||||||
|
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `#`
|
||||||
|
--> $DIR/edition-cstr-2015-2018.rs:47:7
|
||||||
|
|
|
||||||
|
LL | cr##"str"##;
|
||||||
|
| ^ expected one of 8 possible tokens
|
||||||
|
|
|
||||||
|
= note: you may be trying to write a c-string literal
|
||||||
|
= note: c-string literals require Rust 2021 or later
|
||||||
|
= help: pass `--edition 2021` to `rustc`
|
||||||
|
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||||
|
|
||||||
|
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||||
|
--> $DIR/edition-cstr-2015-2018.rs:57:7
|
||||||
|
|
|
||||||
|
LL | c "str";
|
||||||
|
| ^^^^^ expected one of 8 possible tokens
|
||||||
|
|
||||||
|
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||||
|
--> $DIR/edition-cstr-2015-2018.rs:1:44
|
||||||
|
|
|
||||||
|
LL | macro_rules! construct { ($x:ident) => { $x"str" } }
|
||||||
|
| ^^^^^ expected one of 8 possible tokens
|
||||||
|
...
|
||||||
|
LL | construct!(c);
|
||||||
|
| ------------- in this macro invocation
|
||||||
|
|
|
||||||
|
= note: this error originates in the macro `construct` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||||
|
--> $DIR/edition-cstr-2015-2018.rs:5:33
|
||||||
|
|
|
||||||
|
LL | macro_rules! contain { () => { c"str" } }
|
||||||
|
| ^^^^^ expected one of 8 possible tokens
|
||||||
|
...
|
||||||
|
LL | contain!();
|
||||||
|
| ---------- in this macro invocation
|
||||||
|
|
|
||||||
|
= note: you may be trying to write a c-string literal
|
||||||
|
= note: c-string literals require Rust 2021 or later
|
||||||
|
= help: pass `--edition 2021` to `rustc`
|
||||||
|
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||||
|
= note: this error originates in the macro `contain` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user