Skip to content

Commit 9fc5c2d

Browse files
authored
Rollup merge of #69870 - petrochenkov:cfgacc, r=matthewjasper
expand: Implement something similar to `#[cfg(accessible(path))]` cc #64797 The feature is implemented as a `#[cfg_accessible(path)]` attribute macro rather than as `#[cfg(accessible(path))]` because it needs to wait until `path` becomes resolvable, and `cfg` cannot wait, but macros can wait. Later we can think about desugaring or not desugaring `#[cfg(accessible(path))]` into `#[cfg_accessible(path)]`. This implementation is also incomplete in the sense that it never returns "false" from `cfg_accessible(path)`, it requires some tweaks to resolve, which is not quite ready to answer queries like this during early resolution. However, the most important part of this PR is not `cfg_accessible` itself, but expansion infrastructure for retrying expansions. Before this PR we could say "we cannot resolve this macro path, let's try it later", with this PR we can say "we cannot expand this macro, let's try it later" as well. This is a pre-requisite for - turning `#[derive(...)]` into a regular attribute macro, - properly supporting eager expansion for macros that cannot yet be resolved like ``` fn main() { println!(not_available_yet!()); } macro_rules! make_available { () => { #[macro_export] macro_rules! not_available_yet { () => { "Hello world!" } }} } make_available!(); ```
2 parents b691145 + 2e65289 commit 9fc5c2d

22 files changed

+439
-71
lines changed

src/libcore/macros/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1404,6 +1404,18 @@ pub(crate) mod builtin {
14041404
/* compiler built-in */
14051405
}
14061406

1407+
/// Keeps the item it's applied to if the passed path is accessible, and removes it otherwise.
1408+
#[cfg(not(bootstrap))]
1409+
#[unstable(
1410+
feature = "cfg_accessible",
1411+
issue = "64797",
1412+
reason = "`cfg_accessible` is not fully implemented"
1413+
)]
1414+
#[rustc_builtin_macro]
1415+
pub macro cfg_accessible($item:item) {
1416+
/* compiler built-in */
1417+
}
1418+
14071419
/// Unstable implementation detail of the `rustc` compiler, do not use.
14081420
#[rustc_builtin_macro]
14091421
#[stable(feature = "rust1", since = "1.0.0")]

src/libcore/prelude/v1.rs

+9
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,12 @@ pub use crate::{
6767
pub use crate::macros::builtin::{
6868
bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
6969
};
70+
71+
#[cfg(not(bootstrap))]
72+
#[unstable(
73+
feature = "cfg_accessible",
74+
issue = "64797",
75+
reason = "`cfg_accessible` is not fully implemented"
76+
)]
77+
#[doc(no_inline)]
78+
pub use crate::macros::builtin::cfg_accessible;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//! Implementation of the `#[cfg_accessible(path)]` attribute macro.
2+
3+
use rustc_ast::ast;
4+
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
5+
use rustc_feature::AttributeTemplate;
6+
use rustc_parse::validate_attr;
7+
use rustc_span::symbol::sym;
8+
use rustc_span::Span;
9+
10+
crate struct Expander;
11+
12+
fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
13+
match mi.meta_item_list() {
14+
None => {}
15+
Some([]) => ecx.span_err(mi.span, "`cfg_accessible` path is not specified"),
16+
Some([_, .., l]) => ecx.span_err(l.span(), "multiple `cfg_accessible` paths are specified"),
17+
Some([nmi]) => match nmi.meta_item() {
18+
None => ecx.span_err(nmi.span(), "`cfg_accessible` path cannot be a literal"),
19+
Some(mi) => {
20+
if !mi.is_word() {
21+
ecx.span_err(mi.span, "`cfg_accessible` path cannot accept arguments");
22+
}
23+
return Some(&mi.path);
24+
}
25+
},
26+
}
27+
None
28+
}
29+
30+
impl MultiItemModifier for Expander {
31+
fn expand(
32+
&self,
33+
ecx: &mut ExtCtxt<'_>,
34+
_span: Span,
35+
meta_item: &ast::MetaItem,
36+
item: Annotatable,
37+
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
38+
let template = AttributeTemplate { list: Some("path"), ..Default::default() };
39+
let attr = &ecx.attribute(meta_item.clone());
40+
validate_attr::check_builtin_attribute(ecx.parse_sess, attr, sym::cfg_accessible, template);
41+
42+
let path = match validate_input(ecx, meta_item) {
43+
Some(path) => path,
44+
None => return ExpandResult::Ready(Vec::new()),
45+
};
46+
47+
let failure_msg = "cannot determine whether the path is accessible or not";
48+
match ecx.resolver.cfg_accessible(ecx.current_expansion.id, path) {
49+
Ok(true) => ExpandResult::Ready(vec![item]),
50+
Ok(false) => ExpandResult::Ready(Vec::new()),
51+
Err(_) => ExpandResult::Retry(item, failure_msg.into()),
52+
}
53+
}
54+
}

