Skip to content

Commit 6046f4a

Browse files
committed
Do not lint dyn tokens under macros.
The existing `KeywordIdents` lint blindly scans the token stream for a macro or macro definition. It does not attempt to parse the input, which means it cannot distinguish between occurrences of `dyn` that are truly instances of it as an identifier (e.g. `let dyn = 3;`) versus occurrences that follow its usage as a contextual keyword (e.g. the type `Box<dyn Trait>`). In an ideal world the lint would parse the token stream in order to distinguish such occurrences; but in general we cannot do this, because a macro_rules definition does not specify what parsing contexts the macro being defined is allowed to be used within. So rather than put a lot of work into attempting to come up with a more precise but still incomplete solution, I am just taking the short cut of not linting any instance of `dyn` under a macro. This prevents `rustfix` from injecting bugs into legal 2015 edition code.
1 parent 267fb90 commit 6046f4a

File tree

1 file changed

+36
-11
lines changed

1 file changed

+36
-11
lines changed

src/librustc_lint/builtin.rs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,14 +1618,16 @@ impl LintPass for KeywordIdents {
16181618
}
16191619
}
16201620

1621+
struct UnderMacro(bool);
1622+
16211623
impl KeywordIdents {
16221624
fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: TokenStream) {
16231625
for tt in tokens.into_trees() {
16241626
match tt {
16251627
TokenTree::Token(span, tok) => match tok.ident() {
16261628
// only report non-raw idents
16271629
Some((ident, false)) => {
1628-
self.check_ident(cx, ast::Ident {
1630+
self.check_ident_token(cx, UnderMacro(true), ast::Ident {
16291631
span: span.substitute_dummy(ident.span),
16301632
..ident
16311633
});
@@ -1638,16 +1640,12 @@ impl KeywordIdents {
16381640
}
16391641
}
16401642
}
1641-
}
16421643

1643-
impl EarlyLintPass for KeywordIdents {
1644-
fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) {
1645-
self.check_tokens(cx, mac_def.stream());
1646-
}
1647-
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) {
1648-
self.check_tokens(cx, mac.node.tts.clone().into());
1649-
}
1650-
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) {
1644+
fn check_ident_token(&mut self,
1645+
cx: &EarlyContext<'_>,
1646+
UnderMacro(under_macro): UnderMacro,
1647+
ident: ast::Ident)
1648+
{
16511649
let ident_str = &ident.as_str()[..];
16521650
let cur_edition = cx.sess.edition();
16531651
let is_raw_ident = |ident: ast::Ident| {
@@ -1656,7 +1654,22 @@ impl EarlyLintPass for KeywordIdents {
16561654
let next_edition = match cur_edition {
16571655
Edition::Edition2015 => {
16581656
match ident_str {
1659-
"async" | "try" | "dyn" => Edition::Edition2018,
1657+
"async" | "try" => Edition::Edition2018,
1658+
1659+
// rust-lang/rust#56327: Conservatively do not
1660+
// attempt to report occurrences of `dyn` within
1661+
// macro definitions or invocations, because `dyn`
1662+
// can legitimately occur as a contextual keyword
1663+
// in 2015 code denoting its 2018 meaning, and we
1664+
// do not want rustfix to inject bugs into working
1665+
// code by rewriting such occurrences.
1666+
//
1667+
// But if we see `dyn` outside of a macro, we know
1668+
// its precise role in the parsed AST and thus are
1669+
// assured this is truly an attempt to use it as
1670+
// an identifier.
1671+
"dyn" if !under_macro => Edition::Edition2018,
1672+
16601673
// Only issue warnings for `await` if the `async_await`
16611674
// feature isn't being used. Otherwise, users need
16621675
// to keep using `await` for the macro exposed by std.
@@ -1714,6 +1727,18 @@ impl EarlyLintPass for KeywordIdents {
17141727
}
17151728
}
17161729

1730+
impl EarlyLintPass for KeywordIdents {
1731+
fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) {
1732+
self.check_tokens(cx, mac_def.stream());
1733+
}
1734+
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) {
1735+
self.check_tokens(cx, mac.node.tts.clone().into());
1736+
}
1737+
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) {
1738+
self.check_ident_token(cx, UnderMacro(false), ident);
1739+
}
1740+
}
1741+
17171742

17181743
pub struct ExplicitOutlivesRequirements;
17191744

0 commit comments

Comments
 (0)