Skip to content

Commit 2c96025

Browse files
committed
Improve compiler error for c-strings in pre-2021
1 parent 84a554c commit 2c96025

File tree

3 files changed

+158
-7
lines changed

3 files changed

+158
-7
lines changed

compiler/rustc_parse/src/parser/diagnostics.rs

+29-7
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ use crate::errors::{
1010
ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
1111
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
1212
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,
2020
};
2121
use crate::fluent_generated as fluent;
2222
use crate::parser;
@@ -640,6 +640,28 @@ impl<'a> Parser<'a> {
640640
}
641641
}
642642

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+
643665
// `pub` may be used for an item or `pub(crate)`
644666
if self.prev_token.is_ident_named(sym::public)
645667
&& (self.token.can_begin_item()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
macro_rules! construct { ($x:ident) => { $x"str" } }
2+
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
3+
//~| NOTE expected one of 8 possible tokens
4+
5+
macro_rules! contain { () => { c"str" } }
6+
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
7+
//~| NOTE expected one of 8 possible tokens
8+
//~| NOTE you may be trying to write a c-string literal
9+
//~| NOTE c-string literals require Rust 2021 or later
10+
//~| HELP pass `--edition 2021` to `rustc`
11+
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
12+
13+
fn check_macro_construct() {
14+
construct!(c); //~ NOTE in this expansion of construct!
15+
}
16+
17+
fn check_macro_contain() {
18+
contain!();
19+
//~^ NOTE in this expansion of contain!
20+
//~| NOTE in this expansion of contain!
21+
//~| NOTE in this expansion of contain!
22+
//~| NOTE in this expansion of contain!
23+
//~| NOTE in this expansion of contain!
24+
}
25+
26+
fn check_basic() {
27+
c"str";
28+
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
29+
//~| NOTE expected one of 8 possible tokens
30+
//~| NOTE you may be trying to write a c-string literal
31+
//~| NOTE c-string literals require Rust 2021 or later
32+
//~| HELP pass `--edition 2021` to `rustc`
33+
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
34+
}
35+
36+
fn check_craw() {
37+
cr"str";
38+
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
39+
//~| NOTE expected one of 8 possible tokens
40+
//~| NOTE you may be trying to write a c-string literal
41+
//~| NOTE c-string literals require Rust 2021 or later
42+
//~| HELP pass `--edition 2021` to `rustc`
43+
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
44+
}
45+
46+
fn check_craw_hash() {
47+
cr##"str"##;
48+
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `#`
49+
//~| NOTE expected one of 8 possible tokens
50+
//~| NOTE you may be trying to write a c-string literal
51+
//~| NOTE c-string literals require Rust 2021 or later
52+
//~| HELP pass `--edition 2021` to `rustc`
53+
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
54+
}
55+
56+
fn check_cstr_space() {
57+
c "str";
58+
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
59+
//~| NOTE expected one of 8 possible tokens
60+
}
61+
62+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
2+
--> $DIR/edition-cstr-2015-2018.rs:27:6
3+
|
4+
LL | c"str";
5+
| ^^^^^ expected one of 8 possible tokens
6+
|
7+
= note: you may be trying to write a c-string literal
8+
= note: c-string literals require Rust 2021 or later
9+
= help: pass `--edition 2021` to `rustc`
10+
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
11+
12+
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
13+
--> $DIR/edition-cstr-2015-2018.rs:37:7
14+
|
15+
LL | cr"str";
16+
| ^^^^^ expected one of 8 possible tokens
17+
|
18+
= note: you may be trying to write a c-string literal
19+
= note: c-string literals require Rust 2021 or later
20+
= help: pass `--edition 2021` to `rustc`
21+
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
22+
23+
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `#`
24+
--> $DIR/edition-cstr-2015-2018.rs:47:7
25+
|
26+
LL | cr##"str"##;
27+
| ^ expected one of 8 possible tokens
28+
|
29+
= note: you may be trying to write a c-string literal
30+
= note: c-string literals require Rust 2021 or later
31+
= help: pass `--edition 2021` to `rustc`
32+
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
33+
34+
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
35+
--> $DIR/edition-cstr-2015-2018.rs:57:7
36+
|
37+
LL | c "str";
38+
| ^^^^^ expected one of 8 possible tokens
39+
40+
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
41+
--> $DIR/edition-cstr-2015-2018.rs:1:44
42+
|
43+
LL | macro_rules! construct { ($x:ident) => { $x"str" } }
44+
| ^^^^^ expected one of 8 possible tokens
45+
...
46+
LL | construct!(c);
47+
| ------------- in this macro invocation
48+
|
49+
= note: this error originates in the macro `construct` (in Nightly builds, run with -Z macro-backtrace for more info)
50+
51+
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
52+
--> $DIR/edition-cstr-2015-2018.rs:5:33
53+
|
54+
LL | macro_rules! contain { () => { c"str" } }
55+
| ^^^^^ expected one of 8 possible tokens
56+
...
57+
LL | contain!();
58+
| ---------- in this macro invocation
59+
|
60+
= note: you may be trying to write a c-string literal
61+
= note: c-string literals require Rust 2021 or later
62+
= help: pass `--edition 2021` to `rustc`
63+
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
64+
= note: this error originates in the macro `contain` (in Nightly builds, run with -Z macro-backtrace for more info)
65+
66+
error: aborting due to 6 previous errors
67+

0 commit comments

Comments
 (0)