1
Fork 0

Rollup merge of #69870 - petrochenkov:cfgacc, r=matthewjasper

expand: Implement something similar to `#[cfg(accessible(path))]`

cc https://github.com/rust-lang/rust/issues/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!();
    ```
This commit is contained in:
Mazdak Farrokhzad 2020-03-17 03:05:12 +01:00 committed by GitHub
commit 9fc5c2d00d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 439 additions and 71 deletions

View file

@ -1404,6 +1404,18 @@ pub(crate) mod builtin {
/* compiler built-in */
}
/// Keeps the item it's applied to if the passed path is accessible, and removes it otherwise.
#[cfg(not(bootstrap))]
#[unstable(
feature = "cfg_accessible",
issue = "64797",
reason = "`cfg_accessible` is not fully implemented"
)]
#[rustc_builtin_macro]
pub macro cfg_accessible($item:item) {
/* compiler built-in */
}
/// Unstable implementation detail of the `rustc` compiler, do not use.
#[rustc_builtin_macro]
#[stable(feature = "rust1", since = "1.0.0")]

View file

@ -67,3 +67,12 @@ pub use crate::{
pub use crate::macros::builtin::{
bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
};
#[cfg(not(bootstrap))]
#[unstable(
feature = "cfg_accessible",
issue = "64797",
reason = "`cfg_accessible` is not fully implemented"
)]
#[doc(no_inline)]
pub use crate::macros::builtin::cfg_accessible;

View file

@ -0,0 +1,54 @@
//! Implementation of the `#[cfg_accessible(path)]` attribute macro.
use rustc_ast::ast;
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
use rustc_feature::AttributeTemplate;
use rustc_parse::validate_attr;
use rustc_span::symbol::sym;
use rustc_span::Span;
crate struct Expander;
fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
match mi.meta_item_list() {
None => {}
Some([]) => ecx.span_err(mi.span, "`cfg_accessible` path is not specified"),
Some([_, .., l]) => ecx.span_err(l.span(), "multiple `cfg_accessible` paths are specified"),
Some([nmi]) => match nmi.meta_item() {
None => ecx.span_err(nmi.span(), "`cfg_accessible` path cannot be a literal"),
Some(mi) => {
if !mi.is_word() {
ecx.span_err(mi.span, "`cfg_accessible` path cannot accept arguments");
}
return Some(&mi.path);
}
},
}
None
}
impl MultiItemModifier for Expander {
fn expand(
&self,
ecx: &mut ExtCtxt<'_>,
_span: Span,
meta_item: &ast::MetaItem,
item: Annotatable,
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
let template = AttributeTemplate { list: Some("path"), ..Default::default() };
let attr = &ecx.attribute(meta_item.clone());
validate_attr::check_builtin_attribute(ecx.parse_sess, attr, sym::cfg_accessible, template);
let path = match validate_input(ecx, meta_item) {
Some(path) => path,
None => return ExpandResult::Ready(Vec::new()),
};
let failure_msg = "cannot determine whether the path is accessible or not";
match ecx.resolver.cfg_accessible(ecx.current_expansion.id, path) {
Ok(true) => ExpandResult::Ready(vec![item]),
Ok(false) => ExpandResult::Ready(Vec::new()),
Err(_) => ExpandResult::Retry(item, failure_msg.into()),
}
}
}

View file

@ -2,7 +2,7 @@
use rustc_ast::ast::{self, ItemKind, MetaItem};
use rustc_ast::ptr::P;
use rustc_expand::base::{Annotatable, ExtCtxt, MultiItemModifier};
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
@ -48,13 +48,13 @@ impl MultiItemModifier for BuiltinDerive {
span: Span,
meta_item: &MetaItem,
item: Annotatable,
) -> Vec<Annotatable> {
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
// FIXME: Built-in derives often forget to give spans contexts,
// so we are doing it here in a centralized way.
let span = ecx.with_def_site_ctxt(span);
let mut items = Vec::new();
(self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
items
ExpandResult::Ready(items)
}
}

View file

