Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1350be7

Browse files
authoredMar 16, 2020
Rollup merge of rust-lang#69870 - petrochenkov:cfgacc, r=matthewjasper
expand: Implement something similar to `#[cfg(accessible(path))]` cc rust-lang#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 59f4ba9 + 2e65289 commit 1350be7

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)]

‎src/librustc_expand/expand.rs

+103-42
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
408408
let mut undetermined_invocations = Vec::new();
409409
let (mut progress, mut force) = (false, !self.monotonic);
410410
loop {
411-
let invoc = if let Some(invoc) = invocations.pop() {
411+
let (invoc, res) = if let Some(invoc) = invocations.pop() {
412412
invoc
413413
} else {
414414
self.resolve_imports();
@@ -420,30 +420,51 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
420420
continue;
421421
};
422422

423-
let eager_expansion_root =
424-
if self.monotonic { invoc.expansion_data.id } else { orig_expansion_data.id };
425-
let res = match self.cx.resolver.resolve_macro_invocation(
426-
&invoc,
427-
eager_expansion_root,
428-
force,
429-
) {
430-
Ok(res) => res,
431-
Err(Indeterminate) => {
432-
undetermined_invocations.push(invoc);
433-
continue;
423+
let res = match res {
424+
Some(res) => res,
425+
None => {
426+
let eager_expansion_root = if self.monotonic {
427+
invoc.expansion_data.id
428+
} else {
429+
orig_expansion_data.id
430+
};
431+
match self.cx.resolver.resolve_macro_invocation(
432+
&invoc,
433+
eager_expansion_root,
434+
force,
435+
) {
436+
Ok(res) => res,
437+
Err(Indeterminate) => {
438+
// Cannot resolve, will retry this invocation later.
439+
undetermined_invocations.push((invoc, None));
440+
continue;
441+
}
442+
}
434443
}
435444
};
436445

437-
progress = true;
438446
let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data;
439447
self.cx.current_expansion = invoc.expansion_data.clone();
440448

441449
// FIXME(jseyfried): Refactor out the following logic
442450
let (expanded_fragment, new_invocations) = match res {
443-
InvocationRes::Single(ext) => {
444-
let fragment = self.expand_invoc(invoc, &ext.kind);
445-
self.collect_invocations(fragment, &[])
446-
}
451+
InvocationRes::Single(ext) => match self.expand_invoc(invoc, &ext.kind) {
452+
ExpandResult::Ready(fragment) => self.collect_invocations(fragment, &[]),
453+
ExpandResult::Retry(invoc, explanation) => {
454+
if force {
455+
// We are stuck, stop retrying and produce a dummy fragment.
456+
let span = invoc.span();
457+
self.cx.span_err(span, &explanation);
458+
let fragment = invoc.fragment_kind.dummy(span);
459+
self.collect_invocations(fragment, &[])
460+
} else {
461+
// Cannot expand, will retry this invocation later.
462+
undetermined_invocations
463+
.push((invoc, Some(InvocationRes::Single(ext))));
464+
continue;
465+
}
466+
}
467+
},
447468
InvocationRes::DeriveContainer(_exts) => {
448469
// FIXME: Consider using the derive resolutions (`_exts`) immediately,
449470
// instead of enqueuing the derives to be resolved again later.
@@ -463,21 +484,25 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
463484
for path in derives {
464485
let expn_id = ExpnId::fresh(None);
465486
derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id));
466-
invocations.push(Invocation {
467-
kind: InvocationKind::Derive { path, item: item.clone() },
468-
fragment_kind: invoc.fragment_kind,
469-
expansion_data: ExpansionData {
470-
id: expn_id,
471-
..invoc.expansion_data.clone()
487+
invocations.push((
488+
Invocation {
489+
kind: InvocationKind::Derive { path, item: item.clone() },
490+
fragment_kind: invoc.fragment_kind,
491+
expansion_data: ExpansionData {
492+
id: expn_id,
493+
..invoc.expansion_data.clone()
494+
},
472495
},
473-
});
496+
None,
497+
));
474498
}
475499
let fragment =
476500
invoc.fragment_kind.expect_from_annotatables(::std::iter::once(item));
477501
self.collect_invocations(fragment, &derive_placeholders)
478502
}
479503
};
480504

505+
progress = true;
481506
if expanded_fragments.len() < depth {
482507
expanded_fragments.push(Vec::new());
483508
}
@@ -535,7 +560,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
535560
&mut self,
536561
mut fragment: AstFragment,
537562
extra_placeholders: &[NodeId],
538-
) -> (AstFragment, Vec<Invocation>) {
563+
) -> (AstFragment, Vec<(Invocation, Option<InvocationRes>)>) {
539564
// Resolve `$crate`s in the fragment for pretty-printing.
540565
self.cx.resolver.resolve_dollar_crates();
541566

@@ -635,13 +660,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
635660
self.cx.trace_macros_diag();
636661
}
637662

638-
fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment {
663+
fn expand_invoc(
664+
&mut self,
665+
invoc: Invocation,
666+
ext: &SyntaxExtensionKind,
667+
) -> ExpandResult<AstFragment, Invocation> {
639668
if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
640669
self.error_recursion_limit_reached();
641670
}
642671

643672
let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
644-
match invoc.kind {
673+
ExpandResult::Ready(match invoc.kind {
645674
InvocationKind::Bang { mac, .. } => match ext {
646675
SyntaxExtensionKind::Bang(expander) => {
647676
self.gate_proc_macro_expansion_kind(span, fragment_kind);
@@ -663,7 +692,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
663692
}
664693
_ => unreachable!(),
665694
},
666-
InvocationKind::Attr { attr, mut item, .. } => match ext {
695+
InvocationKind::Attr { attr, mut item, derives, after_derive } => match ext {
667696
SyntaxExtensionKind::Attr(expander) => {
668697
self.gate_proc_macro_input(&item);
669698
self.gate_proc_macro_attr_item(span, &item);
@@ -679,8 +708,25 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
679708
SyntaxExtensionKind::LegacyAttr(expander) => {
680709
match validate_attr::parse_meta(self.cx.parse_sess, &attr) {
681710
Ok(meta) => {
682-
let item = expander.expand(self.cx, span, &meta, item);
683-
fragment_kind.expect_from_annotatables(item)
711+
let items = match expander.expand(self.cx, span, &meta, item) {
712+
ExpandResult::Ready(items) => items,
713+
ExpandResult::Retry(item, explanation) => {
714+
// Reassemble the original invocation for retrying.
715+
return ExpandResult::Retry(
716+
Invocation {
717+
kind: InvocationKind::Attr {
718+
attr,
719+
item,
720+
derives,
721+
after_derive,
722+
},
723+
..invoc
724+
},
725+
explanation,
726+
);
727+
}
728+
};
729+
fragment_kind.expect_from_annotatables(items)
684730
}
685731
Err(mut err) => {
686732
err.emit();
@@ -702,19 +748,31 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
702748
SyntaxExtensionKind::Derive(expander)
703749
| SyntaxExtensionKind::LegacyDerive(expander) => {
704750
if !item.derive_allowed() {
705-
return fragment_kind.dummy(span);
751+
return ExpandResult::Ready(fragment_kind.dummy(span));
706752
}
707753
if let SyntaxExtensionKind::Derive(..) = ext {
708754
self.gate_proc_macro_input(&item);
709755
}
710756
let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path };
711-
let items = expander.expand(self.cx, span, &meta, item);
757+
let items = match expander.expand(self.cx, span, &meta, item) {
758+
ExpandResult::Ready(items) => items,
759+
ExpandResult::Retry(item, explanation) => {
760+
// Reassemble the original invocation for retrying.
761+
return ExpandResult::Retry(
762+
Invocation {
763+
kind: InvocationKind::Derive { path: meta.path, item },
764+
..invoc
765+
},
766+
explanation,
767+
);
768+
}
769+
};
712770
fragment_kind.expect_from_annotatables(items)
713771
}
714772
_ => unreachable!(),
715773
},
716774
InvocationKind::DeriveContainer { .. } => unreachable!(),
717-
}
775+
})
718776
}
719777

720778
fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
@@ -933,7 +991,7 @@ pub fn ensure_complete_parse<'a>(
933991
struct InvocationCollector<'a, 'b> {
934992
cx: &'a mut ExtCtxt<'b>,
935993
cfg: StripUnconfigured<'a>,
936-
invocations: Vec<Invocation>,
994+
invocations: Vec<(Invocation, Option<InvocationRes>)>,
937995
monotonic: bool,
938996
}
939997

@@ -955,15 +1013,18 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
9551013
};
9561014
let expn_id = ExpnId::fresh(expn_data);
9571015
let vis = kind.placeholder_visibility();
958-
self.invocations.push(Invocation {
959-
kind,
960-
fragment_kind,
961-
expansion_data: ExpansionData {
962-
id: expn_id,
963-
depth: self.cx.current_expansion.depth + 1,
964-
..self.cx.current_expansion.clone()
1016+
self.invocations.push((
1017+
Invocation {
1018+
kind,
1019+
fragment_kind,
1020+
expansion_data: ExpansionData {
1021+
id: expn_id,
1022+
depth: self.cx.current_expansion.depth + 1,
1023+
..self.cx.current_expansion.clone()
1024+
},
9651025
},
966-
});
1026+
None,
1027+
));
9671028
placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis)
9681029
}
9691030

‎src/librustc_expand/proc_macro.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl MultiItemModifier for ProcMacroDerive {
7979
span: Span,
8080
_meta_item: &ast::MetaItem,
8181
item: Annotatable,
82-
) -> Vec<Annotatable> {
82+
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
8383
let item = match item {
8484
Annotatable::Arm(..)
8585
| Annotatable::Field(..)
@@ -99,7 +99,7 @@ impl MultiItemModifier for ProcMacroDerive {
9999
"proc-macro derives may only be \
100100
applied to a struct, enum, or union",
101101
);
102-
return Vec::new();
102+
return ExpandResult::Ready(Vec::new());
103103
}
104104
};
105105
match item.kind {
@@ -110,7 +110,7 @@ impl MultiItemModifier for ProcMacroDerive {
110110
"proc-macro derives may only be \
111111
applied to a struct, enum, or union",
112112
);
113-
return Vec::new();
113+
return ExpandResult::Ready(Vec::new());
114114
}
115115
}
116116

@@ -158,7 +158,7 @@ impl MultiItemModifier for ProcMacroDerive {
158158
FatalError.raise();
159159
}
160160

161-
items
161+
ExpandResult::Ready(items)
162162
}
163163
}
164164

‎src/librustc_feature/builtin_attrs.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,13 @@ impl AttributeGate {
8585

8686
/// A template that the attribute input must match.
8787
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
88-
#[derive(Clone, Copy)]
88+
#[derive(Clone, Copy, Default)]
8989
pub struct AttributeTemplate {
9090
pub word: bool,
9191
pub list: Option<&'static str>,
9292
pub name_value_str: Option<&'static str>,
9393
}
9494

95-
impl AttributeTemplate {
96-
pub fn only_word() -> Self {
97-
Self { word: true, list: None, name_value_str: None }
98-
}
99-
}
100-
10195
/// A convenience macro for constructing attribute templates.
10296
/// E.g., `template!(Word, List: "description")` means that the attribute
10397
/// supports forms `#[attr]` and `#[attr(description)]`.

‎src/librustc_resolve/macros.rs

+36
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,42 @@ impl<'a> base::Resolver for Resolver<'a> {
345345
fn add_derive_copy(&mut self, expn_id: ExpnId) {
346346
self.containers_deriving_copy.insert(expn_id);
347347
}
348+
349+
// The function that implements the resolution logic of `#[cfg_accessible(path)]`.
350+
// Returns true if the path can certainly be resolved in one of three namespaces,
351+
// returns false if the path certainly cannot be resolved in any of the three namespaces.
352+
// Returns `Indeterminate` if we cannot give a certain answer yet.
353+
fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate> {
354+
let span = path.span;
355+
let path = &Segment::from_path(path);
356+
let parent_scope = self.invocation_parent_scopes[&expn_id];
357+
358+
let mut indeterminate = false;
359+
for ns in [TypeNS, ValueNS, MacroNS].iter().copied() {
360+
match self.resolve_path(path, Some(ns), &parent_scope, false, span, CrateLint::No) {
361+
PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true),
362+
PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => {
363+
return Ok(true);
364+
}
365+
PathResult::Indeterminate => indeterminate = true,
366+
// FIXME: `resolve_path` is not ready to report partially resolved paths
367+
// correctly, so we just report an error if the path was reported as unresolved.
368+
// This needs to be fixed for `cfg_accessible` to be useful.
369+
PathResult::NonModule(..) | PathResult::Failed { .. } => {}
370+
PathResult::Module(_) => panic!("unexpected path resolution"),
371+
}
372+
}
373+
374+
if indeterminate {
375+
return Err(Indeterminate);
376+
}
377+
378+
self.session
379+
.struct_span_err(span, "not sure whether the path is accessible or not")
380+
.span_note(span, "`cfg_accessible` is not fully implemented")
381+
.emit();
382+
Ok(false)
383+
}
348384
}
349385

350386
impl<'a> Resolver<'a> {

‎src/librustc_span/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ symbols! {
182182
caller_location,
183183
cdylib,
184184
cfg,
185+
cfg_accessible,
185186
cfg_attr,
186187
cfg_attr_multi,
187188
cfg_doctest,

‎src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@
240240
#![feature(atomic_mut_ptr)]
241241
#![feature(box_syntax)]
242242
#![feature(c_variadic)]
243+
#![cfg_attr(not(bootstrap), feature(cfg_accessible))]
243244
#![feature(cfg_target_has_atomic)]
244245
#![feature(cfg_target_thread_local)]
245246
#![feature(char_error_internals)]

‎src/libstd/prelude/v1.rs

+9
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ pub use core::prelude::v1::{
5353
PartialEq, PartialOrd, RustcDecodable, RustcEncodable,
5454
};
5555

56+
#[cfg(not(bootstrap))]
57+
#[unstable(
58+
feature = "cfg_accessible",
59+
issue = "64797",
60+
reason = "`cfg_accessible` is not fully implemented"
61+
)]
62+
#[doc(hidden)]
63+
pub use core::prelude::v1::cfg_accessible;
64+
5665
// The file so far is equivalent to src/libcore/prelude/v1.rs,
5766
// and below to src/liballoc/prelude.rs.
5867
// Those files are duplicated rather than using glob imports
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(cfg_accessible)]
2+
3+
#[cfg_accessible] //~ ERROR malformed `cfg_accessible` attribute input
4+
struct S1;
5+
6+
#[cfg_accessible = "value"] //~ ERROR malformed `cfg_accessible` attribute input
7+
struct S2;
8+
9+
#[cfg_accessible()] //~ ERROR `cfg_accessible` path is not specified
10+
struct S3;
11+
12+
#[cfg_accessible(std, core)] //~ ERROR multiple `cfg_accessible` paths are specified
13+
struct S4;
14+
15+
#[cfg_accessible("std")] //~ ERROR `cfg_accessible` path cannot be a literal
16+
struct S5;
17+
18+
#[cfg_accessible(std = "value")] //~ ERROR `cfg_accessible` path cannot accept arguments
19+
struct S6;
20+
21+
#[cfg_accessible(std(value))] //~ ERROR `cfg_accessible` path cannot accept arguments
22+
struct S7;
23+
24+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
error: malformed `cfg_accessible` attribute input
2+
--> $DIR/cfg_accessible-input-validation.rs:3:1
3+
|
4+
LL | #[cfg_accessible]
5+
| ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[cfg_accessible(path)]`
6+
7+
error: malformed `cfg_accessible` attribute input
8+
--> $DIR/cfg_accessible-input-validation.rs:6:1
9+
|
10+
LL | #[cfg_accessible = "value"]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[cfg_accessible(path)]`
12+
13+
error: `cfg_accessible` path is not specified
14+
--> $DIR/cfg_accessible-input-validation.rs:9:1
15+
|
16+
LL | #[cfg_accessible()]
17+
| ^^^^^^^^^^^^^^^^^^^
18+
19+
error: multiple `cfg_accessible` paths are specified
20+
--> $DIR/cfg_accessible-input-validation.rs:12:23
21+
|
22+
LL | #[cfg_accessible(std, core)]
23+
| ^^^^
24+
25+
error: `cfg_accessible` path cannot be a literal
26+
--> $DIR/cfg_accessible-input-validation.rs:15:18
27+
|
28+
LL | #[cfg_accessible("std")]
29+
| ^^^^^
30+
31+
error: `cfg_accessible` path cannot accept arguments
32+
--> $DIR/cfg_accessible-input-validation.rs:18:18
33+
|
34+
LL | #[cfg_accessible(std = "value")]
35+
| ^^^^^^^^^^^^^
36+
37+
error: `cfg_accessible` path cannot accept arguments
38+
--> $DIR/cfg_accessible-input-validation.rs:21:18
39+
|
40+
LL | #[cfg_accessible(std(value))]
41+
| ^^^^^^^^^^
42+
43+
error: aborting due to 7 previous errors
44+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![feature(cfg_accessible)]
2+
3+
#[cfg_accessible(Z)] //~ ERROR cannot determine whether the path is accessible or not
4+
struct S;
5+
6+
#[cfg_accessible(S)] //~ ERROR cannot determine whether the path is accessible or not
7+
struct Z;
8+
9+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: cannot determine whether the path is accessible or not
2+
--> $DIR/cfg_accessible-stuck.rs:6:1
3+
|
4+
LL | #[cfg_accessible(S)]
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
7+
error: cannot determine whether the path is accessible or not
8+
--> $DIR/cfg_accessible-stuck.rs:3:1
9+
|
10+
LL | #[cfg_accessible(Z)]
11+
| ^^^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to 2 previous errors
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#[cfg_accessible(std)] //~ ERROR use of unstable library feature 'cfg_accessible'
2+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0658]: use of unstable library feature 'cfg_accessible': `cfg_accessible` is not fully implemented
2+
--> $DIR/cfg_accessible-unstable.rs:1:3
3+
|
4+
LL | #[cfg_accessible(std)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #64797 <https://github.com/rust-lang/rust/issues/64797> for more information
8+
= help: add `#![feature(cfg_accessible)]` to the crate attributes to enable
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0658`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#![feature(cfg_accessible)]
2+
3+
mod m {
4+
pub struct ExistingPublic;
5+
struct ExistingPrivate;
6+
}
7+
8+
#[cfg_accessible(m::ExistingPublic)]
9+
struct ExistingPublic;
10+
11+
// FIXME: Not implemented yet.
12+
#[cfg_accessible(m::ExistingPrivate)] //~ ERROR not sure whether the path is accessible or not
13+
struct ExistingPrivate;
14+
15+
// FIXME: Not implemented yet.
16+
#[cfg_accessible(m::NonExistent)] //~ ERROR not sure whether the path is accessible or not
17+
struct ExistingPrivate;
18+
19+
#[cfg_accessible(n::AccessibleExpanded)] // OK, `cfg_accessible` can wait and retry.
20+
struct AccessibleExpanded;
21+
22+
macro_rules! generate_accessible_expanded {
23+
() => {
24+
mod n {
25+
pub struct AccessibleExpanded;
26+
}
27+
};
28+
}
29+
30+
generate_accessible_expanded!();
31+
32+
struct S {
33+
field: u8,
34+
}
35+
36+
// FIXME: Not implemented yet.
37+
#[cfg_accessible(S::field)] //~ ERROR not sure whether the path is accessible or not
38+
struct Field;
39+
40+
fn main() {
41+
ExistingPublic;
42+
AccessibleExpanded;
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error: not sure whether the path is accessible or not
2+
--> $DIR/cfg_accessible.rs:12:18
3+
|
4+
LL | #[cfg_accessible(m::ExistingPrivate)]
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
note: `cfg_accessible` is not fully implemented
8+
--> $DIR/cfg_accessible.rs:12:18
9+
|
10+
LL | #[cfg_accessible(m::ExistingPrivate)]
11+
| ^^^^^^^^^^^^^^^^^^
12+
13+
error: not sure whether the path is accessible or not
14+
--> $DIR/cfg_accessible.rs:16:18
15+
|
16+
LL | #[cfg_accessible(m::NonExistent)]
17+
| ^^^^^^^^^^^^^^
18+
|
19+
note: `cfg_accessible` is not fully implemented
20+
--> $DIR/cfg_accessible.rs:16:18
21+
|
22+
LL | #[cfg_accessible(m::NonExistent)]
23+
| ^^^^^^^^^^^^^^
24+
25+
error: not sure whether the path is accessible or not
26+
--> $DIR/cfg_accessible.rs:37:18
27+
|
28+
LL | #[cfg_accessible(S::field)]
29+
| ^^^^^^^^
30+
|
31+
note: `cfg_accessible` is not fully implemented
32+
--> $DIR/cfg_accessible.rs:37:18
33+
|
34+
LL | #[cfg_accessible(S::field)]
35+
| ^^^^^^^^
36+
37+
error: aborting due to 3 previous errors
38+

0 commit comments

Comments
 (0)
Please sign in to comment.