From eafeb9a2676e16ed322e9e0695b5ce9407f5de8d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 30 Dec 2019 21:38:43 +0300 Subject: [PATCH 01/10] expand/builtin_macros: Minor cleanup --- src/librustc_builtin_macros/util.rs | 2 +- src/librustc_expand/base.rs | 13 +++---------- src/librustc_feature/builtin_attrs.rs | 8 +------- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/librustc_builtin_macros/util.rs b/src/librustc_builtin_macros/util.rs index 8ef76a8657e1e..b486eadd1a8be 100644 --- a/src/librustc_builtin_macros/util.rs +++ b/src/librustc_builtin_macros/util.rs @@ -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); } diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index f15e626c2783b..55e9c70d63732 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -270,10 +270,9 @@ pub trait MultiItemModifier { ) -> Vec; } -impl MultiItemModifier for F +impl MultiItemModifier for F where - F: Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, Annotatable) -> T, - T: Into>, + F: Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, Annotatable) -> Vec, { fn expand( &self, @@ -282,13 +281,7 @@ where meta_item: &ast::MetaItem, item: Annotatable, ) -> Vec { - (*self)(ecx, span, meta_item, item).into() - } -} - -impl Into> for Annotatable { - fn into(self) -> Vec { - vec![self] + self(ecx, span, meta_item, item) } } diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs index e9a5364c65838..e0e38c2dba941 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -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)]`. From 552a8875bd5520c2e8c01ab05a12c304c730c5b9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 9 Mar 2020 20:50:12 +0300 Subject: [PATCH 02/10] expand: Implement support for retrying macro expansions --- src/librustc_builtin_macros/deriving/mod.rs | 6 +- src/librustc_expand/base.rs | 19 ++- src/librustc_expand/expand.rs | 145 ++++++++++++++------ src/librustc_expand/proc_macro.rs | 8 +- 4 files changed, 124 insertions(+), 54 deletions(-) diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/src/librustc_builtin_macros/deriving/mod.rs index 5ba9d3800e118..b5ad67abf6201 100644 --- a/src/librustc_builtin_macros/deriving/mod.rs +++ b/src/librustc_builtin_macros/deriving/mod.rs @@ -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 { + ) -> ExpandResult, 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) } } diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 55e9c70d63732..3782746a57de4 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -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 { + /// 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,7 +276,7 @@ pub trait MultiItemModifier { span: Span, meta_item: &ast::MetaItem, item: Annotatable, - ) -> Vec; + ) -> ExpandResult, Annotatable>; } impl MultiItemModifier for F @@ -280,8 +289,8 @@ where span: Span, meta_item: &ast::MetaItem, item: Annotatable, - ) -> Vec { - self(ecx, span, meta_item, item) + ) -> ExpandResult, Annotatable> { + ExpandResult::Ready(self(ecx, span, meta_item, item)) } } diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index effa89e8bfb21..f2af6755517f1 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -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) { + ) -> (AstFragment, Vec<(Invocation, Option)>) { // 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 { 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, + invocations: Vec<(Invocation, Option)>, 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) } diff --git a/src/librustc_expand/proc_macro.rs b/src/librustc_expand/proc_macro.rs index 84a546345bb28..cb9afa4cd4f02 100644 --- a/src/librustc_expand/proc_macro.rs +++ b/src/librustc_expand/proc_macro.rs @@ -79,7 +79,7 @@ impl MultiItemModifier for ProcMacroDerive { span: Span, _meta_item: &ast::MetaItem, item: Annotatable, - ) -> Vec { + ) -> ExpandResult, 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) } } From 2e6528961c44a4f3841fd319af71f1d1a6af029c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 10 Mar 2020 00:56:20 +0300 Subject: [PATCH 03/10] builtin_macros: Add attribute macro `#[cfg_accessible(path)]` --- src/libcore/macros/mod.rs | 12 +++++ src/libcore/prelude/v1.rs | 9 ++++ src/librustc_builtin_macros/cfg_accessible.rs | 54 +++++++++++++++++++ src/librustc_builtin_macros/lib.rs | 2 + src/librustc_expand/base.rs | 1 + src/librustc_resolve/macros.rs | 36 +++++++++++++ src/librustc_span/symbol.rs | 1 + src/libstd/lib.rs | 1 + src/libstd/prelude/v1.rs | 9 ++++ .../cfg_accessible-input-validation.rs | 24 +++++++++ .../cfg_accessible-input-validation.stderr | 44 +++++++++++++++ .../cfg_accessible-stuck.rs | 9 ++++ .../cfg_accessible-stuck.stderr | 14 +++++ .../cfg_accessible-unstable.rs | 2 + .../cfg_accessible-unstable.stderr | 12 +++++ .../conditional-compilation/cfg_accessible.rs | 43 +++++++++++++++ .../cfg_accessible.stderr | 38 +++++++++++++ 17 files changed, 311 insertions(+) create mode 100644 src/librustc_builtin_macros/cfg_accessible.rs create mode 100644 src/test/ui/conditional-compilation/cfg_accessible-input-validation.rs create mode 100644 src/test/ui/conditional-compilation/cfg_accessible-input-validation.stderr create mode 100644 src/test/ui/conditional-compilation/cfg_accessible-stuck.rs create mode 100644 src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr create mode 100644 src/test/ui/conditional-compilation/cfg_accessible-unstable.rs create mode 100644 src/test/ui/conditional-compilation/cfg_accessible-unstable.stderr create mode 100644 src/test/ui/conditional-compilation/cfg_accessible.rs create mode 100644 src/test/ui/conditional-compilation/cfg_accessible.stderr diff --git a/src/libcore/macros/mod.rs b/src/libcore/macros/mod.rs index 76e58f0cc62bc..3b615a5246c29 100644 --- a/src/libcore/macros/mod.rs +++ b/src/libcore/macros/mod.rs @@ -1383,6 +1383,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")] diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index 66b5a90b77b91..c91370b271992 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -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; diff --git a/src/librustc_builtin_macros/cfg_accessible.rs b/src/librustc_builtin_macros/cfg_accessible.rs new file mode 100644 index 0000000000000..3607a4d0d15b6 --- /dev/null +++ b/src/librustc_builtin_macros/cfg_accessible.rs @@ -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, 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()), + } + } +} diff --git a/src/librustc_builtin_macros/lib.rs b/src/librustc_builtin_macros/lib.rs index 9a8b0a87cb793..26a59c6b1bedb 100644 --- a/src/librustc_builtin_macros/lib.rs +++ b/src/librustc_builtin_macros/lib.rs @@ -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, diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 3782746a57de4..4839651ac844b 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -897,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; } #[derive(Clone)] diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index e11aec906693e..4e41ea82c47c9 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -339,6 +339,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 { + 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> { diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index c39f9f360c027..55284e73efcfa 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -181,6 +181,7 @@ symbols! { caller_location, cdylib, cfg, + cfg_accessible, cfg_attr, cfg_attr_multi, cfg_doctest, diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 784868b52e517..9950a8132555f 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -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)] diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index 7c0efe828c27a..6712f5ba5808c 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -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 diff --git a/src/test/ui/conditional-compilation/cfg_accessible-input-validation.rs b/src/test/ui/conditional-compilation/cfg_accessible-input-validation.rs new file mode 100644 index 0000000000000..c51c908a4262e --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-input-validation.rs @@ -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() {} diff --git a/src/test/ui/conditional-compilation/cfg_accessible-input-validation.stderr b/src/test/ui/conditional-compilation/cfg_accessible-input-validation.stderr new file mode 100644 index 0000000000000..86706c766356e --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-input-validation.stderr @@ -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 + diff --git a/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs b/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs new file mode 100644 index 0000000000000..8bc93fa324378 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs @@ -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() {} diff --git a/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr b/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr new file mode 100644 index 0000000000000..9641441a819b0 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr @@ -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 + diff --git a/src/test/ui/conditional-compilation/cfg_accessible-unstable.rs b/src/test/ui/conditional-compilation/cfg_accessible-unstable.rs new file mode 100644 index 0000000000000..e9247e67a2a26 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-unstable.rs @@ -0,0 +1,2 @@ +#[cfg_accessible(std)] //~ ERROR use of unstable library feature 'cfg_accessible' +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg_accessible-unstable.stderr b/src/test/ui/conditional-compilation/cfg_accessible-unstable.stderr new file mode 100644 index 0000000000000..2f55b9559c78f --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-unstable.stderr @@ -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 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`. diff --git a/src/test/ui/conditional-compilation/cfg_accessible.rs b/src/test/ui/conditional-compilation/cfg_accessible.rs new file mode 100644 index 0000000000000..07b0be5b1ae26 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible.rs @@ -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; +} diff --git a/src/test/ui/conditional-compilation/cfg_accessible.stderr b/src/test/ui/conditional-compilation/cfg_accessible.stderr new file mode 100644 index 0000000000000..167765cd66ee6 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible.stderr @@ -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 + From e80cb2032cac39db2226ba940fad05b5adb17e62 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 14 Mar 2020 15:28:17 +0300 Subject: [PATCH 04/10] resolve: Fix regression in resolution of raw keywords in paths --- src/librustc_resolve/lib.rs | 5 +---- src/test/rustdoc-ui/issue-61732.rs | 2 +- src/test/rustdoc-ui/issue-61732.stderr | 8 ++++---- .../keyword/extern/keyword-extern-as-identifier-use.rs | 1 + .../extern/keyword-extern-as-identifier-use.stderr | 9 ++++++++- src/test/ui/resolve/raw-ident-in-path.rs | 5 +++++ src/test/ui/resolve/raw-ident-in-path.stderr | 9 +++++++++ 7 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/resolve/raw-ident-in-path.rs create mode 100644 src/test/ui/resolve/raw-ident-in-path.stderr diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 948b86225f38b..02ac560093d04 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2183,11 +2183,8 @@ impl<'a> Resolver<'a> { Applicability::MaybeIncorrect, )), ) - } else if !ident.is_reserved() { - (format!("maybe a missing crate `{}`?", ident), None) } else { - // the parser will already have complained about the keyword being used - return PathResult::NonModule(PartialRes::new(Res::Err)); + (format!("maybe a missing crate `{}`?", ident), None) } } else if i == 0 { (format!("use of undeclared type or module `{}`", ident), None) diff --git a/src/test/rustdoc-ui/issue-61732.rs b/src/test/rustdoc-ui/issue-61732.rs index d4835c092248e..4bd8efeaa3b97 100644 --- a/src/test/rustdoc-ui/issue-61732.rs +++ b/src/test/rustdoc-ui/issue-61732.rs @@ -1,4 +1,4 @@ // This previously triggered an ICE. pub(in crate::r#mod) fn main() {} -//~^ ERROR expected module, found unresolved item +//~^ ERROR failed to resolve: maybe a missing crate `r#mod` diff --git a/src/test/rustdoc-ui/issue-61732.stderr b/src/test/rustdoc-ui/issue-61732.stderr index 6c8ba48864df0..8213422491120 100644 --- a/src/test/rustdoc-ui/issue-61732.stderr +++ b/src/test/rustdoc-ui/issue-61732.stderr @@ -1,11 +1,11 @@ -error[E0577]: expected module, found unresolved item `crate::r#mod` - --> $DIR/issue-61732.rs:3:8 +error[E0433]: failed to resolve: maybe a missing crate `r#mod`? + --> $DIR/issue-61732.rs:3:15 | LL | pub(in crate::r#mod) fn main() {} - | ^^^^^^^^^^^^ not a module + | ^^^^^ maybe a missing crate `r#mod`? error: Compilation failed, aborting rustdoc error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0577`. +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.rs b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.rs index b07de3e341c41..a46ce67d40d5a 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.rs +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.rs @@ -1,3 +1,4 @@ use extern::foo; //~ ERROR expected identifier, found keyword `extern` + //~| ERROR unresolved import `r#extern` fn main() {} diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr index 05802f2d36710..edbb36452b6ce 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr @@ -9,5 +9,12 @@ help: you can escape reserved keywords to use them as identifiers LL | use r#extern::foo; | ^^^^^^^^ -error: aborting due to previous error +error[E0432]: unresolved import `r#extern` + --> $DIR/keyword-extern-as-identifier-use.rs:1:5 + | +LL | use extern::foo; + | ^^^^^^ maybe a missing crate `r#extern`? + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/resolve/raw-ident-in-path.rs b/src/test/ui/resolve/raw-ident-in-path.rs new file mode 100644 index 0000000000000..1bcbef5943741 --- /dev/null +++ b/src/test/ui/resolve/raw-ident-in-path.rs @@ -0,0 +1,5 @@ +// Regression test for issue #63882. + +type A = crate::r#break; //~ ERROR cannot find type `r#break` in module `crate` + +fn main() {} diff --git a/src/test/ui/resolve/raw-ident-in-path.stderr b/src/test/ui/resolve/raw-ident-in-path.stderr new file mode 100644 index 0000000000000..f2efcbc8e8586 --- /dev/null +++ b/src/test/ui/resolve/raw-ident-in-path.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `r#break` in module `crate` + --> $DIR/raw-ident-in-path.rs:3:17 + | +LL | type A = crate::r#break; + | ^^^^^^^ not found in `crate` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. From 81099c27ddc856238d7b1b15c20d487130ef3057 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 10 Mar 2020 10:10:10 +0100 Subject: [PATCH 05/10] VariantSizeDifferences: bail on SizeOverflow --- src/librustc_lint/types.rs | 6 ++---- .../ui/lint/issue-69485-var-size-diffs-too-large.rs | 10 ++++++++++ .../lint/issue-69485-var-size-diffs-too-large.stderr | 8 ++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs create mode 100644 src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 86d93612e993b..2896682ea8268 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -998,10 +998,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { let ty = cx.tcx.erase_regions(&t); let layout = match cx.layout_of(ty) { Ok(layout) => layout, - Err(ty::layout::LayoutError::Unknown(_)) => return, - Err(err @ ty::layout::LayoutError::SizeOverflow(_)) => { - bug!("failed to get layout for `{}`: {}", t, err); - } + Err(ty::layout::LayoutError::Unknown(_)) + | Err(ty::layout::LayoutError::SizeOverflow(_)) => return, }; let (variants, tag) = match layout.variants { layout::Variants::Multiple { diff --git a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs new file mode 100644 index 0000000000000..49d489d916837 --- /dev/null +++ b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs @@ -0,0 +1,10 @@ +// build-fail +// only-x86_64 + +fn main() { + Bug::V([0; !0]); //~ ERROR is too big for the current +} + +enum Bug { + V([u8; !0]), +} diff --git a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr new file mode 100644 index 0000000000000..d31ce9cfe0c2b --- /dev/null +++ b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr @@ -0,0 +1,8 @@ +error: the type `[u8; 18446744073709551615]` is too big for the current architecture + --> $DIR/issue-69485-var-size-diffs-too-large.rs:5:12 + | +LL | Bug::V([0; !0]); + | ^^^^^^^ + +error: aborting due to previous error + From f53f9a88f16dc3d1b94ed2e7f0f201e1456d8cfc Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 15 Mar 2020 19:43:25 +0100 Subject: [PATCH 06/10] Bump the bootstrap compiler --- src/bootstrap/builder.rs | 10 ++---- src/bootstrap/channel.rs | 2 +- src/liballoc/boxed.rs | 24 ------------- src/libcore/cell.rs | 2 +- src/libcore/lib.rs | 2 +- src/libcore/ops/generator.rs | 31 ++--------------- src/librustc_data_structures/box_region.rs | 39 ---------------------- src/libstd/future.rs | 5 +-- src/stage0.txt | 2 +- 9 files changed, 9 insertions(+), 108 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index e4b57cddfb891..602e4511ea583 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -725,7 +725,7 @@ impl<'a> Builder<'a> { self.clear_if_dirty(&my_out, &rustdoc); } - cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd).arg("-Zconfig-profile"); + cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd); let profile_var = |name: &str| { let profile = if self.config.rust_optimize { "RELEASE" } else { "DEV" }; @@ -847,13 +847,7 @@ impl<'a> Builder<'a> { rustflags.arg("-Zforce-unstable-if-unmarked"); } - // cfg(bootstrap): the flag was renamed from `-Zexternal-macro-backtrace` - // to `-Zmacro-backtrace`, keep only the latter after beta promotion. - if stage == 0 { - rustflags.arg("-Zexternal-macro-backtrace"); - } else { - rustflags.arg("-Zmacro-backtrace"); - } + rustflags.arg("-Zmacro-backtrace"); let want_rustdoc = self.doc_tests != DocTests::No; diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 504cba45570c1..be2b0f36d14a7 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -13,7 +13,7 @@ use build_helper::output; use crate::Build; // The version number -pub const CFG_RELEASE_NUM: &str = "1.43.0"; +pub const CFG_RELEASE_NUM: &str = "1.44.0"; pub struct GitInfo { inner: Option, diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 9a7d0d9aebaaf..36641284a769b 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -1105,29 +1105,6 @@ impl AsMut for Box { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Box {} -#[cfg(bootstrap)] -#[unstable(feature = "generator_trait", issue = "43122")] -impl Generator for Box { - type Yield = G::Yield; - type Return = G::Return; - - fn resume(mut self: Pin<&mut Self>) -> GeneratorState { - G::resume(Pin::new(&mut *self)) - } -} - -#[cfg(bootstrap)] -#[unstable(feature = "generator_trait", issue = "43122")] -impl Generator for Pin> { - type Yield = G::Yield; - type Return = G::Return; - - fn resume(mut self: Pin<&mut Self>) -> GeneratorState { - G::resume((*self).as_mut()) - } -} - -#[cfg(not(bootstrap))] #[unstable(feature = "generator_trait", issue = "43122")] impl + Unpin, R> Generator for Box { type Yield = G::Yield; @@ -1138,7 +1115,6 @@ impl + Unpin, R> Generator for Box { } } -#[cfg(not(bootstrap))] #[unstable(feature = "generator_trait", issue = "43122")] impl, R> Generator for Pin> { type Yield = G::Yield; diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 9ebb317641875..a84f0caf0a0c3 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1538,7 +1538,7 @@ impl fmt::Display for RefMut<'_, T> { #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] -#[cfg_attr(not(bootstrap), repr(no_niche))] // rust-lang/rust#68303. +#[repr(no_niche)] // rust-lang/rust#68303. pub struct UnsafeCell { value: T, } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index a1dde1d51ef80..5a731766054bd 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -140,7 +140,7 @@ #![feature(associated_type_bounds)] #![feature(const_type_id)] #![feature(const_caller_location)] -#![cfg_attr(not(bootstrap), feature(no_niche))] // rust-lang/rust#68303 +#![feature(no_niche)] // rust-lang/rust#68303 #[prelude_import] #[allow(unused)] diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index 4e43561996c37..4f23620b92b80 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -67,7 +67,7 @@ pub enum GeneratorState { #[lang = "generator"] #[unstable(feature = "generator_trait", issue = "43122")] #[fundamental] -pub trait Generator<#[cfg(not(bootstrap))] R = ()> { +pub trait Generator { /// The type of value this generator yields. /// /// This associated type corresponds to the `yield` expression and the @@ -110,35 +110,9 @@ pub trait Generator<#[cfg(not(bootstrap))] R = ()> { /// been returned previously. While generator literals in the language are /// guaranteed to panic on resuming after `Complete`, this is not guaranteed /// for all implementations of the `Generator` trait. - fn resume( - self: Pin<&mut Self>, - #[cfg(not(bootstrap))] arg: R, - ) -> GeneratorState; + fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState; } -#[cfg(bootstrap)] -#[unstable(feature = "generator_trait", issue = "43122")] -impl Generator for Pin<&mut G> { - type Yield = G::Yield; - type Return = G::Return; - - fn resume(mut self: Pin<&mut Self>) -> GeneratorState { - G::resume((*self).as_mut()) - } -} - -#[cfg(bootstrap)] -#[unstable(feature = "generator_trait", issue = "43122")] -impl Generator for &mut G { - type Yield = G::Yield; - type Return = G::Return; - - fn resume(mut self: Pin<&mut Self>) -> GeneratorState { - G::resume(Pin::new(&mut *self)) - } -} - -#[cfg(not(bootstrap))] #[unstable(feature = "generator_trait", issue = "43122")] impl, R> Generator for Pin<&mut G> { type Yield = G::Yield; @@ -149,7 +123,6 @@ impl, R> Generator for Pin<&mut G> { } } -#[cfg(not(bootstrap))] #[unstable(feature = "generator_trait", issue = "43122")] impl + Unpin, R> Generator for &mut G { type Yield = G::Yield; diff --git a/src/librustc_data_structures/box_region.rs b/src/librustc_data_structures/box_region.rs index dbc54291f4087..edeb4f83c7d7e 100644 --- a/src/librustc_data_structures/box_region.rs +++ b/src/librustc_data_structures/box_region.rs @@ -25,22 +25,6 @@ pub struct PinnedGenerator { } impl PinnedGenerator { - #[cfg(bootstrap)] - pub fn new, Return = R> + 'static>( - generator: T, - ) -> (I, Self) { - let mut result = PinnedGenerator { generator: Box::pin(generator) }; - - // Run it to the first yield to set it up - let init = match Pin::new(&mut result.generator).resume() { - GeneratorState::Yielded(YieldType::Initial(y)) => y, - _ => panic!(), - }; - - (init, result) - } - - #[cfg(not(bootstrap))] pub fn new, Return = R> + 'static>( generator: T, ) -> (I, Self) { @@ -55,19 +39,6 @@ impl PinnedGenerator { (init, result) } - #[cfg(bootstrap)] - pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) { - BOX_REGION_ARG.with(|i| { - i.set(Action::Access(AccessAction(closure))); - }); - - // Call the generator, which in turn will call the closure in BOX_REGION_ARG - if let GeneratorState::Complete(_) = Pin::new(&mut self.generator).resume() { - panic!() - } - } - - #[cfg(not(bootstrap))] pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) { BOX_REGION_ARG.with(|i| { i.set(Action::Access(AccessAction(closure))); @@ -79,16 +50,6 @@ impl PinnedGenerator { } } - #[cfg(bootstrap)] - pub fn complete(&mut self) -> R { - // Tell the generator we want it to complete, consuming it and yielding a result - BOX_REGION_ARG.with(|i| i.set(Action::Complete)); - - let result = Pin::new(&mut self.generator).resume(); - if let GeneratorState::Complete(r) = result { r } else { panic!() } - } - - #[cfg(not(bootstrap))] pub fn complete(&mut self) -> R { // Tell the generator we want it to complete, consuming it and yielding a result BOX_REGION_ARG.with(|i| i.set(Action::Complete)); diff --git a/src/libstd/future.rs b/src/libstd/future.rs index 7b1beb1ecda80..c1ca6771326cb 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -41,10 +41,7 @@ impl> Future for GenFuture { // Safe because we're !Unpin + !Drop mapping to a ?Unpin value let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; let _guard = unsafe { set_task_context(cx) }; - match gen.resume( - #[cfg(not(bootstrap))] - (), - ) { + match gen.resume(()) { GeneratorState::Yielded(()) => Poll::Pending, GeneratorState::Complete(x) => Poll::Ready(x), } diff --git a/src/stage0.txt b/src/stage0.txt index 55416b6729adb..4d9a91e38b33c 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2020-02-29 +date: 2020-03-12 rustc: beta cargo: beta From ce5e49f86fc8bff241695f8a62e77f517749bd6d Mon Sep 17 00:00:00 2001 From: lzutao Date: Mon, 16 Mar 2020 23:43:42 +0700 Subject: [PATCH 07/10] Use sublice patterns to avoid computing the len --- src/libstd/sys_common/wtf8.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 7509e1ee35dee..77977e255172a 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -599,24 +599,16 @@ impl Wtf8 { #[inline] fn final_lead_surrogate(&self) -> Option { - let len = self.len(); - if len < 3 { - return None; - } - match self.bytes[(len - 3)..] { - [0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), + match self.bytes { + [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(*b2, *b3)), _ => None, } } #[inline] fn initial_trail_surrogate(&self) -> Option { - let len = self.len(); - if len < 3 { - return None; - } - match self.bytes[..3] { - [0xED, b2 @ 0xB0..=0xBF, b3] => Some(decode_surrogate(b2, b3)), + match self.bytes { + [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(*b2, *b3)), _ => None, } } From e1bc9af9eb503e7ca0027b4d7086c35cd661140e Mon Sep 17 00:00:00 2001 From: lzutao Date: Mon, 16 Mar 2020 23:54:32 +0700 Subject: [PATCH 08/10] Fix wrong deref --- src/libstd/sys_common/wtf8.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 77977e255172a..498950e682101 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -600,7 +600,7 @@ impl Wtf8 { #[inline] fn final_lead_surrogate(&self) -> Option { match self.bytes { - [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(*b2, *b3)), + [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), _ => None, } } @@ -608,7 +608,7 @@ impl Wtf8 { #[inline] fn initial_trail_surrogate(&self) -> Option { match self.bytes { - [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(*b2, *b3)), + [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(b2, b3)), _ => None, } } From 7894509b000157185b10cfae64ac1e88acd88f4a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 16 Mar 2020 18:51:55 +0100 Subject: [PATCH 09/10] Fiddle `ParamEnv` through to a place that used to use `ParamEnv::empty` in a buggy manner --- src/librustc/ty/inhabitedness/mod.rs | 49 +++++++++++++------ src/librustc_lint/unused.rs | 7 ++- .../build/matches/simplify.rs | 7 ++- src/librustc_mir_build/hair/pattern/_match.rs | 4 +- src/librustc_passes/liveness.rs | 21 ++++++-- 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 144e3bc9c8bc6..b166c4dea0c85 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -90,30 +90,46 @@ impl<'tcx> TyCtxt<'tcx> { /// ``` /// This code should only compile in modules where the uninhabitedness of Foo is /// visible. - pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool { + pub fn is_ty_uninhabited_from( + self, + module: DefId, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> bool { // To check whether this type is uninhabited at all (not just from the // given node), you could check whether the forest is empty. // ``` // forest.is_empty() // ``` - ty.uninhabited_from(self).contains(self, module) + ty.uninhabited_from(self, param_env).contains(self, module) } - pub fn is_ty_uninhabited_from_any_module(self, ty: Ty<'tcx>) -> bool { - !ty.uninhabited_from(self).is_empty() + pub fn is_ty_uninhabited_from_any_module( + self, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> bool { + !ty.uninhabited_from(self, param_env).is_empty() } } impl<'tcx> AdtDef { /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited. - fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>) -> DefIdForest { + fn uninhabited_from( + &self, + tcx: TyCtxt<'tcx>, + substs: SubstsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> DefIdForest { // Non-exhaustive ADTs from other crates are always considered inhabited. if self.is_variant_list_non_exhaustive() && !self.did.is_local() { DefIdForest::empty() } else { DefIdForest::intersection( tcx, - self.variants.iter().map(|v| v.uninhabited_from(tcx, substs, self.adt_kind())), + self.variants + .iter() + .map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)), ) } } @@ -126,6 +142,7 @@ impl<'tcx> VariantDef { tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, adt_kind: AdtKind, + param_env: ty::ParamEnv<'tcx>, ) -> DefIdForest { let is_enum = match adt_kind { // For now, `union`s are never considered uninhabited. @@ -140,7 +157,7 @@ impl<'tcx> VariantDef { } else { DefIdForest::union( tcx, - self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum)), + self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum, param_env)), ) } } @@ -153,8 +170,9 @@ impl<'tcx> FieldDef { tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, is_enum: bool, + param_env: ty::ParamEnv<'tcx>, ) -> DefIdForest { - let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx); + let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env); // FIXME(canndrew): Currently enum fields are (incorrectly) stored with // `Visibility::Invisible` so we need to override `self.vis` if we're // dealing with an enum. @@ -176,20 +194,21 @@ impl<'tcx> FieldDef { impl<'tcx> TyS<'tcx> { /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. - fn uninhabited_from(&self, tcx: TyCtxt<'tcx>) -> DefIdForest { + fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest { match self.kind { - Adt(def, substs) => def.uninhabited_from(tcx, substs), + Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env), Never => DefIdForest::full(tcx), - Tuple(ref tys) => { - DefIdForest::union(tcx, tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx))) - } + Tuple(ref tys) => DefIdForest::union( + tcx, + tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)), + ), - Array(ty, len) => match len.try_eval_usize(tcx, ty::ParamEnv::empty()) { + Array(ty, len) => match len.try_eval_usize(tcx, param_env) { // If the array is definitely non-empty, it's uninhabited if // the type of its elements is uninhabited. - Some(n) if n != 0 => ty.uninhabited_from(tcx), + Some(n) if n != 0 => ty.uninhabited_from(tcx, param_env), _ => DefIdForest::empty(), }, diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index d0bbc5ac26d89..2ac461a0eb264 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -124,7 +124,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { descr_post: &str, plural_len: usize, ) -> bool { - if ty.is_unit() || cx.tcx.is_ty_uninhabited_from(cx.tcx.parent_module(expr.hir_id), ty) + if ty.is_unit() + || cx.tcx.is_ty_uninhabited_from( + cx.tcx.parent_module(expr.hir_id), + ty, + cx.param_env, + ) { return true; } diff --git a/src/librustc_mir_build/build/matches/simplify.rs b/src/librustc_mir_build/build/matches/simplify.rs index 80fa0c44860e4..aea4f5f1b3ac9 100644 --- a/src/librustc_mir_build/build/matches/simplify.rs +++ b/src/librustc_mir_build/build/matches/simplify.rs @@ -209,7 +209,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { i == variant_index || { self.hir.tcx().features().exhaustive_patterns && !v - .uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind()) + .uninhabited_from( + self.hir.tcx(), + substs, + adt_def.adt_kind(), + self.hir.param_env, + ) .is_empty() } }) && (adt_def.did.is_local() diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 37ad5f5ea4e38..486dd3579d293 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -598,7 +598,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { if self.tcx.features().exhaustive_patterns { - self.tcx.is_ty_uninhabited_from(self.module, ty) + self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env) } else { false } @@ -1267,7 +1267,7 @@ fn all_constructors<'a, 'tcx>( def.variants .iter() .filter(|v| { - !v.uninhabited_from(cx.tcx, substs, def.adt_kind()) + !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env) .contains(cx.tcx, cx.module) }) .map(|v| Variant(v.def_id)) diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 030d0893b0274..d7208a00e0938 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -398,7 +398,7 @@ fn visit_fn<'tcx>( intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id); // compute liveness - let mut lsets = Liveness::new(&mut fn_maps, body_id); + let mut lsets = Liveness::new(&mut fn_maps, def_id); let entry_ln = lsets.compute(&body.value); // check for various error conditions @@ -658,6 +658,7 @@ const ACC_USE: u32 = 4; struct Liveness<'a, 'tcx> { ir: &'a mut IrMaps<'tcx>, tables: &'a ty::TypeckTables<'tcx>, + param_env: ty::ParamEnv<'tcx>, s: Specials, successors: Vec, rwu_table: RWUTable, @@ -670,7 +671,7 @@ struct Liveness<'a, 'tcx> { } impl<'a, 'tcx> Liveness<'a, 'tcx> { - fn new(ir: &'a mut IrMaps<'tcx>, body: hir::BodyId) -> Liveness<'a, 'tcx> { + fn new(ir: &'a mut IrMaps<'tcx>, def_id: DefId) -> Liveness<'a, 'tcx> { // Special nodes and variables: // - exit_ln represents the end of the fn, either by return or panic // - implicit_ret_var is a pseudo-variable that represents @@ -681,7 +682,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { clean_exit_var: ir.add_variable(CleanExit), }; - let tables = ir.tcx.body_tables(body); + let tables = ir.tcx.typeck_tables_of(def_id); + let param_env = ir.tcx.param_env(def_id); let num_live_nodes = ir.num_live_nodes; let num_vars = ir.num_vars; @@ -689,6 +691,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { Liveness { ir, tables, + param_env, s: specials, successors: vec![invalid_node(); num_live_nodes], rwu_table: RWUTable::new(num_live_nodes * num_vars), @@ -1126,7 +1129,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::Call(ref f, ref args) => { let m = self.ir.tcx.parent_module(expr.hir_id); - let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) { + let succ = if self.ir.tcx.is_ty_uninhabited_from( + m, + self.tables.expr_ty(expr), + self.param_env, + ) { self.s.exit_ln } else { succ @@ -1137,7 +1144,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::MethodCall(.., ref args) => { let m = self.ir.tcx.parent_module(expr.hir_id); - let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) { + let succ = if self.ir.tcx.is_ty_uninhabited_from( + m, + self.tables.expr_ty(expr), + self.param_env, + ) { self.s.exit_ln } else { succ From 6207e8dcba8c8859294c8398fef1210dec3df886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 16 Mar 2020 19:17:40 +0100 Subject: [PATCH 10/10] Allow `hir().find` to return `None` --- src/librustc/hir/map/mod.rs | 25 ++++++++++++++++--------- src/librustc/hir/mod.rs | 7 +++---- src/librustc/query/mod.rs | 4 ++-- src/test/ui/issues/issue-70041.rs | 10 ++++++++++ 4 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/issues/issue-70041.rs diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index bcbb6f3ec31e6..1560831266400 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -341,20 +341,25 @@ impl<'hir> Map<'hir> { } fn find_entry(&self, id: HirId) -> Option> { - Some(self.get_entry(id)) - } - - fn get_entry(&self, id: HirId) -> Entry<'hir> { if id.local_id == ItemLocalId::from_u32_const(0) { let owner = self.tcx.hir_owner(id.owner_def_id()); - Entry { parent: owner.parent, node: owner.node } + owner.map(|owner| Entry { parent: owner.parent, node: owner.node }) } else { let owner = self.tcx.hir_owner_items(id.owner_def_id()); - let item = owner.items[id.local_id].as_ref().unwrap(); - Entry { parent: HirId { owner: id.owner, local_id: item.parent }, node: item.node } + owner.and_then(|owner| { + let item = owner.items[id.local_id].as_ref(); + item.map(|item| Entry { + parent: HirId { owner: id.owner, local_id: item.parent }, + node: item.node, + }) + }) } } + fn get_entry(&self, id: HirId) -> Entry<'hir> { + self.find_entry(id).unwrap() + } + pub fn item(&self, id: HirId) -> &'hir Item<'hir> { match self.find(id).unwrap() { Node::Item(item) => item, @@ -379,6 +384,7 @@ impl<'hir> Map<'hir> { pub fn body(&self, id: BodyId) -> &'hir Body<'hir> { self.tcx .hir_owner_items(DefId::local(id.hir_id.owner)) + .unwrap() .bodies .get(&id.hir_id.local_id) .unwrap() @@ -540,8 +546,9 @@ impl<'hir> Map<'hir> { /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. pub fn find(&self, hir_id: HirId) -> Option> { - let node = self.get_entry(hir_id).node; - if let Node::Crate(..) = node { None } else { Some(node) } + self.find_entry(hir_id).and_then(|entry| { + if let Node::Crate(..) = entry.node { None } else { Some(entry.node) } + }) } /// Similar to `get_parent`; returns the parent HIR Id, or just `hir_id` if there diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 3b69fc8d8f2ac..9fdcaadde4f85 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -78,9 +78,8 @@ pub fn provide(providers: &mut Providers<'_>) { let module = hir.as_local_hir_id(id).unwrap(); &tcx.untracked_crate.modules[&module] }; - providers.hir_owner = |tcx, id| tcx.index_hir(id.krate).map[id.index].signature.unwrap(); - providers.hir_owner_items = |tcx, id| { - tcx.index_hir(id.krate).map[id.index].with_bodies.as_ref().map(|items| &**items).unwrap() - }; + providers.hir_owner = |tcx, id| tcx.index_hir(id.krate).map[id.index].signature; + providers.hir_owner_items = + |tcx, id| tcx.index_hir(id.krate).map[id.index].with_bodies.as_ref().map(|items| &**items); map::provide(providers); } diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index ff3a82e53639e..19a9f6b2d5ac0 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -74,7 +74,7 @@ rustc_queries! { // a `DefId`. // This can be conveniently accessed by methods on `tcx.hir()`. // Avoid calling this query directly. - query hir_owner(key: DefId) -> &'tcx HirOwner<'tcx> { + query hir_owner(key: DefId) -> Option<&'tcx HirOwner<'tcx>> { eval_always } @@ -82,7 +82,7 @@ rustc_queries! { // with a `DefId`. // This can be conveniently accessed by methods on `tcx.hir()`. // Avoid calling this query directly. - query hir_owner_items(key: DefId) -> &'tcx HirOwnerItems<'tcx> { + query hir_owner_items(key: DefId) -> Option<&'tcx HirOwnerItems<'tcx>> { eval_always } diff --git a/src/test/ui/issues/issue-70041.rs b/src/test/ui/issues/issue-70041.rs new file mode 100644 index 0000000000000..320baab882ffb --- /dev/null +++ b/src/test/ui/issues/issue-70041.rs @@ -0,0 +1,10 @@ +// compile-flags: --edition=2018 + +macro_rules! regex { + () => {}; +} + +#[allow(dead_code)] +use regex; + +fn main() {}