@ -22,6 +22,7 @@ use rustc_span::symbol::sym;
mod asm;
mod assert;
mod cfg;
mod cfg_accessible;
mod compile_error;
mod concat;
mod concat_idents;
@ -85,6 +86,7 @@ pub fn register_builtin_macros(resolver: &mut dyn Resolver, edition: Edition) {
register_attr! {
bench: test::expand_bench,
cfg_accessible: cfg_accessible::Expander,
global_allocator: global_allocator::expand,
test: test::expand_test,
test_case: test::expand_test_case,

View file

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

View file

@ -258,8 +258,17 @@ impl Annotatable {
}
}
// `meta_item` is the annotation, and `item` is the item being modified.
// FIXME Decorators should follow the same pattern too.
/// Result of an expansion that may need to be retried.
/// Consider using this for non-`MultiItemModifier` expanders as well.
pub enum ExpandResult<T, U> {
/// Expansion produced a result (possibly dummy).
Ready(T),
/// Expansion could not produce a result and needs to be retried.
/// The string is an explanation that will be printed if we are stuck in an infinite retry loop.
Retry(U, String),
}
// `meta_item` is the attribute, and `item` is the item being modified.
pub trait MultiItemModifier {
fn expand(
&self,
@ -267,13 +276,12 @@ pub trait MultiItemModifier {
span: Span,
meta_item: &ast::MetaItem,
item: Annotatable,
) -> Vec<Annotatable>;
) -> ExpandResult<Vec<Annotatable>, Annotatable>;
}
impl<F, T> MultiItemModifier for F
impl<F> MultiItemModifier for F
where
F: Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, Annotatable) -> T,
T: Into<Vec<Annotatable>>,
F: Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, Annotatable) -> Vec<Annotatable>,
{
fn expand(
&self,
@ -281,14 +289,8 @@ where
span: Span,
meta_item: &ast::MetaItem,
item: Annotatable,
) -> Vec<Annotatable> {
(*self)(ecx, span, meta_item, item).into()
}
}
impl Into<Vec<Annotatable>> for Annotatable {
fn into(self) -> Vec<Annotatable> {
vec![self]
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
ExpandResult::Ready(self(ecx, span, meta_item, item))
}
}
@ -895,6 +897,7 @@ pub trait Resolver {
fn has_derive_copy(&self, expn_id: ExpnId) -> bool;
fn add_derive_copy(&mut self, expn_id: ExpnId);
fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate>;
}
#[derive(Clone)]

View file

