Skip to content

Commit a4cc3cb

Browse files
authored
Unrolled build for #150971
Rollup merge of #150971 - disallow-eii-in-statement-position, r=wafflelapkin Disallow eii in statement position With how v2 macros resolve, and the name resolution of `super` works, I realized with @WaffleLapkin that there's actually no way to consistently expand EIIs in statement position. r? @WaffleLapkin
2 parents 86a49fd + 8dd701c commit a4cc3cb

File tree

5 files changed

+61
-70
lines changed

5 files changed

+61
-70
lines changed

‎compiler/rustc_builtin_macros/messages.ftl‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ builtin_macros_eii_only_once = `#[{$name}]` can only be specified once
161161
162162
builtin_macros_eii_shared_macro_expected_function = `#[{$name}]` is only valid on functions
163163
builtin_macros_eii_shared_macro_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]`
164+
builtin_macros_eii_shared_macro_in_statement_position = `#[{$name}]` can only be used on functions inside a module
165+
.label = `#[{$name}]` is used on this item, which is part of another item's local scope
164166
165167
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
166168
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead

‎compiler/rustc_builtin_macros/src/eii.rs‎

Lines changed: 30 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use rustc_ast::token::{Delimiter, TokenKind};
22
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
33
use rustc_ast::{
4-
Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, Stmt, StmtKind,
5-
Visibility, ast,
4+
Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, StmtKind, Visibility, ast,
65
};
76
use rustc_ast_pretty::pprust::path_to_string;
87
use rustc_expand::base::{Annotatable, ExtCtxt};
@@ -12,6 +11,7 @@ use thin_vec::{ThinVec, thin_vec};
1211
use crate::errors::{
1312
EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe,
1413
EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction,
14+
EiiSharedMacroInStatementPosition,
1515
};
1616

1717
/// ```rust
@@ -55,29 +55,29 @@ fn eii_(
5555
ecx: &mut ExtCtxt<'_>,
5656
eii_attr_span: Span,
5757
meta_item: &ast::MetaItem,
58-
item: Annotatable,
58+
orig_item: Annotatable,
5959
impl_unsafe: bool,
6060
) -> Vec<Annotatable> {
6161
let eii_attr_span = ecx.with_def_site_ctxt(eii_attr_span);
6262

63-
let (item, wrap_item): (_, &dyn Fn(_) -> _) = if let Annotatable::Item(item) = item {
64-
(item, &Annotatable::Item)
65-
} else if let Annotatable::Stmt(ref stmt) = item
63+
let item = if let Annotatable::Item(item) = orig_item {
64+
item
65+
} else if let Annotatable::Stmt(ref stmt) = orig_item
6666
&& let StmtKind::Item(ref item) = stmt.kind
67+
&& let ItemKind::Fn(ref f) = item.kind
6768
{
68-
(item.clone(), &|item| {
69-
Annotatable::Stmt(Box::new(Stmt {
70-
id: DUMMY_NODE_ID,
71-
kind: StmtKind::Item(item),
72-
span: eii_attr_span,
73-
}))
74-
})
69+
ecx.dcx().emit_err(EiiSharedMacroInStatementPosition {
70+
span: eii_attr_span.to(item.span),
71+
name: path_to_string(&meta_item.path),
72+
item_span: f.ident.span,
73+
});
74+
return vec![orig_item];
7575
} else {
7676
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
7777
span: eii_attr_span,
7878
name: path_to_string(&meta_item.path),
7979
});
80-
return vec![item];
80+
return vec![orig_item];
8181
};
8282

8383
let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } =
@@ -87,7 +87,7 @@ fn eii_(
8787
span: eii_attr_span,
8888
name: path_to_string(&meta_item.path),
8989
});
90-
return vec![wrap_item(item)];
90+
return vec![Annotatable::Item(item)];
9191
};
9292
// only clone what we need
9393
let attrs = attrs.clone();
@@ -98,17 +98,19 @@ fn eii_(
9898
filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path);
9999

100100
let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else {
101-
return vec![wrap_item(item)];
101+
// we don't need to wrap in Annotatable::Stmt conditionally since
102+
// EII can't be used on items in statement position
103+
return vec![Annotatable::Item(item)];
102104
};
103105

104106
// span of the declaring item without attributes
105107
let item_span = func.sig.span;
106108
let foreign_item_name = func.ident;
107109

108-
let mut return_items = Vec::new();
110+
let mut module_items = Vec::new();
109111