src/librustc_builtin_macros/deriving/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use rustc_ast::ast::{self, ItemKind, MetaItem};
44
use rustc_ast::ptr::P;
5-
use rustc_expand::base::{Annotatable, ExtCtxt, MultiItemModifier};
5+
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
66
use rustc_span::symbol::{sym, Symbol};
77
use rustc_span::Span;
88

@@ -48,13 +48,13 @@ impl MultiItemModifier for BuiltinDerive {
4848
span: Span,
4949
meta_item: &MetaItem,
5050
item: Annotatable,
51-
) -> Vec<Annotatable> {
51+
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
5252
// FIXME: Built-in derives often forget to give spans contexts,
5353
// so we are doing it here in a centralized way.
5454
let span = ecx.with_def_site_ctxt(span);
5555
let mut items = Vec::new();
5656
(self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
57-
items
57+
ExpandResult::Ready(items)
5858
}
5959
}
6060

src/librustc_builtin_macros/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use rustc_span::symbol::sym;
2222
mod asm;
2323
mod assert;
2424
mod cfg;
25+
mod cfg_accessible;
2526
mod compile_error;
2627
mod concat;
2728
mod concat_idents;
@@ -85,6 +86,7 @@ pub fn register_builtin_macros(resolver: &mut dyn Resolver, edition: Edition) {
8586

8687
register_attr! {
8788
bench: test::expand_bench,
89+
cfg_accessible: cfg_accessible::Expander,
8890
global_allocator: global_allocator::expand,
8991
test: test::expand_test,
9092
test_case: test::expand_test_case,

src/librustc_builtin_macros/util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_span::Symbol;
66

77
pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
88
// All the built-in macro attributes are "words" at the moment.
9-
let template = AttributeTemplate::only_word();
9+
let template = AttributeTemplate { word: true, ..Default::default() };
1010
let attr = ecx.attribute(meta_item.clone());
1111
validate_attr::check_builtin_attribute(ecx.parse_sess, &attr, name, template);
1212
}

src/librustc_expand/base.rs

+17-14
Original file line numberDiff line numberDiff line change
@@ -258,37 +258,39 @@ impl Annotatable {
258258
}
259259
}
260260

261-
// `meta_item` is the annotation, and `item` is the item being modified.
262-
// FIXME Decorators should follow the same pattern too.
261+
/// Result of an expansion that may need to be retried.
262+
/// Consider using this for non-`MultiItemModifier` expanders as well.
263+
pub enum ExpandResult<T, U> {
264+
/// Expansion produced a result (possibly dummy).
265+
Ready(T),
266+
/// Expansion could not produce a result and needs to be retried.
267+
/// The string is an explanation that will be printed if we are stuck in an infinite retry loop.
268+
Retry(U, String),
269+
}
270+
271+
// `meta_item` is the attribute, and `item` is the item being modified.
263272
pub trait MultiItemModifier {
264273
fn expand(
265274
&self,
266275
ecx: &mut ExtCtxt<'_>,
267276
span: Span,
268277
meta_item: &ast::MetaItem,
269278
item: Annotatable,
270-
) -> Vec<Annotatable>;
279+
) -> ExpandResult<Vec<Annotatable>, Annotatable>;
271280
}
272281

273-
impl<F, T> MultiItemModifier for F
282+
impl<F> MultiItemModifier for F
274283
where
275-
F: Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, Annotatable) -> T,
276-
T: Into<Vec<Annotatable>>,
284+
F: Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, Annotatable) -> Vec<Annotatable>,
277285
{
278286
fn expand(
279287
&self,
280288
ecx: &mut ExtCtxt<'_>,
281289
span: Span,
282290
meta_item: &ast::MetaItem,
283291
item: Annotatable,
284-
) -> Vec<Annotatable> {
285-
(*self)(ecx, span, meta_item, item).into()
286-
}
287-
}
288-
289-
impl Into<Vec<Annotatable>> for Annotatable {
290-
fn into(self) -> Vec<Annotatable> {
291-
vec![self]
292+
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
293+
ExpandResult::Ready(self(ecx, span, meta_item, item))
292294
}
293295
}
294296

@@ -895,6 +897,7 @@ pub trait Resolver {
895897

896898
fn has_derive_copy(&self, expn_id: ExpnId) -> bool;
897899
fn add_derive_copy(&mut self, expn_id: ExpnId);
900+
fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate>;
898901
}
899902

900903
#[derive(Clone)]

0 commit comments

Comments
 (0)