From eafeb9a2676e16ed322e9e0695b5ce9407f5de8d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 30 Dec 2019 21:38:43 +0300 Subject: [PATCH 01/12] 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 8ef76a8657e..b486eadd1a8 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 f15e626c278..55e9c70d637 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 e9a5364c658..e0e38c2dba9 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/12] 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 5ba9d3800e1..b5ad67abf62 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 55e9c70d637..3782746a57d 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 effa89e8bfb..f2af6755517 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 84a546345bb..cb9afa4cd4f 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/12] 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 76e58f0cc62..3b615a5246c 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 66b5a90b77b..c91370b2719 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 00000000000..3607a4d0d15 --- /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 9a8b0a87cb7..26a59c6b1be 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 3782746a57d..4839651ac84 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 e11aec90669..4e41ea82c47 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 c39f9f360c0..55284e73efc 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 784868b52e5..9950a813255 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 7c0efe828c2..6712f5ba580 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 00000000000..c51c908a426 --- /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 00000000000..86706c76635 --- /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 00000000000..8bc93fa3243 --- /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 00000000000..9641441a819 --- /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 00000000000..e9247e67a2a --- /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 00000000000..2f55b9559c7 --- /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 00000000000..07b0be5b1ae --- /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 00000000000..167765cd66e --- /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 71ebc6182012d80e076e4aaa03e0dbe44132fcbf Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 7 Mar 2020 18:39:16 +0300 Subject: [PATCH 04/12] resolve: Simplify `fn report_privacy_error` by factoring out `fn ctor_fields_span` into a separate function --- src/librustc_resolve/diagnostics.rs | 67 +++++++++++++---------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 47a05ec90d4..edbb2db3868 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -916,51 +916,46 @@ impl<'a> Resolver<'a> { err.emit(); } - crate fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) { - let PrivacyError { ident, binding, .. } = *privacy_error; - let session = &self.session; - let mk_struct_span_error = |is_constructor| { - let mut descr = binding.res().descr().to_string(); - if is_constructor { - descr += " constructor"; - } - if binding.is_import() { - descr += " import"; - } - - let mut err = - struct_span_err!(session, ident.span, E0603, "{} `{}` is private", descr, ident); - - err.span_label(ident.span, &format!("this {} is private", descr)); - err.span_note( - session.source_map().def_span(binding.span), - &format!("the {} `{}` is defined here", descr, ident), - ); - - err - }; - - let mut err = if let NameBindingKind::Res( + /// If the binding refers to a tuple struct constructor with fields, + /// returns the span of its fields. + fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option { + if let NameBindingKind::Res( Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id), _, ) = binding.kind { let def_id = (&*self).parent(ctor_def_id).expect("no parent for a constructor"); if let Some(fields) = self.field_names.get(&def_id) { - let mut err = mk_struct_span_error(true); let first_field = fields.first().expect("empty field list in the map"); - err.span_label( - fields.iter().fold(first_field.span, |acc, field| acc.to(field.span)), - "a constructor is private if any of the fields is private", - ); - err - } else { - mk_struct_span_error(false) + return Some(fields.iter().fold(first_field.span, |acc, field| acc.to(field.span))); } - } else { - mk_struct_span_error(false) - }; + } + None + } + crate fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) { + let PrivacyError { ident, binding, .. } = *privacy_error; + + let ctor_fields_span = self.ctor_fields_span(binding); + let mut descr = binding.res().descr().to_string(); + if ctor_fields_span.is_some() { + descr += " constructor"; + } + if binding.is_import() { + descr += " import"; + } + + let mut err = + struct_span_err!(self.session, ident.span, E0603, "{} `{}` is private", descr, ident); + err.span_label(ident.span, &format!("this {} is private", descr)); + if let Some(span) = ctor_fields_span { + err.span_label(span, "a constructor is private if any of the fields is private"); + } + + err.span_note( + self.session.source_map().def_span(binding.span), + &format!("the {} `{}` is defined here", descr, ident), + ); err.emit(); } } From 580c6a29d47a9cd786c89df98d97e6de13f49291 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 7 Mar 2020 21:18:29 +0300 Subject: [PATCH 05/12] resolve: Print import chains on privacy errors --- src/librustc_resolve/diagnostics.rs | 59 +++++++++++++++---- src/test/ui/imports/issue-55884-2.stderr | 17 +++++- src/test/ui/imports/reexports.stderr | 14 ++++- src/test/ui/privacy/privacy2.stderr | 7 ++- .../shadowed/shadowed-use-visibility.stderr | 14 ++++- 5 files changed, 94 insertions(+), 17 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index edbb2db3868..063c62ad9aa 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1,4 +1,5 @@ use std::cmp::Reverse; +use std::ptr; use log::debug; use rustc::bug; @@ -936,15 +937,17 @@ impl<'a> Resolver<'a> { crate fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) { let PrivacyError { ident, binding, .. } = *privacy_error; + let res = binding.res(); let ctor_fields_span = self.ctor_fields_span(binding); - let mut descr = binding.res().descr().to_string(); - if ctor_fields_span.is_some() { - descr += " constructor"; - } - if binding.is_import() { - descr += " import"; - } + let plain_descr = res.descr().to_string(); + let nonimport_descr = + if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr }; + let import_descr = nonimport_descr.clone() + " import"; + let get_descr = + |b: &NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; + // Print the primary message. + let descr = get_descr(binding); let mut err = struct_span_err!(self.session, ident.span, E0603, "{} `{}` is private", descr, ident); err.span_label(ident.span, &format!("this {} is private", descr)); @@ -952,10 +955,44 @@ impl<'a> Resolver<'a> { err.span_label(span, "a constructor is private if any of the fields is private"); } - err.span_note( - self.session.source_map().def_span(binding.span), - &format!("the {} `{}` is defined here", descr, ident), - ); + // Print the whole import chain to make it easier to see what happens. + let first_binding = binding; + let mut next_binding = Some(binding); + let mut next_ident = ident; + while let Some(binding) = next_binding { + let name = next_ident; + next_binding = match binding.kind { + _ if res == Res::Err => None, + NameBindingKind::Import { binding, import, .. } => match import.kind { + _ if binding.span.is_dummy() => None, + ImportKind::Single { source, .. } => { + next_ident = source; + Some(binding) + } + ImportKind::Glob { .. } | ImportKind::MacroUse => Some(binding), + ImportKind::ExternCrate { .. } => None, + }, + _ => None, + }; + + let first = ptr::eq(binding, first_binding); + let descr = get_descr(binding); + let msg = format!( + "{and_refers_to}the {item} `{name}`{which} is defined here{dots}", + and_refers_to = if first { "" } else { "...and refers to " }, + item = descr, + name = name, + which = if first { "" } else { " which" }, + dots = if next_binding.is_some() { "..." } else { "" }, + ); + let def_span = self.session.source_map().def_span(binding.span); + let mut note_span = MultiSpan::from_span(def_span); + if !first && next_binding.is_none() && binding.vis == ty::Visibility::Public { + note_span.push_span_label(def_span, "consider importing it directly".into()); + } + err.span_note(note_span, &msg); + } + err.emit(); } } diff --git a/src/test/ui/imports/issue-55884-2.stderr b/src/test/ui/imports/issue-55884-2.stderr index f16d2adb365..3eee7118e5a 100644 --- a/src/test/ui/imports/issue-55884-2.stderr +++ b/src/test/ui/imports/issue-55884-2.stderr @@ -4,11 +4,26 @@ error[E0603]: struct import `ParseOptions` is private LL | pub use parser::ParseOptions; | ^^^^^^^^^^^^ this struct import is private | -note: the struct import `ParseOptions` is defined here +note: the struct import `ParseOptions` is defined here... --> $DIR/issue-55884-2.rs:9:9 | LL | use ParseOptions; | ^^^^^^^^^^^^ +note: ...and refers to the struct import `ParseOptions` which is defined here... + --> $DIR/issue-55884-2.rs:12:9 + | +LL | pub use parser::ParseOptions; + | ^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct import `ParseOptions` which is defined here... + --> $DIR/issue-55884-2.rs:6:13 + | +LL | pub use options::*; + | ^^^^^^^^^^ +note: ...and refers to the struct `ParseOptions` which is defined here + --> $DIR/issue-55884-2.rs:2:5 + | +LL | pub struct ParseOptions {} + | ^^^^^^^^^^^^^^^^^^^^^^^ consider importing it directly error: aborting due to previous error diff --git a/src/test/ui/imports/reexports.stderr b/src/test/ui/imports/reexports.stderr index 7b0d63574ec..d63fbc7ec67 100644 --- a/src/test/ui/imports/reexports.stderr +++ b/src/test/ui/imports/reexports.stderr @@ -16,11 +16,16 @@ error[E0603]: module import `foo` is private LL | use b::a::foo::S; | ^^^ this module import is private | -note: the module import `foo` is defined here +note: the module import `foo` is defined here... --> $DIR/reexports.rs:21:17 | LL | pub use super::foo; // This is OK since the value `foo` is visible enough. | ^^^^^^^^^^ +note: ...and refers to the module `foo` which is defined here + --> $DIR/reexports.rs:16:5 + | +LL | mod foo { + | ^^^^^^^ error[E0603]: module import `foo` is private --> $DIR/reexports.rs:34:15 @@ -28,11 +33,16 @@ error[E0603]: module import `foo` is private LL | use b::b::foo::S as T; | ^^^ this module import is private | -note: the module import `foo` is defined here +note: the module import `foo` is defined here... --> $DIR/reexports.rs:26:17 | LL | pub use super::*; // This is also OK since the value `foo` is visible enough. | ^^^^^^^^ +note: ...and refers to the module `foo` which is defined here + --> $DIR/reexports.rs:16:5 + | +LL | mod foo { + | ^^^^^^^ warning: glob import doesn't reexport anything because no candidate is public enough --> $DIR/reexports.rs:9:17 diff --git a/src/test/ui/privacy/privacy2.stderr b/src/test/ui/privacy/privacy2.stderr index 719dc27ccf4..b10c3a52659 100644 --- a/src/test/ui/privacy/privacy2.stderr +++ b/src/test/ui/privacy/privacy2.stderr @@ -10,11 +10,16 @@ error[E0603]: function import `foo` is private LL | use bar::glob::foo; | ^^^ this function import is private | -note: the function import `foo` is defined here +note: the function import `foo` is defined here... --> $DIR/privacy2.rs:10:13 | LL | use foo; | ^^^ +note: ...and refers to the function `foo` which is defined here + --> $DIR/privacy2.rs:14:1 + | +LL | pub fn foo() {} + | ^^^^^^^^^^^^ consider importing it directly error: requires `sized` lang_item diff --git a/src/test/ui/shadowed/shadowed-use-visibility.stderr b/src/test/ui/shadowed/shadowed-use-visibility.stderr index cd8ec13794c..2244f3a46b2 100644 --- a/src/test/ui/shadowed/shadowed-use-visibility.stderr +++ b/src/test/ui/shadowed/shadowed-use-visibility.stderr @@ -4,11 +4,16 @@ error[E0603]: module import `bar` is private LL | use foo::bar::f as g; | ^^^ this module import is private | -note: the module import `bar` is defined here +note: the module import `bar` is defined here... --> $DIR/shadowed-use-visibility.rs:4:9 | LL | use foo as bar; | ^^^^^^^^^^ +note: ...and refers to the module `foo` which is defined here + --> $DIR/shadowed-use-visibility.rs:1:1 + | +LL | mod foo { + | ^^^^^^^ error[E0603]: module import `f` is private --> $DIR/shadowed-use-visibility.rs:15:10 @@ -16,11 +21,16 @@ error[E0603]: module import `f` is private LL | use bar::f::f; | ^ this module import is private | -note: the module import `f` is defined here +note: the module import `f` is defined here... --> $DIR/shadowed-use-visibility.rs:11:9 | LL | use foo as f; | ^^^^^^^^ +note: ...and refers to the module `foo` which is defined here + --> $DIR/shadowed-use-visibility.rs:1:1 + | +LL | mod foo { + | ^^^^^^^ error: aborting due to 2 previous errors From f4083c6455ad47e0369013dba7eb716eb00223eb Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 11 Mar 2020 21:17:23 +0300 Subject: [PATCH 06/12] Add the "consider importing it directly" label to public imports as well --- src/librustc_resolve/diagnostics.rs | 2 +- src/test/ui/imports/issue-55884-2.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 063c62ad9aa..b00c7473bac 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -987,7 +987,7 @@ impl<'a> Resolver<'a> { ); let def_span = self.session.source_map().def_span(binding.span); let mut note_span = MultiSpan::from_span(def_span); - if !first && next_binding.is_none() && binding.vis == ty::Visibility::Public { + if !first && binding.vis == ty::Visibility::Public { note_span.push_span_label(def_span, "consider importing it directly".into()); } err.span_note(note_span, &msg); diff --git a/src/test/ui/imports/issue-55884-2.stderr b/src/test/ui/imports/issue-55884-2.stderr index 3eee7118e5a..490c08446b5 100644 --- a/src/test/ui/imports/issue-55884-2.stderr +++ b/src/test/ui/imports/issue-55884-2.stderr @@ -13,12 +13,12 @@ note: ...and refers to the struct import `ParseOptions` which is defined here... --> $DIR/issue-55884-2.rs:12:9 | LL | pub use parser::ParseOptions; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ consider importing it directly note: ...and refers to the struct import `ParseOptions` which is defined here... --> $DIR/issue-55884-2.rs:6:13 | LL | pub use options::*; - | ^^^^^^^^^^ + | ^^^^^^^^^^ consider importing it directly note: ...and refers to the struct `ParseOptions` which is defined here --> $DIR/issue-55884-2.rs:2:5 | From e80cb2032cac39db2226ba940fad05b5adb17e62 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 14 Mar 2020 15:28:17 +0300 Subject: [PATCH 07/12] 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 948b86225f3..02ac560093d 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 d4835c09224..4bd8efeaa3b 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 6c8ba48864d..82134224911 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 b07de3e341c..a46ce67d40d 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 05802f2d367..edbb36452b6 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 00000000000..1bcbef59437 --- /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 00000000000..f2efcbc8e85 --- /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 08/12] 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 86d93612e99..2896682ea82 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 00000000000..49d489d9168 --- /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 00000000000..d31ce9cfe0c --- /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 09/12] 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 e4b57cddfb8..602e4511ea5 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 504cba45570..be2b0f36d14 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 9a7d0d9aeba..36641284a76 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 9ebb3176418..a84f0caf0a0 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 a1dde1d51ef..5a731766054 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 4e43561996c..4f23620b92b 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 dbc54291f40..edeb4f83c7d 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 7b1beb1ecda..c1ca6771326 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 55416b6729a..4d9a91e38b3 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 10/12] 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 7509e1ee35d..77977e25517 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 11/12] 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 77977e25517..498950e6821 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 12/12] 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 144e3bc9c8b..b166c4dea0c 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 d0bbc5ac26d..2ac461a0eb2 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 80fa0c44860..aea4f5f1b3a 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 37ad5f5ea4e..486dd3579d2 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 030d0893b02..d7208a00e09 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