110112
if func.body.is_some() {
111-
return_items.push(generate_default_impl(
113+
module_items.push(generate_default_impl(
112114
ecx,
113115
&func,
114116
impl_unsafe,
@@ -119,15 +121,15 @@ fn eii_(
119121
))
120122
}
121123

122-
return_items.push(generate_foreign_item(
124+
module_items.push(generate_foreign_item(
123125
ecx,
124126
eii_attr_span,
125127
item_span,
126128
func,
127129
vis,
128130
&attrs_from_decl,
129131
));
130-
return_items.push(generate_attribute_macro_to_implement(
132+
module_items.push(generate_attribute_macro_to_implement(
131133
ecx,
132134
eii_attr_span,
133135
macro_name,
@@ -136,7 +138,9 @@ fn eii_(
136138
&attrs_from_decl,
137139
));
138140

139-
return_items.into_iter().map(wrap_item).collect()
141+
// we don't need to wrap in Annotatable::Stmt conditionally since
142+
// EII can't be used on items in statement position
143+
module_items.into_iter().map(Annotatable::Item).collect()
140144
}
141145

142146
/// Decide on the name of the macro that can be used to implement the EII.
@@ -213,29 +217,14 @@ fn generate_default_impl(
213217
known_eii_macro_resolution: Some(ast::EiiDecl {
214218
foreign_item: ecx.path(
215219
foreign_item_name.span,
216-
// prefix super to escape the `dflt` module generated below
217-
vec![Ident::from_str_and_span("super", foreign_item_name.span), foreign_item_name],
220+
// prefix self to explicitly escape the const block generated below
221+
// NOTE: this is why EIIs can't be used on statements
222+
vec![Ident::from_str_and_span("self", foreign_item_name.span), foreign_item_name],
218223
),
219224
impl_unsafe,
220225
}),
221226
});
222227

223-
let item_mod = |span: Span, name: Ident, items: ThinVec<Box<ast::Item>>| {
224-
ecx.item(
225-
item_span,
226-
ThinVec::new(),
227-
ItemKind::Mod(
228-
ast::Safety::Default,
229-
name,
230-
ast::ModKind::Loaded(
231-
items,
232-
ast::Inline::Yes,
233-
ast::ModSpans { inner_span: span, inject_use_span: span },
234-
),
235-
),
236-
)
237-
};
238-
239228
let anon_mod = |span: Span, stmts: ThinVec<ast::Stmt>| {
240229
let unit = ecx.ty(item_span, ast::TyKind::Tup(ThinVec::new()));
241230
let underscore = Ident::new(kw::Underscore, item_span);
@@ -248,33 +237,13 @@ fn generate_default_impl(
248237
};
249238

250239
// const _: () = {
251-
// mod dflt {
252-
// use super::*;
253-
// <orig fn>
254-
// }
240+
// <orig fn>
255241
// }
256242
anon_mod(
257243
item_span,
258244
thin_vec![ecx.stmt_item(
259245
item_span,
260-
item_mod(
261-
item_span,
262-
Ident::from_str_and_span("dflt", item_span),
263-
thin_vec![
264-
ecx.item(
265-
item_span,
266-
thin_vec![ecx.attr_nested_word(sym::allow, sym::unused_imports, item_span)],
267-
ItemKind::Use(ast::UseTree {
268-
prefix: ast::Path::from_ident(Ident::from_str_and_span(
269-
"super", item_span,
270-
)),
271-
kind: ast::UseTreeKind::Glob,
272-
span: item_span,
273-
})
274-
),
275-
ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func)))
276-
]
277-
)
246+
ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func)))
278247
),],
279248
)
280249
}

‎compiler/rustc_builtin_macros/src/errors.rs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,16 @@ pub(crate) struct EiiSharedMacroExpectedFunction {
10391039
pub name: String,
10401040
}
10411041

1042+
#[derive(Diagnostic)]
1043+
#[diag(builtin_macros_eii_shared_macro_in_statement_position)]
1044+
pub(crate) struct EiiSharedMacroInStatementPosition {
1045+
#[primary_span]
1046+
pub span: Span,
1047+
pub name: String,
1048+
#[label]
1049+
pub item_span: Span,
1050+
}
1051+
10421052
#[derive(Diagnostic)]
10431053
#[diag(builtin_macros_eii_only_once)]
10441054
pub(crate) struct EiiOnlyOnce {
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
#![feature(extern_item_impls)]
2-
// EIIs can, despite not being super useful, be declared in statement position
3-
// nested inside items. Items in statement position, when expanded as part of a macro,
4-
// need to be wrapped slightly differently (in an `ast::Statement`).
5-
// We did this on the happy path (no errors), but when there was an error, we'd
6-
// replace it with *just* an `ast::Item` not wrapped in an `ast::Statement`.
7-
// This caused an ICE (https://github.com/rust-lang/rust/issues/149980).
8-
// this test fails to build, but demonstrates that no ICE is produced.
2+
// EIIs cannot be used in statement position.
3+
// This is also a regression test for an ICE (https://github.com/rust-lang/rust/issues/149980).
94

105
fn main() {
116
struct Bar;
127

138
#[eii]
149
//~^ ERROR `#[eii]` is only valid on functions
1510
impl Bar {}
11+
12+
13+
// Even on functions, eiis in statement position are rejected
14+
#[eii]
15+
//~^ ERROR `#[eii]` can only be used on functions inside a module
16+
fn foo() {}
1617
}
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
error: `#[eii]` is only valid on functions
2-
--> $DIR/error_statement_position.rs:13:5
2+
--> $DIR/error_statement_position.rs:8:5
33
|
44
LL | #[eii]
55
| ^^^^^^
66

7-
error: aborting due to 1 previous error
7+
error: `#[eii]` can only be used on functions inside a module
8+
--> $DIR/error_statement_position.rs:14:5
9+
|
10+
LL | #[eii]
11+
| ^^^^^^
12+
LL |
13+
LL | fn foo() {}
14+
| --- `#[eii]` is used on this item, which is part of another item's local scope
15+
16+
error: aborting due to 2 previous errors
817

0 commit comments

Comments
 (0)