Skip to content

Commit 5e65467

Browse files
committed
Auto merge of #83488 - Aaron1011:ban-expr-inner-attrs, r=petrochenkov
Ban custom inner attributes in expressions and statements Split out from #82608 Custom inner attributes are unstable, so this won't break any stable users. This allows us to speed up token collection, and avoid a redundant call to `collect_tokens_no_attrs` when parsing an `Expr` that has outer attributes. r? `@petrochenkov`
2 parents b8719c5 + 7504b9b commit 5e65467

File tree

8 files changed

+257
-173
lines changed

8 files changed

+257
-173
lines changed

compiler/rustc_expand/src/expand.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -206,30 +206,36 @@ ast_fragments! {
206206
}
207207
}
208208

209+
pub enum SupportsMacroExpansion {
210+
No,
211+
Yes { supports_inner_attrs: bool },
212+
}
213+
209214
impl AstFragmentKind {
210215
crate fn dummy(self, span: Span) -> AstFragment {
211216
self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment")
212217
}
213218

214-
/// Fragment supports macro expansion and not just inert attributes, `cfg` and `cfg_attr`.
215-
pub fn supports_macro_expansion(self) -> bool {
219+
pub fn supports_macro_expansion(self) -> SupportsMacroExpansion {
216220
match self {
217221
AstFragmentKind::OptExpr
218222
| AstFragmentKind::Expr
219-
| AstFragmentKind::Pat
220-
| AstFragmentKind::Ty
221223
| AstFragmentKind::Stmts
222-
| AstFragmentKind::Items
224+
| AstFragmentKind::Ty
225+
| AstFragmentKind::Pat => SupportsMacroExpansion::Yes { supports_inner_attrs: false },
226+
AstFragmentKind::Items
223227
| AstFragmentKind::TraitItems
224228
| AstFragmentKind::ImplItems
225-
| AstFragmentKind::ForeignItems => true,
229+
| AstFragmentKind::ForeignItems => {
230+
SupportsMacroExpansion::Yes { supports_inner_attrs: true }
231+
}
226232
AstFragmentKind::Arms
227233
| AstFragmentKind::Fields
228234
| AstFragmentKind::FieldPats
229235
| AstFragmentKind::GenericParams
230236
| AstFragmentKind::Params
231237
| AstFragmentKind::StructFields
232-
| AstFragmentKind::Variants => false,
238+
| AstFragmentKind::Variants => SupportsMacroExpansion::No,
233239
}
234240
}
235241

compiler/rustc_parse/src/parser/expr.rs

+15
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,21 @@ impl<'a> Parser<'a> {
9292
self.parse_expr_res(Restrictions::empty(), None)
9393
}
9494

95+
/// Parses an expression, forcing tokens to be collected
96+
pub fn parse_expr_force_collect(&mut self) -> PResult<'a, P<Expr>> {
97+
// If we have outer attributes, then the call to `collect_tokens_trailing_token`
98+
// will be made for us.
99+
if matches!(self.token.kind, TokenKind::Pound | TokenKind::DocComment(..)) {
100+
self.parse_expr()
101+
} else {
102+
// If we don't have outer attributes, then we need to ensure
103+
// that collection happens by using `collect_tokens_no_attrs`.
104+
// Expression don't support custom inner attributes, so `parse_expr`
105+
// will never try to collect tokens if we don't have outer attributes.
106+
self.collect_tokens_no_attrs(|this| this.parse_expr())
107+
}
108+
}
109+
95110
pub(super) fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> {
96111
self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value })
97112
}

compiler/rustc_parse/src/parser/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,7 @@ impl<'a> Parser<'a> {
987987
}
988988

989989
// Collect tokens because they are used during lowering to HIR.
990-
let expr = self.collect_tokens_no_attrs(|this| this.parse_expr())?;
990+
let expr = self.parse_expr_force_collect()?;
991991
let span = expr.span;
992992

993993
match &expr.kind {

compiler/rustc_parse/src/parser/nonterminal.rs

+1-16
Original file line numberDiff line numberDiff line change
@@ -128,22 +128,7 @@ impl<'a> Parser<'a> {
128128
})?)
129129
}
130130