@ -408,7 +408,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let mut undetermined_invocations = Vec::new();
let (mut progress, mut force) = (false, !self.monotonic);
loop {
let invoc = if let Some(invoc) = invocations.pop() {
let (invoc, res) = if let Some(invoc) = invocations.pop() {
invoc
} else {
self.resolve_imports();
@ -420,30 +420,51 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
continue;
};
let eager_expansion_root =
if self.monotonic { invoc.expansion_data.id } else { orig_expansion_data.id };
let res = match self.cx.resolver.resolve_macro_invocation(
&invoc,
eager_expansion_root,
force,
) {
Ok(res) => res,
Err(Indeterminate) => {
undetermined_invocations.push(invoc);
continue;
let res = match res {
Some(res) => res,
None => {
let eager_expansion_root = if self.monotonic {
invoc.expansion_data.id
} else {
orig_expansion_data.id
};
match self.cx.resolver.resolve_macro_invocation(
&invoc,
eager_expansion_root,
force,
) {
Ok(res) => res,
Err(Indeterminate) => {
// Cannot resolve, will retry this invocation later.
undetermined_invocations.push((invoc, None));
continue;
}
}
}
};
progress = true;
let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data;
self.cx.current_expansion = invoc.expansion_data.clone();
// FIXME(jseyfried): Refactor out the following logic
let (expanded_fragment, new_invocations) = match res {
InvocationRes::Single(ext) => {
let fragment = self.expand_invoc(invoc, &ext.kind);
self.collect_invocations(fragment, &[])
}
InvocationRes::Single(ext) => match self.expand_invoc(invoc, &ext.kind) {
ExpandResult::Ready(fragment) => self.collect_invocations(fragment, &[]),
ExpandResult::Retry(invoc, explanation) => {
if force {
// We are stuck, stop retrying and produce a dummy fragment.
let span = invoc.span();
self.cx.span_err(span, &explanation);
let fragment = invoc.fragment_kind.dummy(span);
self.collect_invocations(fragment, &[])
} else {
// Cannot expand, will retry this invocation later.
undetermined_invocations
.push((invoc, Some(InvocationRes::Single(ext))));
continue;
}
}
},
InvocationRes::DeriveContainer(_exts) => {
// FIXME: Consider using the derive resolutions (`_exts`) immediately,
// instead of enqueuing the derives to be resolved again later.
@ -463,14 +484,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
for path in derives {
let expn_id = ExpnId::fresh(None);
derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id));
invocations.push(Invocation {
kind: InvocationKind::Derive { path, item: item.clone() },
fragment_kind: invoc.fragment_kind,
expansion_data: ExpansionData {
id: expn_id,
..invoc.expansion_data.clone()
invocations.push((
Invocation {
kind: InvocationKind::Derive { path, item: item.clone() },
fragment_kind: invoc.fragment_kind,
expansion_data: ExpansionData {
id: expn_id,
..invoc.expansion_data.clone()
},
},
});
None,
));
}
let fragment =
invoc.fragment_kind.expect_from_annotatables(::std::iter::once(item));
@ -478,6 +502,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
};
progress = true;
if expanded_fragments.len() < depth {
expanded_fragments.push(Vec::new());
}
@ -535,7 +560,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
&mut self,
mut fragment: AstFragment,
extra_placeholders: &[NodeId],
) -> (AstFragment, Vec<Invocation>) {
) -> (AstFragment, Vec<(Invocation, Option<InvocationRes>)>) {
// Resolve `$crate`s in the fragment for pretty-printing.
self.cx.resolver.resolve_dollar_crates();
@ -635,13 +660,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
self.cx.trace_macros_diag();
}
fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment {
fn expand_invoc(
&mut self,
invoc: Invocation,
ext: &SyntaxExtensionKind,
) -> ExpandResult<AstFragment, Invocation> {
if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
self.error_recursion_limit_reached();
}
let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
match invoc.kind {
ExpandResult::Ready(match invoc.kind {
InvocationKind::Bang { mac, .. } => match ext {
SyntaxExtensionKind::Bang(expander) => {
self.gate_proc_macro_expansion_kind(span, fragment_kind);
@ -663,7 +692,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
_ => unreachable!(),
},
InvocationKind::Attr { attr, mut item, .. } => match ext {
InvocationKind::Attr { attr, mut item, derives, after_derive } => match ext {
SyntaxExtensionKind::Attr(expander) => {
self.gate_proc_macro_input(&item);
self.gate_proc_macro_attr_item(span, &item);
@ -679,8 +708,25 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
SyntaxExtensionKind::LegacyAttr(expander) => {
match validate_attr::parse_meta(self.cx.parse_sess, &attr) {
Ok(meta) => {
let item = expander.expand(self.cx, span, &meta, item);
fragment_kind.expect_from_annotatables(item)
let items = match expander.expand(self.cx, span, &meta, item) {
ExpandResult::Ready(items) => items,
ExpandResult::Retry(item, explanation) => {
// Reassemble the original invocation for retrying.
return ExpandResult::Retry(
Invocation {
kind: InvocationKind::Attr {
attr,
item,
derives,
after_derive,
},
..invoc
},
explanation,
);
}
};
fragment_kind.expect_from_annotatables(items)
}
Err(mut err) => {
err.emit();
@ -702,19 +748,31 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
SyntaxExtensionKind::Derive(expander)
| SyntaxExtensionKind::LegacyDerive(expander) => {
if !item.derive_allowed() {
return fragment_kind.dummy(span);
return ExpandResult::Ready(fragment_kind.dummy(span));
}
if let SyntaxExtensionKind::Derive(..) = ext {
self.gate_proc_macro_input(&item);
}
let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path };
let items = expander.expand(self.cx, span, &meta, item);
let items = match expander.expand(self.cx, span, &meta, item) {
ExpandResult::Ready(items) => items,
ExpandResult::Retry(item, explanation) => {
// Reassemble the original invocation for retrying.
return ExpandResult::Retry(
Invocation {
kind: InvocationKind::Derive { path: meta.path, item },
..invoc
},
explanation,
);
}
};
fragment_kind.expect_from_annotatables(items)
}
_ => unreachable!(),
},
InvocationKind::DeriveContainer { .. } => unreachable!(),
}
})
}
fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
@ -933,7 +991,7 @@ pub fn ensure_complete_parse<'a>(
struct InvocationCollector<'a, 'b> {
cx: &'a mut ExtCtxt<'b>,
cfg: StripUnconfigured<'a>,
invocations: Vec<Invocation>,
invocations: Vec<(Invocation, Option<InvocationRes>)>,
monotonic: bool,
}
@ -955,15 +1013,18 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
};
let expn_id = ExpnId::fresh(expn_data);
let vis = kind.placeholder_visibility();
self.invocations.push(Invocation {
kind,
fragment_kind,
expansion_data: ExpansionData {
id: expn_id,
depth: self.cx.current_expansion.depth + 1,
..self.cx.current_expansion.clone()
self.invocations.push((
Invocation {
kind,
fragment_kind,
expansion_data: ExpansionData {
id: expn_id,
depth: self.cx.current_expansion.depth + 1,
..self.cx.current_expansion.clone()
},
},
});
None,
));
placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis)
}

View file

@ -79,7 +79,7 @@ impl MultiItemModifier for ProcMacroDerive {
span: Span,
_meta_item: &ast::MetaItem,
item: Annotatable,
) -> Vec<Annotatable> {
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
let item = match item {
Annotatable::Arm(..)
| Annotatable::Field(..)
@ -99,7 +99,7 @@ impl MultiItemModifier for ProcMacroDerive {
"proc-macro derives may only be \
applied to a struct, enum, or union",
);
return Vec::new();
return ExpandResult::Ready(Vec::new());
}
};
match item.kind {
@ -110,7 +110,7 @@ impl MultiItemModifier for ProcMacroDerive {
"proc-macro derives may only be \
applied to a struct, enum, or union",
);
return Vec::new();
return ExpandResult::Ready(Vec::new());
}
}
@ -158,7 +158,7 @@ impl MultiItemModifier for ProcMacroDerive {
FatalError.raise();
}
items
ExpandResult::Ready(items)
}
}

View file

@ -85,19 +85,13 @@ impl AttributeGate {
/// A template that the attribute input must match.
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Default)]
pub struct AttributeTemplate {
pub word: bool,
pub list: Option<&'static str>,
pub name_value_str: Option<&'static str>,
}
impl AttributeTemplate {
pub fn only_word() -> Self {
Self { word: true, list: None, name_value_str: None }
}
}
/// A convenience macro for constructing attribute templates.
/// E.g., `template!(Word, List: "description")` means that the attribute
/// supports forms `#[attr]` and `#[attr(description)]`.

View file

@ -345,6 +345,42 @@ impl<'a> base::Resolver for Resolver<'a> {
fn add_derive_copy(&mut self, expn_id: ExpnId) {
self.containers_deriving_copy.insert(expn_id);
}
// The function that implements the resolution logic of `#[cfg_accessible(path)]`.
// Returns true if the path can certainly be resolved in one of three namespaces,
// returns false if the path certainly cannot be resolved in any of the three namespaces.
// Returns `Indeterminate` if we cannot give a certain answer yet.
fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate> {
let span = path.span;
let path = &Segment::from_path(path);
let parent_scope = self.invocation_parent_scopes[&expn_id];
let mut indeterminate = false;
for ns in [TypeNS, ValueNS, MacroNS].iter().copied() {
match self.resolve_path(path, Some(ns), &parent_scope, false, span, CrateLint::No) {
PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true),
PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => {
return Ok(true);
}
PathResult::Indeterminate => indeterminate = true,
// FIXME: `resolve_path` is not ready to report partially resolved paths
// correctly, so we just report an error if the path was reported as unresolved.
// This needs to be fixed for `cfg_accessible` to be useful.
PathResult::NonModule(..) | PathResult::Failed { .. } => {}
PathResult::Module(_) => panic!("unexpected path resolution"),
}
}
if indeterminate {
return Err(Indeterminate);
}
self.session
.struct_span_err(span, "not sure whether the path is accessible or not")
.span_note(span, "`cfg_accessible` is not fully implemented")
.emit();
Ok(false)
}
}
impl<'a> Resolver<'a> {

View file

@ -182,6 +182,7 @@ symbols! {
caller_location,
cdylib,
cfg,
cfg_accessible,
cfg_attr,
cfg_attr_multi,
cfg_doctest,

View file

@ -240,6 +240,7 @@
#![feature(atomic_mut_ptr)]
#![feature(box_syntax)]
#![feature(c_variadic)]
#![cfg_attr(not(bootstrap), feature(cfg_accessible))]
#![feature(cfg_target_has_atomic)]
#![feature(cfg_target_thread_local)]
#![feature(char_error_internals)]

View file

@ -53,6 +53,15 @@ pub use core::prelude::v1::{
PartialEq, PartialOrd, RustcDecodable, RustcEncodable,
};
#[cfg(not(bootstrap))]
#[unstable(
feature = "cfg_accessible",
issue = "64797",
reason = "`cfg_accessible` is not fully implemented"
)]
#[doc(hidden)]
pub use core::prelude::v1::cfg_accessible;
// The file so far is equivalent to src/libcore/prelude/v1.rs,
// and below to src/liballoc/prelude.rs.
// Those files are duplicated rather than using glob imports

View file

@ -0,0 +1,24 @@
#![feature(cfg_accessible)]
#[cfg_accessible] //~ ERROR malformed `cfg_accessible` attribute input
struct S1;
#[cfg_accessible = "value"] //~ ERROR malformed `cfg_accessible` attribute input
struct S2;
#[cfg_accessible()] //~ ERROR `cfg_accessible` path is not specified
struct S3;
#[cfg_accessible(std, core)] //~ ERROR multiple `cfg_accessible` paths are specified
struct S4;
#[cfg_accessible("std")] //~ ERROR `cfg_accessible` path cannot be a literal
struct S5;
#[cfg_accessible(std = "value")] //~ ERROR `cfg_accessible` path cannot accept arguments
struct S6;
#[cfg_accessible(std(value))] //~ ERROR `cfg_accessible` path cannot accept arguments
struct S7;
fn main() {}

View file

@ -0,0 +1,44 @@
error: malformed `cfg_accessible` attribute input
--> $DIR/cfg_accessible-input-validation.rs:3:1
|
LL | #[cfg_accessible]
| ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[cfg_accessible(path)]`
error: malformed `cfg_accessible` attribute input
--> $DIR/cfg_accessible-input-validation.rs:6:1
|
LL | #[cfg_accessible = "value"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[cfg_accessible(path)]`
error: `cfg_accessible` path is not specified
--> $DIR/cfg_accessible-input-validation.rs:9:1
|
LL | #[cfg_accessible()]
| ^^^^^^^^^^^^^^^^^^^
error: multiple `cfg_accessible` paths are specified
--> $DIR/cfg_accessible-input-validation.rs:12:23
|
LL | #[cfg_accessible(std, core)]
| ^^^^
error: `cfg_accessible` path cannot be a literal
--> $DIR/cfg_accessible-input-validation.rs:15:18
|
LL | #[cfg_accessible("std")]
| ^^^^^
error: `cfg_accessible` path cannot accept arguments
--> $DIR/cfg_accessible-input-validation.rs:18:18
|
LL | #[cfg_accessible(std = "value")]
| ^^^^^^^^^^^^^
error: `cfg_accessible` path cannot accept arguments
--> $DIR/cfg_accessible-input-validation.rs:21:18
|
LL | #[cfg_accessible(std(value))]
| ^^^^^^^^^^
error: aborting due to 7 previous errors

View file

@ -0,0 +1,9 @@
#![feature(cfg_accessible)]
#[cfg_accessible(Z)] //~ ERROR cannot determine whether the path is accessible or not
struct S;
#[cfg_accessible(S)] //~ ERROR cannot determine whether the path is accessible or not
struct Z;
fn main() {}

View file

@ -0,0 +1,14 @@
error: cannot determine whether the path is accessible or not
--> $DIR/cfg_accessible-stuck.rs:6:1
|
LL | #[cfg_accessible(S)]
| ^^^^^^^^^^^^^^^^^^^^
error: cannot determine whether the path is accessible or not
--> $DIR/cfg_accessible-stuck.rs:3:1
|
LL | #[cfg_accessible(Z)]
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View file

@ -0,0 +1,2 @@
#[cfg_accessible(std)] //~ ERROR use of unstable library feature 'cfg_accessible'
fn main() {}

View file

@ -0,0 +1,12 @@
error[E0658]: use of unstable library feature 'cfg_accessible': `cfg_accessible` is not fully implemented
--> $DIR/cfg_accessible-unstable.rs:1:3
|
LL | #[cfg_accessible(std)]
| ^^^^^^^^^^^^^^
|
= note: see issue #64797 <https://github.com/rust-lang/rust/issues/64797> for more information
= help: add `#![feature(cfg_accessible)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,43 @@
#![feature(cfg_accessible)]
mod m {
pub struct ExistingPublic;
struct ExistingPrivate;
}
#[cfg_accessible(m::ExistingPublic)]
struct ExistingPublic;
// FIXME: Not implemented yet.
#[cfg_accessible(m::ExistingPrivate)] //~ ERROR not sure whether the path is accessible or not
struct ExistingPrivate;
// FIXME: Not implemented yet.
#[cfg_accessible(m::NonExistent)] //~ ERROR not sure whether the path is accessible or not
struct ExistingPrivate;
#[cfg_accessible(n::AccessibleExpanded)] // OK, `cfg_accessible` can wait and retry.
struct AccessibleExpanded;
macro_rules! generate_accessible_expanded {
() => {
mod n {
pub struct AccessibleExpanded;
}
};
}
generate_accessible_expanded!();
struct S {
field: u8,
}
// FIXME: Not implemented yet.
#[cfg_accessible(S::field)] //~ ERROR not sure whether the path is accessible or not
struct Field;
fn main() {
ExistingPublic;
AccessibleExpanded;
}

View file

@ -0,0 +1,38 @@
error: not sure whether the path is accessible or not
--> $DIR/cfg_accessible.rs:12:18
|
LL | #[cfg_accessible(m::ExistingPrivate)]
| ^^^^^^^^^^^^^^^^^^
|
note: `cfg_accessible` is not fully implemented
--> $DIR/cfg_accessible.rs:12:18
|
LL | #[cfg_accessible(m::ExistingPrivate)]
| ^^^^^^^^^^^^^^^^^^
error: not sure whether the path is accessible or not
--> $DIR/cfg_accessible.rs:16:18
|
LL | #[cfg_accessible(m::NonExistent)]
| ^^^^^^^^^^^^^^
|
note: `cfg_accessible` is not fully implemented
--> $DIR/cfg_accessible.rs:16:18
|
LL | #[cfg_accessible(m::NonExistent)]
| ^^^^^^^^^^^^^^
error: not sure whether the path is accessible or not
--> $DIR/cfg_accessible.rs:37:18
|
LL | #[cfg_accessible(S::field)]
| ^^^^^^^^
|
note: `cfg_accessible` is not fully implemented
--> $DIR/cfg_accessible.rs:37:18
|
LL | #[cfg_accessible(S::field)]
| ^^^^^^^^
error: aborting due to 3 previous errors