131-
// If there are attributes present, then `parse_expr` will end up collecting tokens,
132-
// turning the outer `collect_tokens_no_attrs` into a no-op due to the already present
133-
// tokens. If there are *not* attributes present, then the outer
134-
// `collect_tokens_no_attrs` will ensure that we will end up collecting tokens for the
135-
// expressions.
136-
//
137-
// This is less efficient than it could be, since the outer `collect_tokens_no_attrs`
138-
// still needs to snapshot the `TokenCursor` before calling `parse_expr`, even when
139-
// `parse_expr` will end up collecting tokens. Ideally, this would work more like
140-
// `parse_item`, and take in a `ForceCollect` parameter. However, this would require
141-
// adding a `ForceCollect` parameter in a bunch of places in expression parsing
142-
// for little gain. If the perf impact from this turns out to be noticeable, we should
143-
// revisit this apporach.
144-
NonterminalKind::Expr => {
145-
token::NtExpr(self.collect_tokens_no_attrs(|this| this.parse_expr())?)
146-
}
131+
NonterminalKind::Expr => token::NtExpr(self.parse_expr_force_collect()?),
147132
NonterminalKind::Literal => {
148133
// The `:literal` matcher does not support attributes
149134
token::NtLiteral(

compiler/rustc_resolve/src/macros.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_errors::struct_span_err;
1717
use rustc_expand::base::Annotatable;
1818
use rustc_expand::base::{Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
1919
use rustc_expand::compile_declarative_macro;
20-
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
20+
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion};
2121
use rustc_feature::is_builtin_attr_name;
2222
use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
2323
use rustc_hir::def_id;
@@ -278,12 +278,12 @@ impl<'a> ResolverExpand for Resolver<'a> {
278278

279279
// Derives are not included when `invocations` are collected, so we have to add them here.
280280
let parent_scope = &ParentScope { derives, ..parent_scope };
281-
let require_inert = !invoc.fragment_kind.supports_macro_expansion();
281+
let supports_macro_expansion = invoc.fragment_kind.supports_macro_expansion();
282282
let node_id = self.lint_node_id(eager_expansion_root);
283283
let (ext, res) = self.smart_resolve_macro_path(
284284
path,
285285
kind,
286-
require_inert,
286+
supports_macro_expansion,
287287
inner_attr,
288288
parent_scope,
289289
node_id,
@@ -457,7 +457,7 @@ impl<'a> Resolver<'a> {
457457
&mut self,
458458
path: &ast::Path,
459459
kind: MacroKind,
460-
require_inert: bool,
460+
supports_macro_expansion: SupportsMacroExpansion,
461461
inner_attr: bool,
462462
parent_scope: &ParentScope<'a>,
463463
node_id: NodeId,
@@ -505,8 +505,17 @@ impl<'a> Resolver<'a> {
505505

506506
let unexpected_res = if ext.macro_kind() != kind {
507507
Some((kind.article(), kind.descr_expected()))
508-
} else if require_inert && matches!(res, Res::Def(..)) {
509-
Some(("a", "non-macro attribute"))
508+
} else if matches!(res, Res::Def(..)) {
509+
match supports_macro_expansion {
510+
SupportsMacroExpansion::No => Some(("a", "non-macro attribute")),
511+
SupportsMacroExpansion::Yes { supports_inner_attrs } => {
512+
if inner_attr && !supports_inner_attrs {
513+
Some(("a", "non-macro inner attribute"))
514+
} else {
515+
None
516+
}
517+
}
518+
}
510519
} else {
511520
None
512521
};

src/test/ui/proc-macro/inner-attrs.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
// check-pass
21
// compile-flags: -Z span-debug --error-format human
32
// aux-build:test-macros.rs
43

54
#![feature(custom_inner_attributes)]
65
#![feature(proc_macro_hygiene)]
76
#![feature(stmt_expr_attributes)]
7+
#![feature(rustc_attrs)]
88

99
#![no_std] // Don't load unnecessary hygiene information from std
1010
extern crate std;
@@ -25,17 +25,34 @@ struct MyStruct {
2525

2626
fn bar() {
2727
(#![print_target_and_args(fifth)] 1, 2);
28+
//~^ ERROR expected non-macro inner attribute, found attribute macro
29+
30+
#[print_target_and_args(tuple_attrs)] (
31+
#![cfg_attr(FALSE, rustc_dummy)]
32+
3, 4, {
33+
#![cfg_attr(not(FALSE), rustc_dummy(innermost))]
34+
5
35+
}
36+
);
37+
38+
#[print_target_and_args(array_attrs)] [
39+
#![rustc_dummy(inner)]
40+
true; 0
41+
];
2842

2943
[#![print_target_and_args(sixth)] 1 , 2];
44+
//~^ ERROR expected non-macro inner attribute, found attribute macro
3045
[#![print_target_and_args(seventh)] true ; 5];
31-
46+
//~^ ERROR expected non-macro inner attribute, found attribute macro
3247

3348
match 0 {
3449
#![print_target_and_args(eighth)]
50+
//~^ ERROR expected non-macro inner attribute, found attribute macro
3551
_ => {}
3652
}
3753

3854
MyStruct { #![print_target_and_args(ninth)] field: true };
55+
//~^ ERROR expected non-macro inner attribute, found attribute macro
3956
}
4057

4158
extern {
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
2+
--> $DIR/inner-attrs.rs:27:9
3+
|
4+
LL | (#![print_target_and_args(fifth)] 1, 2);
5+
| ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
6+
7+
error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
8+
--> $DIR/inner-attrs.rs:43:9
9+
|
10+
LL | [#![print_target_and_args(sixth)] 1 , 2];
11+
| ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
12+
13+
error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
14+
--> $DIR/inner-attrs.rs:45:9
15+
|
16+
LL | [#![print_target_and_args(seventh)] true ; 5];
17+
| ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
18+
19+
error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
20+
--> $DIR/inner-attrs.rs:49:12
21+
|
22+
LL | #![print_target_and_args(eighth)]
23+
| ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
24+
25+
error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
26+
--> $DIR/inner-attrs.rs:54:19
27+
|
28+
LL | MyStruct { #![print_target_and_args(ninth)] field: true };
29+
| ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
30+
31+
error: aborting due to 5 previous errors
32+

0 commit comments

Comments
 (0)