From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 10:07:07 +0000 (+0100) Subject: Rollup merge of #66941 - CAD97:nord, r=Dylan-DPC X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=1303bf2f3cc7f8a60c9b09895e8b0c0fc8f54f75;hp=ac57e1b64711dfdc3bd2987636ecc021707df283;p=rust.git Rollup merge of #66941 - CAD97:nord, r=Dylan-DPC Remove `ord` lang item At this point it seems to be unused, and just `partial_ord` is used instead. This removes the unused lang item. --- diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 730e8cf05d4..bb169414886 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -643,7 +643,9 @@ class RustBuild(object): env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ (os.pathsep + env["LIBRARY_PATH"]) \ if "LIBRARY_PATH" in env else "" - env["RUSTFLAGS"] = "-Cdebuginfo=2 " + # preserve existing RUSTFLAGS + env.setdefault("RUSTFLAGS", "") + env["RUSTFLAGS"] += " -Cdebuginfo=2" build_section = "target.{}".format(self.build_triple()) target_features = [] @@ -652,13 +654,13 @@ class RustBuild(object): elif self.get_toml("crt-static", build_section) == "false": target_features += ["-crt-static"] if target_features: - env["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features)) + " " + env["RUSTFLAGS"] += " -C target-feature=" + (",".join(target_features)) target_linker = self.get_toml("linker", build_section) if target_linker is not None: - env["RUSTFLAGS"] += "-C linker=" + target_linker + " " - env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes " + env["RUSTFLAGS"] += " -C linker=" + target_linker + env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes" if self.get_toml("deny-warnings", "rust") != "false": - env["RUSTFLAGS"] += "-Dwarnings " + env["RUSTFLAGS"] += " -Dwarnings" env["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 384219c38fd..f8734ebdf42 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -260,7 +260,7 @@ fn run($sel, $builder: &Builder<'_>) { }; Rustc, "src/librustc", true, only_hosts: true, { builder.ensure(dist::Rustc { - compiler: self.compiler, + compiler: builder.compiler(builder.top_stage, self.target), }); install_rustc(builder, self.compiler.stage, self.target); }; diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md index 77642a850fa..386f6008d06 100644 --- a/src/doc/rustc/src/lints/listing/warn-by-default.md +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -307,18 +307,6 @@ warning: path statement with no effect | ``` -## plugin-as-library - -This lint detects when compiler plugins are used as ordinary library in -non-plugin crate. Some example code that triggers this lint: - -```rust,ignore -#![feature(plugin)] -#![plugin(macro_crate_test)] - -extern crate macro_crate_test; -``` - ## private-in-public This lint detects private items in public interfaces not caught by the old implementation. Some diff --git a/src/doc/unstable-book/src/language-features/cfg-sanitize.md b/src/doc/unstable-book/src/language-features/cfg-sanitize.md new file mode 100644 index 00000000000..949f24ab9c1 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cfg-sanitize.md @@ -0,0 +1,36 @@ +# `cfg_sanitize` + +The tracking issue for this feature is: [#39699] + +[#39699]: https://github.com/rust-lang/rust/issues/39699 + +------------------------ + +The `cfg_sanitize` feature makes it possible to execute different code +depending on whether a particular sanitizer is enabled or not. + +## Examples + +``` rust +#![feature(cfg_sanitize)] + +#[cfg(sanitize = "thread")] +fn a() { + // ... +} + +#[cfg(not(sanitize = "thread"))] +fn a() { + // ... +} + +fn b() { + if cfg!(sanitize = "leak") { + // ... + } else { + // ... + } +} + +``` + diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md index cd1137e762e..495cdee62c8 100644 --- a/src/doc/unstable-book/src/language-features/plugin.md +++ b/src/doc/unstable-book/src/language-features/plugin.md @@ -21,15 +21,10 @@ the crate attribute `#![plugin(...)]`. See the `rustc_driver::plugin` documentation for more about the mechanics of defining and loading a plugin. -If present, arguments passed as `#![plugin(foo(... args ...))]` are not -interpreted by rustc itself. They are provided to the plugin through the -`Registry`'s `args` method. - In the vast majority of cases, a plugin should *only* be used through `#![plugin]` and not through an `extern crate` item. Linking a plugin would pull in all of libsyntax and librustc as dependencies of your crate. This is -generally unwanted unless you are building another plugin. The -`plugin_as_library` lint checks these guidelines. +generally unwanted unless you are building another plugin. The usual practice is to put compiler plugins in their own crate, separate from any `macro_rules!` macros or ordinary Rust code meant to be used by consumers diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index ec08965674a..2254cde7f49 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -926,7 +926,7 @@ unsafe fn allocate_for_layout( // reference (see #54908). let layout = Layout::new::>() .extend(value_layout).unwrap().0 - .pad_to_align().unwrap(); + .pad_to_align(); // Allocate for the layout. let mem = Global.alloc(layout) diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 0deb321d623..7bf2ff13615 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -780,7 +780,7 @@ unsafe fn allocate_for_layout( // reference (see #54908). let layout = Layout::new::>() .extend(value_layout).unwrap().0 - .pad_to_align().unwrap(); + .pad_to_align(); let mem = Global.alloc(layout) .unwrap_or_else(|_| handle_alloc_error(layout)); diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 1b06baeb711..4798769823f 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -213,18 +213,19 @@ pub fn padding_needed_for(&self, align: usize) -> usize { /// Creates a layout by rounding the size of this layout up to a multiple /// of the layout's alignment. /// - /// Returns `Err` if the padded size would overflow. - /// /// This is equivalent to adding the result of `padding_needed_for` /// to the layout's current size. #[unstable(feature = "alloc_layout_extra", issue = "55724")] #[inline] - pub fn pad_to_align(&self) -> Result { + pub fn pad_to_align(&self) -> Layout { let pad = self.padding_needed_for(self.align()); - let new_size = self.size().checked_add(pad) - .ok_or(LayoutErr { private: () })?; + // This cannot overflow. Quoting from the invariant of Layout: + // > `size`, when rounded up to the nearest multiple of `align`, + // > must not overflow (i.e., the rounded value must be less than + // > `usize::MAX`) + let new_size = self.size() + pad; - Layout::from_size_align(new_size, self.align()) + Layout::from_size_align(new_size, self.align()).unwrap() } /// Creates a layout describing the record for `n` instances of diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index e3dc5630c94..d4952f53bf7 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1348,9 +1348,11 @@ pub fn volatile_copy_nonoverlapping_memory(dst: *mut T, src: *const T, pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; /// Internal hook used by Miri to implement unwinding. + /// Compiles to a NOP during non-Miri codegen. + /// /// Perma-unstable: do not use #[cfg(not(bootstrap))] - pub fn miri_start_panic(data: *mut (dyn crate::any::Any + crate::marker::Send)) -> !; + pub fn miri_start_panic(data: *mut (dyn crate::any::Any + crate::marker::Send)) -> (); } // Some functions are defined here because they accidentally got made diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index 4f4652084a8..a748ee87ef9 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -5,19 +5,20 @@ /// extracting those success or failure values from an existing instance and /// creating a new instance from a success or failure value. #[unstable(feature = "try_trait", issue = "42327")] -#[rustc_on_unimplemented( +#[cfg_attr(not(bootstrap), rustc_on_unimplemented( on(all( any(from_method="from_error", from_method="from_ok"), from_desugaring="QuestionMark"), message="the `?` operator can only be used in {ItemContext} \ that returns `Result` or `Option` \ (or another type that implements `{Try}`)", -label="cannot use the `?` operator in {ItemContext} that returns `{Self}`"), +label="cannot use the `?` operator in {ItemContext} that returns `{Self}`", +enclosing_scope="this function should return `Result` or `Option` to accept `?`"), on(all(from_method="into_result", from_desugaring="QuestionMark"), message="the `?` operator can only be applied to values \ that implement `{Try}`", label="the `?` operator cannot be applied to type `{Self}`") -)] +))] #[doc(alias = "?")] pub trait Try { /// The type of this value when viewed as successful. diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 0c834e5c2a0..3a14197c77b 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -36,10 +36,7 @@ use core::panic::BoxMeUp; cfg_if::cfg_if! { - if #[cfg(miri)] { - #[path = "miri.rs"] - mod imp; - } else if #[cfg(target_os = "emscripten")] { + if #[cfg(target_os = "emscripten")] { #[path = "emcc.rs"] mod imp; } else if #[cfg(target_arch = "wasm32")] { @@ -94,5 +91,14 @@ #[unwind(allowed)] pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 { let payload = payload as *mut &mut dyn BoxMeUp; - imp::panic(Box::from_raw((*payload).take_box())) + let payload = (*payload).take_box(); + + // Miri panic support: cfg'd out of normal builds just to be sure. + // When going through normal codegen, `miri_start_panic` is a NOP, so the + // Miri-enabled sysroot still supports normal unwinding. But when executed in + // Miri, this line initiates unwinding. + #[cfg(miri)] + core::intrinsics::miri_start_panic(payload); + + imp::panic(Box::from_raw(payload)) } diff --git a/src/libpanic_unwind/miri.rs b/src/libpanic_unwind/miri.rs deleted file mode 100644 index f26c42fd4bc..00000000000 --- a/src/libpanic_unwind/miri.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![allow(nonstandard_style)] - -use core::any::Any; -use alloc::boxed::Box; - -pub fn payload() -> *mut u8 { - core::ptr::null_mut() -} - -pub unsafe fn panic(data: Box) -> ! { - core::intrinsics::miri_start_panic(Box::into_raw(data)) -} - -pub unsafe fn cleanup(ptr: *mut u8) -> Box { - Box::from_raw(ptr) -} - -// This is required by the compiler to exist (e.g., it's a lang item), -// but is never used by Miri. Therefore, we just use a stub here -#[lang = "eh_personality"] -#[cfg(not(test))] -fn rust_eh_personality() { - unsafe { core::intrinsics::abort() } -} - -// The rest is required on *some* targets to exist (specifically, MSVC targets that use SEH). -// We just add it on all targets. Copied from `seh.rs`. -#[repr(C)] -pub struct _TypeDescriptor { - pub pVFTable: *const u8, - pub spare: *mut u8, - pub name: [u8; 11], -} - -const TYPE_NAME: [u8; 11] = *b"rust_panic\0"; - -#[cfg_attr(not(test), lang = "eh_catch_typeinfo")] -static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor { - pVFTable: core::ptr::null(), - spare: core::ptr::null_mut(), - name: TYPE_NAME, -}; diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index 1d6a3420ed9..364a35f1b6f 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -23,17 +23,17 @@ macro_rules! arena_types { [] generics: rustc::ty::Generics, [] trait_def: rustc::ty::TraitDef, [] adt_def: rustc::ty::AdtDef, - [] steal_mir: rustc::ty::steal::Steal>, - [] mir: rustc::mir::Body<$tcx>, + [] steal_mir: rustc::ty::steal::Steal>, + [] mir: rustc::mir::BodyCache<$tcx>, [] steal_promoted: rustc::ty::steal::Steal< rustc_index::vec::IndexVec< rustc::mir::Promoted, - rustc::mir::Body<$tcx> + rustc::mir::BodyCache<$tcx> > >, [] promoted: rustc_index::vec::IndexVec< rustc::mir::Promoted, - rustc::mir::Body<$tcx> + rustc::mir::BodyCache<$tcx> >, [] tables: rustc::ty::TypeckTables<$tcx>, [] const_allocs: rustc::mir::interpret::Allocation, diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index ac8173f101a..e13f6cabb52 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1003,7 +1003,7 @@ fn lower_attr(&mut self, attr: &Attribute) -> Attribute { AttrKind::Normal(ref item) => { AttrKind::Normal(AttrItem { path: item.path.clone(), - tokens: self.lower_token_stream(item.tokens.clone()), + args: self.lower_mac_args(&item.args), }) } AttrKind::DocComment(comment) => AttrKind::DocComment(comment) @@ -1017,6 +1017,16 @@ fn lower_attr(&mut self, attr: &Attribute) -> Attribute { } } + fn lower_mac_args(&mut self, args: &MacArgs) -> MacArgs { + match *args { + MacArgs::Empty => MacArgs::Empty, + MacArgs::Delimited(dspan, delim, ref tokens) => + MacArgs::Delimited(dspan, delim, self.lower_token_stream(tokens.clone())), + MacArgs::Eq(eq_span, ref tokens) => + MacArgs::Eq(eq_span, self.lower_token_stream(tokens.clone())), + } + } + fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream { tokens .into_trees() diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs index f689e7f9622..ff9d8c85df8 100644 --- a/src/librustc/hir/lowering/item.rs +++ b/src/librustc/hir/lowering/item.rs @@ -233,7 +233,7 @@ pub fn lower_item(&mut self, i: &Item) -> Option { if let ItemKind::MacroDef(ref def) = i.kind { if !def.legacy || attr::contains_name(&i.attrs, sym::macro_export) { - let body = self.lower_token_stream(def.stream()); + let body = self.lower_token_stream(def.body.inner_tokens()); let hir_id = self.lower_node_id(i.id); self.exported_macros.push(hir::MacroDef { name: ident.name, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 05543f1d2ef..7f72154e42c 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -47,8 +47,7 @@ /// This is basically the subset of `Context` that we can /// build early in the compile pipeline. pub struct LintStore { - /// Registered lints. The bool is true if the lint was - /// added by a plugin. + /// Registered lints. lints: Vec<&'static Lint>, /// Constructor functions for each variety of lint pass. diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index 9b413667418..b8ef4f753f3 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -1,16 +1,19 @@ use rustc_index::vec::IndexVec; -use rustc_data_structures::sync::{RwLock, MappedReadGuard, ReadGuard}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use crate::ich::StableHashingContext; -use crate::mir::{Body, BasicBlock}; +use crate::mir::{BasicBlock, BasicBlockData, Body, LocalDecls, Location, Successors}; +use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; +use rustc_data_structures::graph::dominators::{dominators, Dominators}; +use std::iter; +use std::ops::{Deref, DerefMut, Index, IndexMut}; +use std::vec::IntoIter; #[derive(Clone, Debug)] pub struct Cache { - predecessors: RwLock>>> + predecessors: Option>>, } - impl rustc_serialize::Encodable for Cache { fn encode(&self, s: &mut S) -> Result<(), S::Error> { Encodable::encode(&(), s) @@ -31,39 +34,264 @@ fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) { impl Cache { pub fn new() -> Self { - Cache { - predecessors: RwLock::new(None) + Self { + predecessors: None, } } - pub fn invalidate(&self) { + pub fn invalidate_predecessors(&mut self) { // FIXME: consider being more fine-grained - *self.predecessors.borrow_mut() = None; + self.predecessors = None; } - pub fn predecessors( - &self, - body: &Body<'_> - ) -> MappedReadGuard<'_, IndexVec>> { - if self.predecessors.borrow().is_none() { - *self.predecessors.borrow_mut() = Some(calculate_predecessors(body)); + pub fn ensure_predecessors(&mut self, body: &Body<'_>) { + if self.predecessors.is_none() { + let mut result = IndexVec::from_elem(vec![], body.basic_blocks()); + for (bb, data) in body.basic_blocks().iter_enumerated() { + if let Some(ref term) = data.terminator { + for &tgt in term.successors() { + result[tgt].push(bb); + } + } + } + + self.predecessors = Some(result) } + } + + /// This will recompute the predecessors cache if it is not available + fn predecessors(&mut self, body: &Body<'_>) -> &IndexVec> { + self.ensure_predecessors(body); + self.predecessors.as_ref().unwrap() + } + + fn unwrap_predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] { + &self.predecessors.as_ref().unwrap()[bb] + } - ReadGuard::map(self.predecessors.borrow(), |p| p.as_ref().unwrap()) + fn unwrap_predecessor_locations<'a>( + &'a self, + loc: Location, + body: &'a Body<'a> + ) -> impl Iterator + 'a { + let if_zero_locations = if loc.statement_index == 0 { + let predecessor_blocks = self.unwrap_predecessors_for(loc.block); + let num_predecessor_blocks = predecessor_blocks.len(); + Some( + (0..num_predecessor_blocks) + .map(move |i| predecessor_blocks[i]) + .map(move |bb| body.terminator_loc(bb)), + ) + } else { + None + }; + + let if_not_zero_locations = if loc.statement_index == 0 { + None + } else { + Some(Location { block: loc.block, statement_index: loc.statement_index - 1 }) + }; + + if_zero_locations.into_iter().flatten().chain(if_not_zero_locations) + } + + pub fn basic_blocks_mut<'a, 'tcx>( + &mut self, + body: &'a mut Body<'tcx> + ) -> &'a mut IndexVec> { + debug!("bbm: Clearing predecessors cache for body at: {:?}", body.span.data()); + self.invalidate_predecessors(); + &mut body.basic_blocks + } + + pub fn basic_blocks_and_local_decls_mut<'a, 'tcx>( + &mut self, + body: &'a mut Body<'tcx> + ) -> (&'a mut IndexVec>, &'a mut LocalDecls<'tcx>) { + debug!("bbaldm: Clearing predecessors cache for body at: {:?}", body.span.data()); + self.invalidate_predecessors(); + (&mut body.basic_blocks, &mut body.local_decls) } } -fn calculate_predecessors(body: &Body<'_>) -> IndexVec> { - let mut result = IndexVec::from_elem(vec![], body.basic_blocks()); - for (bb, data) in body.basic_blocks().iter_enumerated() { - if let Some(ref term) = data.terminator { - for &tgt in term.successors() { - result[tgt].push(bb); - } +#[derive(Clone, Debug, HashStable, RustcEncodable, RustcDecodable, TypeFoldable)] +pub struct BodyCache<'tcx> { + cache: Cache, + body: Body<'tcx>, +} + +impl BodyCache<'tcx> { + pub fn new(body: Body<'tcx>) -> Self { + Self { + cache: Cache::new(), + body, + } + } +} + +#[macro_export] +macro_rules! read_only { + ($body:expr) => { + { + $body.ensure_predecessors(); + $body.unwrap_read_only() + } + }; +} + +impl BodyCache<'tcx> { + pub fn ensure_predecessors(&mut self) { + self.cache.ensure_predecessors(&self.body); + } + + pub fn predecessors(&mut self) -> &IndexVec> { + self.cache.predecessors(&self.body) + } + + pub fn unwrap_read_only(&self) -> ReadOnlyBodyCache<'_, 'tcx> { + ReadOnlyBodyCache::new(&self.cache, &self.body) + } + + pub fn basic_blocks_mut(&mut self) -> &mut IndexVec> { + self.cache.basic_blocks_mut(&mut self.body) + } + + pub fn basic_blocks_and_local_decls_mut( + &mut self + ) -> (&mut IndexVec>, &mut LocalDecls<'tcx>) { + self.cache.basic_blocks_and_local_decls_mut(&mut self.body) + } +} + +impl<'tcx> Index for BodyCache<'tcx> { + type Output = BasicBlockData<'tcx>; + + fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { + &self.body[index] + } +} + +impl<'tcx> IndexMut for BodyCache<'tcx> { + fn index_mut(&mut self, index: BasicBlock) -> &mut Self::Output { + &mut self.basic_blocks_mut()[index] + } +} + +impl<'tcx> Deref for BodyCache<'tcx> { + type Target = Body<'tcx>; + + fn deref(&self) -> &Self::Target { + &self.body + } +} + +impl<'tcx> DerefMut for BodyCache<'tcx> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.body + } +} + +#[derive(Copy, Clone, Debug)] +pub struct ReadOnlyBodyCache<'a, 'tcx> { + cache: &'a Cache, + body: &'a Body<'tcx>, +} + +impl ReadOnlyBodyCache<'a, 'tcx> { + fn new(cache: &'a Cache, body: &'a Body<'tcx>) -> Self { + assert!( + cache.predecessors.is_some(), + "Cannot construct ReadOnlyBodyCache without computed predecessors"); + Self { + cache, + body, } } - result + pub fn predecessors(&self) -> &IndexVec> { + self.cache.predecessors.as_ref().unwrap() + } + + pub fn predecessors_for(&self, bb: BasicBlock) -> &[BasicBlock] { + self.cache.unwrap_predecessors_for(bb) + } + + pub fn predecessor_locations(&self, loc: Location) -> impl Iterator + '_ { + self.cache.unwrap_predecessor_locations(loc, self.body) + } + + pub fn body(&self) -> &'a Body<'tcx> { + self.body + } + + pub fn basic_blocks(&self) -> &IndexVec> { + &self.body.basic_blocks + } + + pub fn dominators(&self) -> Dominators { + dominators(self) + } +} + +impl graph::DirectedGraph for ReadOnlyBodyCache<'a, 'tcx> { + type Node = BasicBlock; +} + +impl graph::GraphPredecessors<'graph> for ReadOnlyBodyCache<'a, 'tcx> { + type Item = BasicBlock; + type Iter = IntoIter; +} + +impl graph::WithPredecessors for ReadOnlyBodyCache<'a, 'tcx> { + fn predecessors( + &self, + node: Self::Node, + ) -> >::Iter { + self.cache.unwrap_predecessors_for(node).to_vec().into_iter() + } +} + +impl graph::WithNumNodes for ReadOnlyBodyCache<'a, 'tcx> { + fn num_nodes(&self) -> usize { + self.body.num_nodes() + } +} + +impl graph::WithStartNode for ReadOnlyBodyCache<'a, 'tcx> { + fn start_node(&self) -> Self::Node { + self.body.start_node() + } +} + +impl graph::WithSuccessors for ReadOnlyBodyCache<'a, 'tcx> { + fn successors( + &self, + node: Self::Node, + ) -> >::Iter { + self.body.successors(node) + } +} + +impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for ReadOnlyBodyCache<'a, 'tcx> { + type Item = BasicBlock; + type Iter = iter::Cloned>; +} + + +impl Deref for ReadOnlyBodyCache<'a, 'tcx> { + type Target = Body<'tcx>; + + fn deref(&self) -> &Self::Target { + self.body + } +} + +impl Index for ReadOnlyBodyCache<'a, 'tcx> { + type Output = BasicBlockData<'tcx>; + + fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { + &self.body[index] + } } CloneTypeFoldableAndLiftImpls! { diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 9f133597ab4..557310650fa 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -14,7 +14,7 @@ use syntax_pos::{Pos, Span}; use syntax::symbol::Symbol; use hir::GeneratorKind; -use std::{fmt, env}; +use std::{fmt, env, any::Any}; use rustc_error_codes::*; @@ -44,14 +44,14 @@ pub fn assert_reported(self) { pub type ConstEvalRawResult<'tcx> = Result, ErrorHandled>; pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>; -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct ConstEvalErr<'tcx> { pub span: Span, pub error: crate::mir::interpret::InterpError<'tcx>, pub stacktrace: Vec>, } -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct FrameInfo<'tcx> { /// This span is in the caller. pub call_site: Span, @@ -138,6 +138,7 @@ fn struct_generic( lint_root: Option, ) -> Result, ErrorHandled> { let must_error = match self.error { + InterpError::MachineStop(_) => bug!("CTFE does not stop"), err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => return Err(ErrorHandled::TooGeneric), @@ -189,7 +190,7 @@ pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<' /// Thsese should always be constructed by calling `.into()` on /// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*` /// macros for this. -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct InterpErrorInfo<'tcx> { pub kind: InterpError<'tcx>, backtrace: Option>, @@ -331,7 +332,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// Error information for when the program we executed turned out not to actually be a valid /// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp /// where we work on generic code or execution does not have all information available. -#[derive(Clone, HashStable)] pub enum InvalidProgramInfo<'tcx> { /// Resolution can fail if we are in a too generic context. TooGeneric, @@ -361,7 +361,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } /// Error information for when the program caused Undefined Behavior. -#[derive(Clone, HashStable)] pub enum UndefinedBehaviorInfo { /// Free-form case. Only for errors that are never caught! Ub(String), @@ -394,7 +393,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// /// Currently, we also use this as fall-back error kind for errors that have not been /// categorized yet. -#[derive(Clone, HashStable)] pub enum UnsupportedOpInfo<'tcx> { /// Free-form case. Only for errors that are never caught! Unsupported(String), @@ -571,7 +569,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// Error information for when the program exhausted the resources granted to it /// by the interpreter. -#[derive(Clone, HashStable)] pub enum ResourceExhaustionInfo { /// The stack grew too big. StackFrameLimitReached, @@ -592,7 +589,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -#[derive(Clone, HashStable)] pub enum InterpError<'tcx> { /// The program panicked. Panic(PanicInfo), @@ -601,14 +597,14 @@ pub enum InterpError<'tcx> { /// The program did something the interpreter does not support (some of these *might* be UB /// but the interpreter is not sure). Unsupported(UnsupportedOpInfo<'tcx>), - /// The program was invalid (ill-typed, not sufficiently monomorphized, ...). + /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...). InvalidProgram(InvalidProgramInfo<'tcx>), /// The program exhausted the interpreter's resources (stack/heap too big, - /// execution takes too long, ..). + /// execution takes too long, ...). ResourceExhaustion(ResourceExhaustionInfo), - /// Not actually an interpreter error -- used to signal that execution has exited - /// with the given status code. Used by Miri, but not by CTFE. - Exit(i32), + /// Stop execution for a machine-controlled reason. This is never raised by + /// the core engine itself. + MachineStop(Box), } pub type InterpResult<'tcx, T = ()> = Result>; @@ -634,8 +630,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", msg), Panic(ref msg) => write!(f, "{:?}", msg), - Exit(code) => - write!(f, "exited with status code {}", code), + MachineStop(_) => + write!(f, "machine caused execution to stop"), } } } diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index f82af62c5f3..a038ca23ae9 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -471,6 +471,13 @@ fn from(s: Scalar) -> Self { } } +impl From> for ScalarMaybeUndef { + #[inline(always)] + fn from(s: Pointer) -> Self { + ScalarMaybeUndef::Scalar(s.into()) + } +} + impl fmt::Debug for ScalarMaybeUndef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 8c1690a177b..df5d4997e08 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -21,25 +21,25 @@ use polonius_engine::Atom; use rustc_index::bit_set::BitMatrix; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::dominators::{dominators, Dominators}; -use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; +use rustc_data_structures::graph::dominators::Dominators; +use rustc_data_structures::graph::{self, GraphSuccessors}; use rustc_index::vec::{Idx, IndexVec}; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::sync::MappedReadGuard; use rustc_macros::HashStable; use rustc_serialize::{Encodable, Decodable}; use smallvec::SmallVec; use std::borrow::Cow; use std::fmt::{self, Debug, Display, Formatter, Write}; -use std::ops::{Index, IndexMut}; +use std::ops::Index; use std::slice; -use std::vec::IntoIter; use std::{iter, mem, option, u32}; use syntax::ast::Name; use syntax::symbol::Symbol; use syntax_pos::{Span, DUMMY_SP}; pub use crate::mir::interpret::AssertMessage; +pub use crate::mir::cache::{BodyCache, ReadOnlyBodyCache}; +pub use crate::read_only; mod cache; pub mod interpret; @@ -104,15 +104,11 @@ pub struct Body<'tcx> { /// and used for debuginfo. Indexed by a `SourceScope`. pub source_scopes: IndexVec, - /// Crate-local information for each source scope, that can't (and - /// needn't) be tracked across crates. - pub source_scope_local_data: ClearCrossCrate>, - /// The yield type of the function, if it is a generator. pub yield_ty: Option>, /// Generator drop glue. - pub generator_drop: Option>>, + pub generator_drop: Option>>, /// The layout of a generator. Produced by the state transformation. pub generator_layout: Option>, @@ -158,16 +154,12 @@ pub struct Body<'tcx> { /// A span representing this MIR, for error reporting. pub span: Span, - - /// A cache for various calculations. - cache: cache::Cache, } impl<'tcx> Body<'tcx> { pub fn new( basic_blocks: IndexVec>, source_scopes: IndexVec, - source_scope_local_data: ClearCrossCrate>, local_decls: LocalDecls<'tcx>, user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, arg_count: usize, @@ -188,7 +180,6 @@ pub fn new( phase: MirPhase::Build, basic_blocks, source_scopes, - source_scope_local_data, yield_ty: None, generator_drop: None, generator_layout: None, @@ -199,7 +190,6 @@ pub fn new( spread_arg: None, var_debug_info, span, - cache: cache::Cache::new(), control_flow_destroyed, } } @@ -209,58 +199,6 @@ pub fn basic_blocks(&self) -> &IndexVec> { &self.basic_blocks } - #[inline] - pub fn basic_blocks_mut(&mut self) -> &mut IndexVec> { - self.cache.invalidate(); - &mut self.basic_blocks - } - - #[inline] - pub fn basic_blocks_and_local_decls_mut( - &mut self, - ) -> (&mut IndexVec>, &mut LocalDecls<'tcx>) { - self.cache.invalidate(); - (&mut self.basic_blocks, &mut self.local_decls) - } - - #[inline] - pub fn predecessors(&self) -> MappedReadGuard<'_, IndexVec>> { - self.cache.predecessors(self) - } - - #[inline] - pub fn predecessors_for(&self, bb: BasicBlock) -> MappedReadGuard<'_, Vec> { - MappedReadGuard::map(self.predecessors(), |p| &p[bb]) - } - - #[inline] - pub fn predecessor_locations(&self, loc: Location) -> impl Iterator + '_ { - let if_zero_locations = if loc.statement_index == 0 { - let predecessor_blocks = self.predecessors_for(loc.block); - let num_predecessor_blocks = predecessor_blocks.len(); - Some( - (0..num_predecessor_blocks) - .map(move |i| predecessor_blocks[i]) - .map(move |bb| self.terminator_loc(bb)), - ) - } else { - None - }; - - let if_not_zero_locations = if loc.statement_index == 0 { - None - } else { - Some(Location { block: loc.block, statement_index: loc.statement_index - 1 }) - }; - - if_zero_locations.into_iter().flatten().chain(if_not_zero_locations) - } - - #[inline] - pub fn dominators(&self) -> Dominators { - dominators(self) - } - /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the /// `START_BLOCK`. pub fn is_cfg_cyclic(&self) -> bool { @@ -361,7 +299,7 @@ pub fn vars_and_temps_iter(&self) -> impl Iterator { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. pub fn make_statement_nop(&mut self, location: Location) { - let block = &mut self[location.block]; + let block = &mut self.basic_blocks[location.block]; debug_assert!(location.statement_index < block.statements.len()); block.statements[location.statement_index].make_nop() } @@ -421,13 +359,6 @@ fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { } } -impl<'tcx> IndexMut for Body<'tcx> { - #[inline] - fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> { - &mut self.basic_blocks_mut()[index] - } -} - #[derive(Copy, Clone, Debug, HashStable, TypeFoldable)] pub enum ClearCrossCrate { Clear, @@ -435,6 +366,13 @@ pub enum ClearCrossCrate { } impl ClearCrossCrate { + pub fn as_ref(&'a self) -> ClearCrossCrate<&'a T> { + match self { + ClearCrossCrate::Clear => ClearCrossCrate::Clear, + ClearCrossCrate::Set(v) => ClearCrossCrate::Set(v), + } + } + pub fn assert_crate_local(self) -> T { match self { ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"), @@ -2027,6 +1965,10 @@ pub struct SourceScope { pub struct SourceScopeData { pub span: Span, pub parent_scope: Option, + + /// Crate-local information for this source scope, that can't (and + /// needn't) be tracked across crates. + pub local_data: ClearCrossCrate, } #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] @@ -2308,10 +2250,14 @@ fn fmt_tuple(fmt: &mut Formatter<'_>, places: &[Operand<'_>]) -> fmt::Result { } } - AggregateKind::Closure(def_id, _) => ty::tls::with(|tcx| { + AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| { if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { let name = if tcx.sess.opts.debugging_opts.span_free_formats { - format!("[closure@{:?}]", hir_id) + let substs = tcx.lift(&substs).unwrap(); + format!( + "[closure@{}]", + tcx.def_path_str_with_substs(def_id, substs), + ) } else { format!("[closure@{:?}]", tcx.hir().span(hir_id)) }; @@ -2609,15 +2555,6 @@ fn start_node(&self) -> Self::Node { } } -impl<'tcx> graph::WithPredecessors for Body<'tcx> { - fn predecessors( - &self, - node: Self::Node, - ) -> >::Iter { - self.predecessors_for(node).clone().into_iter() - } -} - impl<'tcx> graph::WithSuccessors for Body<'tcx> { fn successors( &self, @@ -2627,11 +2564,6 @@ fn successors( } } -impl<'a, 'b> graph::GraphPredecessors<'b> for Body<'a> { - type Item = BasicBlock; - type Iter = IntoIter; -} - impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> { type Item = BasicBlock; type Iter = iter::Cloned>; @@ -2666,7 +2598,11 @@ pub fn successor_within_block(&self) -> Location { } /// Returns `true` if `other` is earlier in the control flow graph than `self`. - pub fn is_predecessor_of<'tcx>(&self, other: Location, body: &Body<'tcx>) -> bool { + pub fn is_predecessor_of<'tcx>( + &self, + other: Location, + body: ReadOnlyBodyCache<'_, 'tcx> + ) -> bool { // If we are in the same block as the other location and are an earlier statement // then we are a predecessor of `other`. if self.block == other.block && self.statement_index < other.statement_index { @@ -2674,13 +2610,13 @@ pub fn is_predecessor_of<'tcx>(&self, other: Location, body: &Body<'tcx>) -> boo } // If we're in another block, then we want to check that block is a predecessor of `other`. - let mut queue: Vec = body.predecessors_for(other.block).clone(); + let mut queue: Vec = body.predecessors_for(other.block).to_vec(); let mut visited = FxHashSet::default(); while let Some(block) = queue.pop() { // If we haven't visited this block before, then make sure we visit it's predecessors. if visited.insert(block) { - queue.append(&mut body.predecessors_for(block).clone()); + queue.extend(body.predecessors_for(block).iter().cloned()); } else { continue; } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 58c12ef2501..47a1d67d5d6 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -65,13 +65,25 @@ // variant argument) that does not require visiting, as in // `is_cleanup` above. +macro_rules! body_cache_type { + (mut $a:lifetime, $tcx:lifetime) => { + &mut BodyCache<$tcx> + }; + ($a:lifetime, $tcx:lifetime) => { + ReadOnlyBodyCache<$a, $tcx> + }; +} + macro_rules! make_mir_visitor { ($visitor_trait_name:ident, $($mutability:ident)?) => { pub trait $visitor_trait_name<'tcx> { // Override these, and call `self.super_xxx` to revert back to the // default behavior. - fn visit_body(&mut self, body: & $($mutability)? Body<'tcx>) { + fn visit_body( + &mut self, + body: body_cache_type!($($mutability)? '_, 'tcx) + ) { self.super_body(body); } @@ -240,11 +252,14 @@ fn visit_source_scope(&mut self, // The `super_xxx` methods comprise the default behavior and are // not meant to be overridden. - fn super_body(&mut self, - body: & $($mutability)? Body<'tcx>) { + fn super_body( + &mut self, + $($mutability)? body: body_cache_type!($($mutability)? '_, 'tcx) + ) { + let span = body.span; if let Some(yield_ty) = &$($mutability)? body.yield_ty { self.visit_ty(yield_ty, TyContext::YieldTy(SourceInfo { - span: body.span, + span, scope: OUTERMOST_SOURCE_SCOPE, })); } @@ -260,6 +275,7 @@ macro_rules! basic_blocks { self.visit_basic_block_data(bb, data); } + let body: & $($mutability)? Body<'_> = & $($mutability)? body; for scope in &$($mutability)? body.source_scopes { self.visit_source_scope_data(scope); } @@ -317,6 +333,7 @@ fn super_source_scope_data(&mut self, scope_data: & $($mutability)? SourceScopeD let SourceScopeData { span, parent_scope, + local_data: _, } = scope_data; self.visit_span(span); @@ -789,7 +806,11 @@ fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) { // Convenience methods - fn visit_location(&mut self, body: & $($mutability)? Body<'tcx>, location: Location) { + fn visit_location( + &mut self, + body: body_cache_type!($($mutability)? '_, 'tcx), + location: Location + ) { let basic_block = & $($mutability)? body[location.block]; if basic_block.statements.len() == location.statement_index { if let Some(ref $($mutability)? terminator) = basic_block.terminator { diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index d715ddb1b81..a6d7e5c9291 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -106,44 +106,54 @@ /// Fetch the MIR for a given `DefId` right after it's built - this includes /// unreachable code. - query mir_built(_: DefId) -> &'tcx Steal> {} + query mir_built(_: DefId) -> &'tcx Steal> {} /// Fetch the MIR for a given `DefId` up till the point where it is /// ready for const evaluation. /// /// See the README for the `mir` module for details. - query mir_const(_: DefId) -> &'tcx Steal> { + query mir_const(_: DefId) -> &'tcx Steal> { no_hash } query mir_validated(_: DefId) -> ( - &'tcx Steal>, - &'tcx Steal>> + &'tcx Steal>, + &'tcx Steal>> ) { no_hash } /// MIR after our optimization passes have run. This is MIR that is ready /// for codegen. This is also the only query that can fetch non-local MIR, at present. - query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> { + query optimized_mir(key: DefId) -> &'tcx mir::BodyCache<'tcx> { cache_on_disk_if { key.is_local() } load_cached(tcx, id) { - let mir: Option> = tcx.queries.on_disk_cache - .try_load_query_result(tcx, id); - mir.map(|x| &*tcx.arena.alloc(x)) + let mir: Option> + = tcx.queries.on_disk_cache.try_load_query_result(tcx, id); + mir.map(|x| { + let cache = tcx.arena.alloc(x); + cache.ensure_predecessors(); + &*cache + }) } } - query promoted_mir(key: DefId) -> &'tcx IndexVec> { + query promoted_mir(key: DefId) -> &'tcx IndexVec> { cache_on_disk_if { key.is_local() } load_cached(tcx, id) { let promoted: Option< rustc_index::vec::IndexVec< crate::mir::Promoted, - crate::mir::Body<'tcx> + crate::mir::BodyCache<'tcx> >> = tcx.queries.on_disk_cache.try_load_query_result(tcx, id); - promoted.map(|p| &*tcx.arena.alloc(p)) + promoted.map(|p| { + let cache = tcx.arena.alloc(p); + for body in cache.iter_mut() { + body.ensure_predecessors(); + } + &*cache + }) } } } @@ -502,7 +512,7 @@ /// in the case of closures, this will be redirected to the enclosing function. query region_scope_tree(_: DefId) -> &'tcx region::ScopeTree {} - query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::Body<'tcx> { + query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::BodyCache<'tcx> { no_force desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index fbfae721bbe..9a242d9d076 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -47,6 +47,17 @@ pub enum Sanitizer { Thread, } +impl fmt::Display for Sanitizer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Sanitizer::Address => "address".fmt(f), + Sanitizer::Leak => "leak".fmt(f), + Sanitizer::Memory => "memory".fmt(f), + Sanitizer::Thread => "thread".fmt(f), + } + } +} + impl FromStr for Sanitizer { type Err = (); fn from_str(s: &str) -> Result { @@ -1364,8 +1375,6 @@ fn parse_symbol_mangling_version( "enable queries of the dependency graph for regression testing"), no_analysis: bool = (false, parse_bool, [UNTRACKED], "parse and expand the source, but run no analysis"), - extra_plugins: Vec = (Vec::new(), parse_list, [TRACKED], - "load extra plugins"), unstable_options: bool = (false, parse_bool, [UNTRACKED], "adds unstable command line options to rustc interface"), force_overflow_checks: Option = (None, parse_opt_bool, [TRACKED], @@ -1582,6 +1591,10 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { } } } + if let Some(s) = &sess.opts.debugging_opts.sanitizer { + let symbol = Symbol::intern(&s.to_string()); + ret.insert((sym::sanitize, Some(symbol))); + } if sess.opts.debug_assertions { ret.insert((Symbol::intern("debug_assertions"), None)); } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 74ba83d0ee4..f673ea3e771 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -76,7 +76,6 @@ pub struct Session { /// (sub)diagnostics that have been set once, but should not be set again, /// in order to avoid redundantly verbose output (Issue #24690, #44953). pub one_time_diagnostics: Lock, String)>>, - pub plugin_llvm_passes: OneThread>>, pub crate_types: Once>, /// The `crate_disambiguator` is constructed out of all the `-C metadata` /// arguments passed to the compiler. Its value together with the crate-name @@ -1149,7 +1148,6 @@ fn build_session_( local_crate_source_file, working_dir, one_time_diagnostics: Default::default(), - plugin_llvm_passes: OneThread::new(RefCell::new(Vec::new())), crate_types: Once::new(), crate_disambiguator: Once::new(), features: Once::new(), diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 90db1fe3195..ba44c6c3b9a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -521,7 +521,7 @@ fn on_unimplemented_note( ) { command.evaluate(self.tcx, trait_ref, &flags[..]) } else { - OnUnimplementedNote::empty() + OnUnimplementedNote::default() } } @@ -697,6 +697,7 @@ pub fn report_selection_error( fallback_has_occurred: bool, points_at_arg: bool, ) { + let tcx = self.tcx; let span = obligation.cause.span; let mut err = match *error { @@ -732,6 +733,7 @@ pub fn report_selection_error( message, label, note, + enclosing_scope, } = self.on_unimplemented_note(trait_ref, obligation); let have_alt_message = message.is_some() || label.is_some(); let is_try = self.tcx.sess.source_map().span_to_snippet(span) @@ -798,6 +800,19 @@ pub fn report_selection_error( // If it has a custom `#[rustc_on_unimplemented]` note, let's display it err.note(s.as_str()); } + if let Some(ref s) = enclosing_scope { + let enclosing_scope_span = tcx.def_span( + tcx.hir() + .opt_local_def_id(obligation.cause.body_id) + .unwrap_or_else(|| { + tcx.hir().body_owner_def_id(hir::BodyId { + hir_id: obligation.cause.body_id, + }) + }), + ); + + err.span_label(enclosing_scope_span, s.as_str()); + } self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 59aa0810975..604f39dcf29 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -22,18 +22,15 @@ pub struct OnUnimplementedDirective { pub message: Option, pub label: Option, pub note: Option, + pub enclosing_scope: Option, } +#[derive(Default)] pub struct OnUnimplementedNote { pub message: Option, pub label: Option, pub note: Option, -} - -impl OnUnimplementedNote { - pub fn empty() -> Self { - OnUnimplementedNote { message: None, label: None, note: None } - } + pub enclosing_scope: Option, } fn parse_error( @@ -85,24 +82,33 @@ fn parse( let mut message = None; let mut label = None; let mut note = None; + let mut enclosing_scope = None; let mut subcommands = vec![]; + + let parse_value = |value_str| { + OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span) + .map(Some) + }; + for item in item_iter { if item.check_name(sym::message) && message.is_none() { if let Some(message_) = item.value_str() { - message = Some(OnUnimplementedFormatString::try_parse( - tcx, trait_def_id, message_, span)?); + message = parse_value(message_)?; continue; } } else if item.check_name(sym::label) && label.is_none() { if let Some(label_) = item.value_str() { - label = Some(OnUnimplementedFormatString::try_parse( - tcx, trait_def_id, label_, span)?); + label = parse_value(label_)?; continue; } } else if item.check_name(sym::note) && note.is_none() { if let Some(note_) = item.value_str() { - note = Some(OnUnimplementedFormatString::try_parse( - tcx, trait_def_id, note_, span)?); + note = parse_value(note_)?; + continue; + } + } else if item.check_name(sym::enclosing_scope) && enclosing_scope.is_none() { + if let Some(enclosing_scope_) = item.value_str() { + enclosing_scope = parse_value(enclosing_scope_)?; continue; } } else if item.check_name(sym::on) && is_root && @@ -130,7 +136,14 @@ fn parse( if errored { Err(ErrorReported) } else { - Ok(OnUnimplementedDirective { condition, message, label, subcommands, note }) + Ok(OnUnimplementedDirective { + condition, + subcommands, + message, + label, + note, + enclosing_scope + }) } } @@ -157,6 +170,7 @@ pub fn of_item( label: Some(OnUnimplementedFormatString::try_parse( tcx, trait_def_id, value, attr.span)?), note: None, + enclosing_scope: None, })) } else { return Err(ErrorReported); @@ -174,6 +188,7 @@ pub fn evaluate( let mut message = None; let mut label = None; let mut note = None; + let mut enclosing_scope = None; info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); for command in self.subcommands.iter().chain(Some(self)).rev() { @@ -202,6 +217,10 @@ pub fn evaluate( if let Some(ref note_) = command.note { note = Some(note_.clone()); } + + if let Some(ref enclosing_scope_) = command.enclosing_scope { + enclosing_scope = Some(enclosing_scope_.clone()); + } } let options: FxHashMap = options.into_iter() @@ -211,6 +230,7 @@ pub fn evaluate( label: label.map(|l| l.format(tcx, trait_ref, &options)), message: message.map(|m| m.format(tcx, trait_ref, &options)), note: note.map(|n| n.format(tcx, trait_ref, &options)), + enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)), } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 776ae7dc141..6a0002cd80f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -22,7 +22,7 @@ use crate::middle::lang_items; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use crate::middle::stability; -use crate::mir::{Body, Field, interpret, Local, Place, PlaceElem, ProjectionKind, Promoted}; +use crate::mir::{BodyCache, Field, interpret, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::mir::interpret::{ConstValue, Allocation, Scalar}; use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef, Subst}; use crate::ty::ReprOptions; @@ -1083,17 +1083,17 @@ pub fn hir(self) -> &'tcx hir_map::Map<'tcx> { &self.hir_map } - pub fn alloc_steal_mir(self, mir: Body<'tcx>) -> &'tcx Steal> { + pub fn alloc_steal_mir(self, mir: BodyCache<'tcx>) -> &'tcx Steal> { self.arena.alloc(Steal::new(mir)) } - pub fn alloc_steal_promoted(self, promoted: IndexVec>) -> - &'tcx Steal>> { + pub fn alloc_steal_promoted(self, promoted: IndexVec>) -> + &'tcx Steal>> { self.arena.alloc(Steal::new(promoted)) } - pub fn intern_promoted(self, promoted: IndexVec>) -> - &'tcx IndexVec> { + pub fn intern_promoted(self, promoted: IndexVec>) -> + &'tcx IndexVec> { self.arena.alloc(promoted) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8ccfc467f4a..c9a934e9ebd 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -18,7 +18,7 @@ use crate::middle::cstore::CrateStoreDyn; use crate::middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use crate::middle::resolve_lifetime::ObjectLifetimeDefault; -use crate::mir::Body; +use crate::mir::ReadOnlyBodyCache; use crate::mir::interpret::{GlobalId, ErrorHandled}; use crate::mir::GeneratorLayout; use crate::session::CrateDisambiguator; @@ -2985,10 +2985,10 @@ pub fn item_name(self, id: DefId) -> Symbol { } /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair. - pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { + pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> ReadOnlyBodyCache<'tcx, 'tcx> { match instance { ty::InstanceDef::Item(did) => { - self.optimized_mir(did) + self.optimized_mir(did).unwrap_read_only() } ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | @@ -2998,7 +2998,7 @@ pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) => { - self.mir_shims(instance) + self.mir_shims(instance).unwrap_read_only() } } } diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index c941b3e5e4b..fff2f06e87b 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -682,7 +682,7 @@ fn pretty_print_type( // FIXME(eddyb) should use `def_span`. if let Some(hir_id) = self.tcx().hir().as_local_hir_id(did) { if self.tcx().sess.opts.debugging_opts.span_free_formats { - p!(write("@{:?}", hir_id)); + p!(write("@"), print_def_path(did, substs)); } else { p!(write("@{:?}", self.tcx().hir().span(hir_id))); } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index ffbf8813d30..ce76a4c831b 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -3,6 +3,7 @@ //! hand, though we've recently added some macros and proc-macros to help with the tedium. use crate::hir::def::Namespace; +use crate::hir::def_id::CRATE_DEF_INDEX; use crate::mir::ProjectionKind; use crate::mir::interpret; use crate::ty::{self, Lift, Ty, TyCtxt, InferConst}; @@ -95,8 +96,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { ty::BrAnon(n) => write!(f, "BrAnon({:?})", n), ty::BrNamed(did, name) => { - write!(f, "BrNamed({:?}:{:?}, {})", - did.krate, did.index, name) + if did.index == CRATE_DEF_INDEX { + write!(f, "BrNamed({})", name) + } else { + write!(f, "BrNamed({:?}, {})", did, name) + } } ty::BrEnv => write!(f, "BrEnv"), } diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 5dfb04a4436..07ac76cec99 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -365,20 +365,6 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext, add_sanitizer_passes(config, &mut extra_passes); - for pass_name in &cgcx.plugin_passes { - if let Some(pass) = find_pass(pass_name) { - extra_passes.push(pass); - } else { - diag_handler.err(&format!("a plugin asked for LLVM pass \ - `{}` but LLVM does not \ - recognize it", pass_name)); - } - - if pass_name == "name-anon-globals" { - have_name_anon_globals_pass = true; - } - } - // Some options cause LLVM bitcode to be emitted, which uses ThinLTOBuffers, so we need // to make sure we run LLVM's NameAnonGlobals pass when emitting bitcode; otherwise // we'll get errors in LLVM. diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 7bff9e69dd5..72612c4704e 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -108,6 +108,8 @@ unsafe fn configure_llvm(sess: &Session) { ("rclass", Some(sym::arm_target_feature)), ("dsp", Some(sym::arm_target_feature)), ("neon", Some(sym::arm_target_feature)), + ("crc", Some(sym::arm_target_feature)), + ("crypto", Some(sym::arm_target_feature)), ("v5te", Some(sym::arm_target_feature)), ("v6", Some(sym::arm_target_feature)), ("v6k", Some(sym::arm_target_feature)), diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 9d3e57449f8..863b41ec15e 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -231,8 +231,6 @@ pub struct CodegenContext { pub total_cgus: usize, // Handler to use for diagnostics produced during codegen. pub diag_emitter: SharedEmitter, - // LLVM passes added by plugins. - pub plugin_passes: Vec, // LLVM optimizations for which we want to print remarks. pub remark: Passes, // Worker thread number @@ -1028,7 +1026,6 @@ fn start_executing_work( time_passes: sess.time_extended(), prof: sess.prof.clone(), exported_symbols, - plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), worker: 0, incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()), diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 22693beb855..e460a4a2e8c 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -374,7 +374,7 @@ pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( let lldecl = cx.get_fn(instance); let mir = cx.tcx().instance_mir(instance.def); - mir::codegen_mir::(cx, lldecl, &mir, instance, sig); + mir::codegen_mir::(cx, lldecl, mir, instance, sig); } /// Creates the `main` function which will initialize the rust runtime and call diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index e44551fcbcd..f15456e0ff8 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -29,7 +29,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead // of putting everything in allocas just so we can use llvm.dbg.declare. if fx.cx.sess().opts.debuginfo == DebugInfo::Full { - if mir.local_kind(local) == mir::LocalKind::Arg { + if fx.mir.local_kind(local) == mir::LocalKind::Arg { analyzer.not_ssa(local); continue; } @@ -70,9 +70,10 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { fn new(fx: &'mir FunctionCx<'a, 'tcx, Bx>) -> Self { let invalid_location = mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location(); + let dominators = fx.mir.dominators(); let mut analyzer = LocalAnalyzer { fx, - dominators: fx.mir.dominators(), + dominators, non_ssa_locals: BitSet::new_empty(fx.mir.local_decls.len()), first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls) }; @@ -130,7 +131,7 @@ fn process_place( }; if is_consume { let base_ty = - mir::Place::ty_from(place_ref.base, proj_base, self.fx.mir, cx.tcx()); + mir::Place::ty_from(place_ref.base, proj_base, &*self.fx.mir, cx.tcx()); let base_ty = self.fx.monomorphize(&base_ty); // ZSTs don't require any actual memory access. diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 14be0e80fb4..23a5b0cf32a 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -153,7 +153,7 @@ fn do_call<'c, 'b, Bx: BuilderMethods<'b, 'tcx>>( // a loop. fn maybe_sideeffect<'b, 'tcx2: 'b, Bx: BuilderMethods<'b, 'tcx2>>( &self, - mir: &'b mir::Body<'tcx>, + mir: mir::ReadOnlyBodyCache<'b, 'tcx>, bx: &mut Bx, targets: &[mir::BasicBlock], ) { @@ -324,7 +324,7 @@ fn codegen_drop_terminator<'b>( target: mir::BasicBlock, unwind: Option, ) { - let ty = location.ty(self.mir, bx.tcx()).ty; + let ty = location.ty(&*self.mir, bx.tcx()).ty; let ty = self.monomorphize(&ty); let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty); @@ -510,7 +510,7 @@ fn codegen_call_terminator<'b>( let extra_args = &args[sig.inputs().len()..]; let extra_args = extra_args.iter().map(|op_arg| { - let op_ty = op_arg.ty(self.mir, bx.tcx()); + let op_ty = op_arg.ty(&*self.mir, bx.tcx()); self.monomorphize(&op_ty) }).collect::>(); @@ -528,18 +528,11 @@ fn codegen_call_terminator<'b>( _ => FnAbi::new(&bx, sig, &extra_args) }; - // This should never be reachable at runtime: - // We should only emit a call to this intrinsic in #[cfg(miri)] mode, - // which means that we will never actually use the generate object files - // (we will just be interpreting the MIR) - // - // Note that we still need to be able to codegen *something* for this intrisnic: - // Miri currently uses Xargo to build a special libstd. As a side effect, - // we generate normal object files for libstd - while these are never used, - // we still need to be able to build them. + // For normal codegen, this Miri-specific intrinsic is just a NOP. if intrinsic == Some("miri_start_panic") { - bx.abort(); - bx.unreachable(); + let target = destination.as_ref().unwrap().1; + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); + helper.funclet_br(self, &mut bx, target); return; } @@ -576,7 +569,7 @@ fn codegen_call_terminator<'b>( // a NOP let target = destination.as_ref().unwrap().1; helper.maybe_sideeffect(self.mir, &mut bx, &[target]); - helper.funclet_br(self, &mut bx, target); + helper.funclet_br(self, &mut bx, target) } return; } @@ -798,7 +791,8 @@ pub fn codegen_block( bb: mir::BasicBlock, ) { let mut bx = self.build_block(bb); - let data = &self.mir[bb]; + let mir = self.mir; + let data = &mir[bb]; debug!("codegen_block({:?}={:?})", bb, data); @@ -1057,7 +1051,7 @@ fn landing_pad_to( fn landing_pad_uncached( &mut self, - target_bb: Bx::BasicBlock + target_bb: Bx::BasicBlock, ) -> Bx::BasicBlock { if base::wants_msvc_seh(self.cx.sess()) { span_bug!(self.mir.span, "landing pad was not inserted?") diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 6041232489d..8b60904081e 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -1,6 +1,6 @@ use rustc::ty::{self, Ty, TypeFoldable, Instance}; use rustc::ty::layout::{TyLayout, HasTyCtxt, FnAbiExt}; -use rustc::mir::{self, Body}; +use rustc::mir::{self, Body, ReadOnlyBodyCache}; use rustc_target::abi::call::{FnAbi, PassMode}; use crate::base; use crate::traits::*; @@ -21,7 +21,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { instance: Instance<'tcx>, - mir: &'a mir::Body<'tcx>, + mir: mir::ReadOnlyBodyCache<'a, 'tcx>, debug_context: Option>, @@ -122,7 +122,7 @@ fn new_operand>( pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, llfn: Bx::Function, - mir: &'a Body<'tcx>, + mir: ReadOnlyBodyCache<'a, 'tcx>, instance: Instance<'tcx>, sig: ty::FnSig<'tcx>, ) { @@ -132,7 +132,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( debug!("fn_abi: {:?}", fn_abi); let debug_context = - cx.create_function_debug_context(instance, sig, llfn, mir); + cx.create_function_debug_context(instance, sig, llfn, &mir); let mut bx = Bx::new_block(cx, llfn, "start"); @@ -155,8 +155,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } }).collect(); - let (landing_pads, funclets) = create_funclets(mir, &mut bx, &cleanup_kinds, &block_bxs); - + let (landing_pads, funclets) = create_funclets(&mir, &mut bx, &cleanup_kinds, &block_bxs); + let mir_body: &Body<'_> = mir.body(); let mut fx = FunctionCx { instance, mir, @@ -171,7 +171,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( funclets, locals: IndexVec::new(), debug_context, - per_local_var_debug_info: debuginfo::per_local_var_debug_info(cx.tcx(), mir), + per_local_var_debug_info: debuginfo::per_local_var_debug_info(cx.tcx(), mir_body), }; let memory_locals = analyze::non_ssa_locals(&fx); @@ -181,7 +181,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let args = arg_local_refs(&mut bx, &fx, &memory_locals); let mut allocate_local = |local| { - let decl = &mir.local_decls[local]; + let decl = &mir_body.local_decls[local]; let layout = bx.layout_of(fx.monomorphize(&decl.ty)); assert!(!layout.ty.has_erasable_regions()); @@ -207,7 +207,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let retptr = allocate_local(mir::RETURN_PLACE); iter::once(retptr) .chain(args.into_iter()) - .chain(mir.vars_and_temps_iter().map(allocate_local)) + .chain(mir_body.vars_and_temps_iter().map(allocate_local)) .collect() }; @@ -226,8 +226,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( debug_context.source_locations_enabled = true; } - let rpo = traversal::reverse_postorder(&mir); - let mut visited = BitSet::new_empty(mir.basic_blocks().len()); + let rpo = traversal::reverse_postorder(&mir_body); + let mut visited = BitSet::new_empty(mir_body.basic_blocks().len()); // Codegen the body of each block using reverse postorder for (bb, _) in rpo { @@ -237,7 +237,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Remove blocks that haven't been visited, or have no // predecessors. - for bb in mir.basic_blocks().indices() { + for bb in mir_body.basic_blocks().indices() { // Unreachable block if !visited.contains(bb.index()) { debug!("codegen_mir: block {:?} was not visited", bb); @@ -248,8 +248,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } -fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - mir: &'a Body<'tcx>, +fn create_funclets<'a, 'b, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + mir: &'b Body<'tcx>, bx: &mut Bx, cleanup_kinds: &IndexVec, block_bxs: &IndexVec, diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 4df5bce9537..9dd4d0ec22f 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -591,7 +591,12 @@ pub fn codegen_place( pub fn monomorphized_place_ty(&self, place_ref: &mir::PlaceRef<'_, 'tcx>) -> Ty<'tcx> { let tcx = self.cx.tcx(); - let place_ty = mir::Place::ty_from(place_ref.base, place_ref.projection, self.mir, tcx); + let place_ty = mir::Place::ty_from( + place_ref.base, + place_ref.projection, + &*self.mir, + tcx, + ); self.monomorphize(&place_ty.ty) } } diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index f7fb4a57140..3bae027e763 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -513,7 +513,7 @@ pub fn codegen_rvalue_operand( mir::Rvalue::Aggregate(..) => { // According to `rvalue_creates_operand`, only ZST // aggregate rvalues are allowed to be operands. - let ty = rvalue.ty(self.mir, self.cx.tcx()); + let ty = rvalue.ty(&*self.mir, self.cx.tcx()); let operand = OperandRef::new_zst( &mut bx, self.cx.layout_of(self.monomorphize(&ty)), @@ -710,7 +710,7 @@ pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> true, mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { - let ty = rvalue.ty(self.mir, self.cx.tcx()); + let ty = rvalue.ty(&*self.mir, self.cx.tcx()); let ty = self.monomorphize(&ty); self.cx.spanned_layout_of(ty, span).is_zst() } diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/src/librustc_data_structures/graph/dominators/mod.rs index 444463c08e5..5fb58eea381 100644 --- a/src/librustc_data_structures/graph/dominators/mod.rs +++ b/src/librustc_data_structures/graph/dominators/mod.rs @@ -7,32 +7,33 @@ use rustc_index::vec::{Idx, IndexVec}; use super::iterate::reverse_post_order; use super::ControlFlowGraph; +use std::borrow::BorrowMut; #[cfg(test)] mod tests; -pub fn dominators(graph: &G) -> Dominators { +pub fn dominators(graph: G) -> Dominators { let start_node = graph.start_node(); - let rpo = reverse_post_order(graph, start_node); + let rpo = reverse_post_order(&graph, start_node); dominators_given_rpo(graph, &rpo) } -fn dominators_given_rpo( - graph: &G, +fn dominators_given_rpo>( + mut graph: G, rpo: &[G::Node], ) -> Dominators { - let start_node = graph.start_node(); + let start_node = graph.borrow().start_node(); assert_eq!(rpo[0], start_node); // compute the post order index (rank) for each node let mut post_order_rank: IndexVec = - (0..graph.num_nodes()).map(|_| 0).collect(); + (0..graph.borrow().num_nodes()).map(|_| 0).collect(); for (index, node) in rpo.iter().rev().cloned().enumerate() { post_order_rank[node] = index; } let mut immediate_dominators: IndexVec> = - (0..graph.num_nodes()).map(|_| None).collect(); + (0..graph.borrow().num_nodes()).map(|_| None).collect(); immediate_dominators[start_node] = Some(start_node); let mut changed = true; @@ -41,7 +42,7 @@ fn dominators_given_rpo( for &node in &rpo[1..] { let mut new_idom = None; - for pred in graph.predecessors(node) { + for pred in graph.borrow_mut().predecessors(node) { if immediate_dominators[pred].is_some() { // (*) dominators for `pred` have been calculated new_idom = Some(if let Some(new_idom) = new_idom { diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 7c0d39965fc..16d8ada9f24 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -524,6 +524,9 @@ pub fn set(&self, features: &mut Features, span: Span) { /// Allows the use of `if` and `match` in constants. (active, const_if_match, "1.41.0", Some(49146), None), + /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. + (active, cfg_sanitize, "1.41.0", Some(39699), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs index f72df00a8e8..4fa0198d871 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -25,6 +25,7 @@ macro_rules! cfg_fn { (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), + (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), ]; /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. @@ -283,7 +284,7 @@ macro_rules! experimental { ) ), ( - sym::plugin, CrateLevel, template!(List: "name|name(args)"), + sym::plugin, CrateLevel, template!(List: "name"), Gated( Stability::Deprecated( "https://github.com/rust-lang/rust/pull/64675", diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index e953a64f190..f985a5b3755 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -30,7 +30,6 @@ use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; use rustc_passes::{self, ast_validation, hir_stats, layout_test}; use rustc_plugin_impl as plugin; -use rustc_plugin_impl::registry::Registry; use rustc_privacy; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_traits; @@ -106,8 +105,7 @@ fn count_nodes(krate: &ast::Crate) -> usize { (&mut Resolver<'_>) -> (Result, ResolverOutputs) ); -/// Runs the "early phases" of the compiler: initial `cfg` processing, -/// loading compiler plugins (including those from `addl_plugins`), +/// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins, /// syntax expansion, secondary `cfg` expansion, synthesis of a test /// harness if one is to be provided, injection of a dependency on the /// standard library and prelude, and name resolution. @@ -209,33 +207,22 @@ pub fn register_plugins<'a>( middle::recursion_limit::update_limits(sess, &krate); }); - let registrars = time(sess, "plugin loading", || { - plugin::load::load_plugins( - sess, - metadata_loader, - &krate, - Some(sess.opts.debugging_opts.extra_plugins.clone()), - ) - }); - let mut lint_store = rustc_lint::new_lint_store( sess.opts.debugging_opts.no_interleave_lints, sess.unstable_options(), ); + register_lints(&sess, &mut lint_store); - (register_lints)(&sess, &mut lint_store); - - let mut registry = Registry::new(sess, &mut lint_store, krate.span); - + let registrars = time(sess, "plugin loading", || { + plugin::load::load_plugins(sess, metadata_loader, &krate) + }); time(sess, "plugin registration", || { + let mut registry = plugin::Registry { lint_store: &mut lint_store }; for registrar in registrars { - registry.args_hidden = Some(registrar.args); - (registrar.fun)(&mut registry); + registrar(&mut registry); } }); - *sess.plugin_llvm_passes.borrow_mut() = registry.llvm_passes; - Ok((krate, Lrc::new(lint_store))) } diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index d39a5d3a073..4c630b56cb4 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -650,10 +650,6 @@ fn test_debugging_options_tracking_hash() { opts.debugging_opts.continue_parse_after_error = true; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); - opts = reference.clone(); - opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")]; - assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); - opts = reference.clone(); opts.debugging_opts.force_overflow_checks = Some(true); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 5d3a6cccc4e..0fd7145f425 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -24,7 +24,7 @@ use std::fmt::Write; use rustc::hir::def::{Res, DefKind}; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, layout::VariantIdx}; use rustc::{lint, util}; use rustc::lint::FutureIncompatibleInfo; @@ -800,45 +800,6 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { } } -declare_lint! { - PLUGIN_AS_LIBRARY, - Warn, - "compiler plugin used as ordinary library in non-plugin crate" -} - -declare_lint_pass!(PluginAsLibrary => [PLUGIN_AS_LIBRARY]); - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PluginAsLibrary { - fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { - if cx.tcx.plugin_registrar_fn(LOCAL_CRATE).is_some() { - // We're compiling a plugin; it's fine to link other plugins. - return; - } - - match it.kind { - hir::ItemKind::ExternCrate(..) => (), - _ => return, - }; - - let def_id = cx.tcx.hir().local_def_id(it.hir_id); - let prfn = match cx.tcx.extern_mod_stmt_cnum(def_id) { - Some(cnum) => cx.tcx.plugin_registrar_fn(cnum), - None => { - // Probably means we aren't linking the crate for some reason. - // - // Not sure if / when this could happen. - return; - } - }; - - if prfn.is_some() { - cx.span_lint(PLUGIN_AS_LIBRARY, - it.span, - "compiler plugin used as an ordinary library"); - } - } -} - declare_lint! { NO_MANGLE_CONST_ITEMS, Deny, @@ -1268,7 +1229,6 @@ fn check_item( MISSING_DEBUG_IMPLEMENTATIONS, ANONYMOUS_PARAMETERS, UNUSED_DOC_COMMENTS, - PLUGIN_AS_LIBRARY, NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS, MUTABLE_TRANSMUTES, @@ -1490,10 +1450,10 @@ fn check_ident_token(&mut self, impl EarlyLintPass for KeywordIdents { fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) { - self.check_tokens(cx, mac_def.stream()); + self.check_tokens(cx, mac_def.body.inner_tokens()); } fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) { - self.check_tokens(cx, mac.tts.clone().into()); + self.check_tokens(cx, mac.args.inner_tokens()); } fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) { self.check_ident_token(cx, UnderMacro(false), ident); diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 7e8dc1d1679..ab4063c421c 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -157,8 +157,6 @@ macro_rules! late_lint_mod_passes { // Depends on types used in type definitions MissingCopyImplementations: MissingCopyImplementations, - PluginAsLibrary: PluginAsLibrary, - // Depends on referenced function signatures in expressions MutableTransmutes: MutableTransmutes, @@ -350,6 +348,7 @@ macro_rules! register_passes { "converted into hard error, see https://github.com/rust-lang/rust/issues/35896"); store.register_removed("nested_impl_trait", "converted into hard error, see https://github.com/rust-lang/rust/issues/59014"); + store.register_removed("plugin_as_library", "plugins have been deprecated and retired"); } fn register_internals(store: &mut lint::LintStore) { diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 820783bab6d..42db642cd4d 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -18,12 +18,11 @@ use rustc_data_structures::svh::Svh; use rustc::dep_graph::{self, DepNodeIndex}; use rustc::middle::lang_items; -use rustc::mir::{self, interpret}; +use rustc::mir::{self, BodyCache, interpret, Promoted}; use rustc::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::codec::TyDecoder; -use rustc::mir::{Body, Promoted}; use rustc::util::common::record_time; use rustc::util::captures::Captures; @@ -1080,26 +1079,32 @@ fn is_item_mir_available(&self, id: DefIndex) -> bool { self.root.per_def.mir.get(self, id).is_some() } - fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { - self.root.per_def.mir.get(self, id) + fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> BodyCache<'tcx> { + let mut cache = self.root.per_def.mir.get(self, id) .filter(|_| !self.is_proc_macro(id)) .unwrap_or_else(|| { bug!("get_optimized_mir: missing MIR for `{:?}`", self.local_def_id(id)) }) - .decode((self, tcx)) + .decode((self, tcx)); + cache.ensure_predecessors(); + cache } fn get_promoted_mir( &self, tcx: TyCtxt<'tcx>, id: DefIndex, - ) -> IndexVec> { - self.root.per_def.promoted_mir.get(self, id) + ) -> IndexVec> { + let mut cache = self.root.per_def.promoted_mir.get(self, id) .filter(|_| !self.is_proc_macro(id)) .unwrap_or_else(|| { bug!("get_promoted_mir: missing MIR for `{:?}`", self.local_def_id(id)) }) - .decode((self, tcx)) + .decode((self, tcx)); + for body in cache.iter_mut() { + body.ensure_predecessors(); + } + cache } fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs { diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index 8214153f153..13db9a6fef9 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -32,6 +32,8 @@ use syntax::source_map::Spanned; use syntax::symbol::Symbol; use syntax::expand::allocator::AllocatorKind; +use syntax::ptr::P; +use syntax::tokenstream::DelimSpan; use syntax_pos::{Span, FileName}; macro_rules! provide { @@ -427,6 +429,7 @@ pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro { let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body); let local_span = Span::with_root_ctxt(source_file.start_pos, source_file.end_pos); + let dspan = DelimSpan::from_single(local_span); let (body, mut errors) = source_file_to_stream(&sess.parse_sess, source_file, None); emit_unclosed_delims(&mut errors, &sess.parse_sess); @@ -448,7 +451,7 @@ pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro { span: local_span, attrs: attrs.iter().cloned().collect(), kind: ast::ItemKind::MacroDef(ast::MacroDef { - tokens: body.into(), + body: P(ast::MacArgs::Delimited(dspan, ast::MacDelimiter::Brace, body)), legacy: def.legacy, }), vis: source_map::respan(local_span.shrink_to_lo(), ast::VisibilityKind::Inherited), diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index 4ea562fced3..fdf43f06eb1 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -276,8 +276,8 @@ fn encode(&self, buf: &mut Encoder) -> LazyPerDefTables<'tcx> { // Also, as an optimization, a missing entry indicates an empty `&[]`. inferred_outlives: Table, Span)])>, super_predicates: Table)>, - mir: Table)>, - promoted_mir: Table>)>, + mir: Table)>, + promoted_mir: Table>)>, } #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index 94323431990..802464ce86b 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -5,7 +5,7 @@ use crate::dataflow::move_paths::MoveData; use rustc::mir::traversal; use rustc::mir::visit::{PlaceContext, Visitor, NonUseContext, MutatingUseContext}; -use rustc::mir::{self, Location, Body, Local}; +use rustc::mir::{self, Location, Body, Local, ReadOnlyBodyCache}; use rustc::ty::{RegionVid, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_index::vec::IndexVec; @@ -90,7 +90,7 @@ fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { impl LocalsStateAtExit { fn build( locals_are_invalidated_at_exit: bool, - body: &Body<'tcx>, + body: ReadOnlyBodyCache<'_, 'tcx>, move_data: &MoveData<'tcx> ) -> Self { struct HasStorageDead(BitSet); @@ -106,7 +106,8 @@ fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) { if locals_are_invalidated_at_exit { LocalsStateAtExit::AllAreInvalidated } else { - let mut has_storage_dead = HasStorageDead(BitSet::new_empty(body.local_decls.len())); + let mut has_storage_dead + = HasStorageDead(BitSet::new_empty(body.local_decls.len())); has_storage_dead.visit_body(body); let mut has_storage_dead_or_moved = has_storage_dead.0; for move_out in &move_data.moves { @@ -123,13 +124,13 @@ fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) { impl<'tcx> BorrowSet<'tcx> { pub fn build( tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, + body: ReadOnlyBodyCache<'_, 'tcx>, locals_are_invalidated_at_exit: bool, move_data: &MoveData<'tcx>, ) -> Self { let mut visitor = GatherBorrows { tcx, - body, + body: &body, idx_vec: IndexVec::new(), location_map: Default::default(), activation_map: Default::default(), @@ -139,7 +140,7 @@ pub fn build( LocalsStateAtExit::build(locals_are_invalidated_at_exit, body, move_data), }; - for (block, block_data) in traversal::preorder(body) { + for (block, block_data) in traversal::preorder(&body) { visitor.visit_basic_block_data(block, block_data); } diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 48f8ad9bbd8..73a9fd81c9b 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -205,9 +205,12 @@ pub(super) fn report_use_of_moved_or_uninitialized( ); } - let ty = - Place::ty_from(used_place.base, used_place.projection, self.body, self.infcx.tcx) - .ty; + let ty = Place::ty_from( + used_place.base, + used_place.projection, + &*self.body, + self.infcx.tcx + ).ty; let needs_note = match ty.kind { ty::Closure(id, _) => { let tables = self.infcx.tcx.typeck_tables_of(id); @@ -222,7 +225,7 @@ pub(super) fn report_use_of_moved_or_uninitialized( let mpi = self.move_data.moves[move_out_indices[0]].path; let place = &self.move_data.move_paths[mpi].place; - let ty = place.ty(self.body, self.infcx.tcx).ty; + let ty = place.ty(&*self.body, self.infcx.tcx).ty; let opt_name = self.describe_place_with_options(place.as_ref(), IncludingDowncast(true)); let note_msg = match opt_name { @@ -314,7 +317,7 @@ pub(super) fn report_move_out_while_borrowed( None, ).add_explanation_to_diagnostic( self.infcx.tcx, - self.body, + &self.body, &self.local_names, &mut err, "", @@ -356,7 +359,7 @@ pub(super) fn report_use_while_mutably_borrowed( self.explain_why_borrow_contains_point(location, borrow, None) .add_explanation_to_diagnostic( self.infcx.tcx, - self.body, + &self.body, &self.local_names, &mut err, "", @@ -578,7 +581,7 @@ pub(super) fn report_conflicting_borrow( explanation.add_explanation_to_diagnostic( self.infcx.tcx, - self.body, + &self.body, &self.local_names, &mut err, first_borrow_desc, @@ -619,7 +622,12 @@ pub(super) fn describe_place_for_conflicting_borrow( // Define a small closure that we can use to check if the type of a place // is a union. let union_ty = |place_base, place_projection| { - let ty = Place::ty_from(place_base, place_projection, self.body, self.infcx.tcx).ty; + let ty = Place::ty_from( + place_base, + place_projection, + &*self.body, + self.infcx.tcx + ).ty; ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty) }; let describe_place = |place| self.describe_place(place).unwrap_or_else(|| "_".to_owned()); @@ -965,7 +973,7 @@ fn report_local_value_does_not_live_long_enough( } else { explanation.add_explanation_to_diagnostic( self.infcx.tcx, - self.body, + &self.body, &self.local_names, &mut err, "", @@ -991,7 +999,7 @@ fn report_local_value_does_not_live_long_enough( ); explanation.add_explanation_to_diagnostic( - self.infcx.tcx, self.body, &self.local_names, &mut err, "", None); + self.infcx.tcx, &self.body, &self.local_names, &mut err, "", None); } err @@ -1051,7 +1059,7 @@ fn report_borrow_conflicts_with_destructor( explanation.add_explanation_to_diagnostic( self.infcx.tcx, - self.body, + &self.body, &self.local_names, &mut err, "", @@ -1138,7 +1146,7 @@ fn report_temporary_value_does_not_live_long_enough( } explanation.add_explanation_to_diagnostic( self.infcx.tcx, - self.body, + &self.body, &self.local_names, &mut err, "", @@ -1174,11 +1182,12 @@ fn try_report_cannot_return_reference_to_local( }; // FIXME use a better heuristic than Spans - let reference_desc = if return_span == self.body.source_info(borrow.reserve_location).span { - "reference to" - } else { - "value referencing" - }; + let reference_desc + = if return_span == self.body.source_info(borrow.reserve_location).span { + "reference to" + } else { + "value referencing" + }; let (place_desc, note) = if let Some(place_desc) = opt_place_desc { let local_kind = if let Some(local) = borrow.borrowed_place.as_local() { @@ -1372,10 +1381,8 @@ fn report_escaping_data( } fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec { - let body = self.body; - let mut stack = Vec::new(); - stack.extend(body.predecessor_locations(location).map(|predecessor| { + stack.extend(self.body.predecessor_locations(location).map(|predecessor| { let is_back_edge = location.dominates(predecessor, &self.dominators); (predecessor, is_back_edge) })); @@ -1394,7 +1401,7 @@ fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec Vec Vec) -> StorageDeadOr StorageDeadOrDrop::LocalStorageDead | StorageDeadOrDrop::BoxedStorageDead => { assert!( - Place::ty_from(&place.base, proj_base, self.body, tcx).ty.is_box(), + Place::ty_from( + &place.base, + proj_base, + &*self.body, + tcx + ).ty.is_box(), "Drop of value behind a reference or raw pointer" ); StorageDeadOrDrop::BoxedStorageDead @@ -1633,7 +1645,12 @@ fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOr StorageDeadOrDrop::Destructor(_) => base_access, }, ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { - let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty; + let base_ty = Place::ty_from( + &place.base, + proj_base, + &*self.body, + tcx + ).ty; match base_ty.kind { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor @@ -1678,7 +1695,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { } } let mut visitor = FakeReadCauseFinder { place, cause: None }; - visitor.visit_body(&self.body); + visitor.visit_body(self.body); match visitor.cause { Some(FakeReadCause::ForMatchGuard) => Some("match guard"), Some(FakeReadCause::ForIndex) => Some("indexing expression"), @@ -1736,7 +1753,8 @@ fn annotate_argument_and_return_for_borrow( // Next, look through the rest of the block, checking if we are assigning the // `target` (that is, the place that contains our borrow) to anything. let mut annotated_closure = None; - for stmt in &self.body[location.block].statements[location.statement_index + 1..] { + for stmt in &self.body[location.block].statements[location.statement_index + 1..] + { debug!( "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}", target, stmt diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index a555e0b74c2..cc15d236b23 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -369,8 +369,11 @@ fn describe_field(&self, place: PlaceRef<'cx, 'tcx>, field: Field) -> String { }, field) } ProjectionElem::Downcast(_, variant_index) => { - let base_ty = - Place::ty_from(place.base, place.projection, self.body, self.infcx.tcx).ty; + let base_ty = Place::ty_from( + place.base, + place.projection, + &*self.body, + self.infcx.tcx).ty; self.describe_field_from_ty(&base_ty, field, Some(*variant_index)) } ProjectionElem::Field(_, field_type) => { @@ -498,9 +501,10 @@ pub(super) fn borrowed_content_source( }, .. }) = bbd.terminator { - if let Some(source) - = BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx) - { + if let Some(source) = BorrowedContentSource::from_call( + func.ty(&*self.body, tcx), + tcx + ) { return source; } } @@ -512,7 +516,12 @@ pub(super) fn borrowed_content_source( // If we didn't find an overloaded deref or index, then assume it's a // built in deref and check the type of the base. - let base_ty = Place::ty_from(deref_base.base, deref_base.projection, self.body, tcx).ty; + let base_ty = Place::ty_from( + deref_base.base, + deref_base.projection, + &*self.body, + tcx + ).ty; if base_ty.is_unsafe_ptr() { BorrowedContentSource::DerefRawPointer } else if base_ty.is_mutable_ptr() { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 649aeac12de..da08de7690a 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -9,8 +9,8 @@ use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT}; use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc::mir::{ - ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceElem, - PlaceRef, Static, StaticKind + ClearCrossCrate, Local, Location, Body, BodyCache, Mutability, Operand, Place, PlaceBase, + PlaceElem, PlaceRef, ReadOnlyBodyCache, Static, StaticKind, read_only }; use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; @@ -102,7 +102,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> BorrowCheckResult<'_> { fn do_mir_borrowck<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, input_body: &Body<'tcx>, - input_promoted: &IndexVec>, + input_promoted: &IndexVec>, def_id: DefId, ) -> BorrowCheckResult<'tcx> { debug!("do_mir_borrowck(def_id = {:?})", def_id); @@ -162,16 +162,22 @@ fn do_mir_borrowck<'a, 'tcx>( // requires first making our own copy of the MIR. This copy will // be modified (in place) to contain non-lexical lifetimes. It // will have a lifetime tied to the inference context. - let mut body: Body<'tcx> = input_body.clone(); - let mut promoted: IndexVec> = input_promoted.clone(); + let body_clone: Body<'tcx> = input_body.clone(); + let mut promoted = input_promoted.clone(); + let mut body = BodyCache::new(body_clone); let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted); - let body = &body; // no further changes - let location_table = &LocationTable::new(body); + let body = read_only!(body); // no further changes + let promoted: IndexVec<_, _> = promoted + .iter_mut() + .map(|body| read_only!(body)) + .collect(); + + let location_table = &LocationTable::new(&body); let mut errors_buffer = Vec::new(); let (move_data, move_errors): (MoveData<'tcx>, Option, MoveError<'tcx>)>>) = - match MoveData::gather_moves(body, tcx) { + match MoveData::gather_moves(&body, tcx) { Ok(move_data) => (move_data, None), Err((move_data, move_errors)) => (move_data, Some(move_errors)), }; @@ -184,17 +190,17 @@ fn do_mir_borrowck<'a, 'tcx>( let dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); let mut flow_inits = FlowAtLocation::new(do_dataflow( tcx, - body, + &body, def_id, &attributes, &dead_unwinds, - MaybeInitializedPlaces::new(tcx, body, &mdpe), + MaybeInitializedPlaces::new(tcx, &body, &mdpe), |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]), )); let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(id).is_fn_or_closure(); let borrow_set = Rc::new(BorrowSet::build( - tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); + tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); // If we are in non-lexical mode, compute the non-lexical lifetimes. let (regioncx, polonius_output, opt_closure_req) = nll::compute_regions( @@ -222,29 +228,29 @@ fn do_mir_borrowck<'a, 'tcx>( let flow_borrows = FlowAtLocation::new(do_dataflow( tcx, - body, + &body, def_id, &attributes, &dead_unwinds, - Borrows::new(tcx, body, param_env, regioncx.clone(), &borrow_set), + Borrows::new(tcx, &body, param_env, regioncx.clone(), &borrow_set), |rs, i| DebugFormatted::new(&rs.location(i)), )); let flow_uninits = FlowAtLocation::new(do_dataflow( tcx, - body, + &body, def_id, &attributes, &dead_unwinds, - MaybeUninitializedPlaces::new(tcx, body, &mdpe), + MaybeUninitializedPlaces::new(tcx, &body, &mdpe), |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]), )); let flow_ever_inits = FlowAtLocation::new(do_dataflow( tcx, - body, + &body, def_id, &attributes, &dead_unwinds, - EverInitializedPlaces::new(tcx, body, &mdpe), + EverInitializedPlaces::new(tcx, &body, &mdpe), |bd, i| DebugFormatted::new(&bd.move_data().inits[i]), )); @@ -300,11 +306,10 @@ fn do_mir_borrowck<'a, 'tcx>( let mut initial_diag = mbcx.report_conflicting_borrow(location, (&place, span), bk, &borrow); - let lint_root = if let ClearCrossCrate::Set(ref vsi) = mbcx.body.source_scope_local_data { - let scope = mbcx.body.source_info(location).scope; - vsi[scope].lint_root - } else { - id + let scope = mbcx.body.source_info(location).scope; + let lint_root = match &mbcx.body.source_scopes[scope].local_data { + ClearCrossCrate::Set(data) => data.lint_root, + _ => id, }; // Span and message don't matter; we overwrite them below anyway @@ -337,39 +342,42 @@ fn do_mir_borrowck<'a, 'tcx>( debug!("mbcx.used_mut: {:?}", mbcx.used_mut); let used_mut = mbcx.used_mut; - for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) { - if let ClearCrossCrate::Set(ref vsi) = mbcx.body.source_scope_local_data { - let local_decl = &mbcx.body.local_decls[local]; - - // Skip over locals that begin with an underscore or have no name - match mbcx.local_names[local] { - Some(name) => if name.as_str().starts_with("_") { - continue; - }, - None => continue, - } + for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) + { + let local_decl = &mbcx.body.local_decls[local]; + let lint_root = match &mbcx.body.source_scopes[local_decl.source_info.scope].local_data { + ClearCrossCrate::Set(data) => data.lint_root, + _ => continue, + }; - let span = local_decl.source_info.span; - if span.desugaring_kind().is_some() { - // If the `mut` arises as part of a desugaring, we should ignore it. + // Skip over locals that begin with an underscore or have no name + match mbcx.local_names[local] { + Some(name) => if name.as_str().starts_with("_") { continue; - } + }, + None => continue, + } - let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); - tcx.struct_span_lint_hir( - UNUSED_MUT, - vsi[local_decl.source_info.scope].lint_root, - span, - "variable does not need to be mutable", - ) - .span_suggestion_short( - mut_span, - "remove this `mut`", - String::new(), - Applicability::MachineApplicable, - ) - .emit(); + let span = local_decl.source_info.span; + if span.desugaring_kind().is_some() { + // If the `mut` arises as part of a desugaring, we should ignore it. + continue; } + + let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); + tcx.struct_span_lint_hir( + UNUSED_MUT, + lint_root, + span, + "variable does not need to be mutable", + ) + .span_suggestion_short( + mut_span, + "remove this `mut`", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); } // Buffer any move errors that we collected and de-duplicated. @@ -397,7 +405,7 @@ fn do_mir_borrowck<'a, 'tcx>( crate struct MirBorrowckCtxt<'cx, 'tcx> { crate infcx: &'cx InferCtxt<'cx, 'tcx>, - body: &'cx Body<'tcx>, + body: ReadOnlyBodyCache<'cx, 'tcx>, mir_def_id: DefId, param_env: ty::ParamEnv<'tcx>, move_data: &'cx MoveData<'tcx>, @@ -488,7 +496,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx type FlowState = Flows<'cx, 'tcx>; fn body(&self) -> &'cx Body<'tcx> { - self.body + self.body.body() } fn visit_block_entry(&mut self, bb: BasicBlock, flow_state: &Self::FlowState) { @@ -638,7 +646,7 @@ fn visit_terminator_entry( let tcx = self.infcx.tcx; // Compute the type with accurate region information. - let drop_place_ty = drop_place.ty(self.body, self.infcx.tcx); + let drop_place_ty = drop_place.ty(&*self.body, self.infcx.tcx); // Erase the regions. let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty).ty; @@ -983,6 +991,7 @@ fn check_access_for_conflict( let mut error_reported = false; let tcx = self.infcx.tcx; let body = self.body; + let body: &Body<'_> = &body; let param_env = self.param_env; let location_table = self.location_table.start_index(location); let borrow_set = self.borrow_set.clone(); @@ -1333,7 +1342,8 @@ fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) { _ => bug!("temporary initialized in arguments"), }; - let bbd = &self.body[loc.block]; + let body = self.body; + let bbd = &body[loc.block]; let stmt = &bbd.statements[loc.statement_index]; debug!("temporary assigned in: stmt={:?}", stmt); @@ -1452,7 +1462,7 @@ fn check_for_invalidation_at_exit( if places_conflict::borrow_conflicts_with_place( self.infcx.tcx, self.param_env, - self.body, + &self.body, place, borrow.kind, root_place, @@ -1743,7 +1753,7 @@ fn check_if_assigned_path_is_moved( // assigning to `P.f` requires `P` itself // be already initialized let tcx = self.infcx.tcx; - let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty; + let base_ty = Place::ty_from(&place.base, proj_base, self.body(), tcx).ty; match base_ty.kind { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( @@ -1850,7 +1860,7 @@ fn check_parent_of_field<'cx, 'tcx>( // of the union - we should error in that case. let tcx = this.infcx.tcx; if let ty::Adt(def, _) = - Place::ty_from(base.base, base.projection, this.body, tcx).ty.kind + Place::ty_from(base.base, base.projection, this.body(), tcx).ty.kind { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { @@ -2120,7 +2130,7 @@ fn is_mutable<'d>( match elem { ProjectionElem::Deref => { let base_ty = - Place::ty_from(place.base, proj_base, self.body, self.infcx.tcx).ty; + Place::ty_from(place.base, proj_base, self.body(), self.infcx.tcx).ty; // Check the kind of deref to decide match base_ty.kind { @@ -2260,7 +2270,7 @@ pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Optio match place_projection { [base @ .., ProjectionElem::Field(field, _ty)] => { let tcx = self.infcx.tcx; - let base_ty = Place::ty_from(place_ref.base, base, self.body, tcx).ty; + let base_ty = Place::ty_from(place_ref.base, base, self.body(), tcx).ty; if (base_ty.is_closure() || base_ty.is_generator()) && (!by_ref || self.upvars[field.index()].by_ref) { diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index bf61eb9f0c5..388a8abd5fc 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -300,7 +300,7 @@ fn report_cannot_move_from_borrowed_content( // Inspect the type of the content behind the // borrow to provide feedback about why this // was a move rather than a copy. - let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty; + let ty = deref_target_place.ty(&*self.body, self.infcx.tcx).ty; let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All) .find_map(|p| self.is_upvar_field_projection(p)); @@ -411,7 +411,7 @@ fn report_cannot_move_from_borrowed_content( }; let move_ty = format!( "{:?}", - move_place.ty(self.body, self.infcx.tcx).ty, + move_place.ty(&*self.body, self.infcx.tcx).ty, ); if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { let is_option = move_ty.starts_with("std::option::Option"); @@ -454,7 +454,7 @@ fn add_move_hints( } if binds_to.is_empty() { - let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; + let place_ty = move_from.ty(&*self.body, self.infcx.tcx).ty; let place_desc = match self.describe_place(move_from.as_ref()) { Some(desc) => format!("`{}`", desc), None => format!("value"), @@ -482,7 +482,7 @@ fn add_move_hints( // No binding. Nothing to suggest. GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => { let span = use_spans.var_or_use(); - let place_ty = original_path.ty(self.body, self.infcx.tcx).ty; + let place_ty = original_path.ty(&*self.body, self.infcx.tcx).ty; let place_desc = match self.describe_place(original_path.as_ref()) { Some(desc) => format!("`{}`", desc), None => format!("value"), diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index bf070c3f07d..e135f8d1be9 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -1,6 +1,6 @@ use rustc::hir; use rustc::hir::Node; -use rustc::mir::{self, Body, ClearCrossCrate, Local, LocalInfo, Location}; +use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyCache}; use rustc::mir::{Mutability, Place, PlaceRef, PlaceBase, ProjectionElem}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_index::vec::Idx; @@ -61,8 +61,12 @@ pub(super) fn report_mutability_error( projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], } => { debug_assert!(is_closure_or_generator( - Place::ty_from(&the_place_err.base, proj_base, self.body, self.infcx.tcx).ty - )); + Place::ty_from( + &the_place_err.base, + proj_base, + &*self.body, + self.infcx.tcx + ).ty)); item_msg = format!("`{}`", access_place_desc.unwrap()); if self.is_upvar_field_projection(access_place.as_ref()).is_some() { @@ -111,7 +115,7 @@ pub(super) fn report_mutability_error( Place::ty_from( the_place_err.base, the_place_err.projection, - self.body, + &*self.body, self.infcx.tcx ) .ty @@ -225,7 +229,7 @@ pub(super) fn report_mutability_error( if let Some((span, message)) = annotate_struct_field( self.infcx.tcx, - Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty, + Place::ty_from(base, proj_base, &*self.body, self.infcx.tcx).ty, field, ) { err.span_suggestion( @@ -300,7 +304,7 @@ pub(super) fn report_mutability_error( projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], } => { debug_assert!(is_closure_or_generator( - Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty + Place::ty_from(base, proj_base, &*self.body, self.infcx.tcx).ty )); err.span_label(span, format!("cannot {ACT}", ACT = act)); @@ -529,7 +533,7 @@ fn suggest_ampmut_self<'tcx>( // by trying (3.), then (2.) and finally falling back on (1.). fn suggest_ampmut<'tcx>( tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, + body: ReadOnlyBodyCache<'_, 'tcx>, local: Local, local_decl: &mir::LocalDecl<'tcx>, opt_ty_info: Option, diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index c7058531958..43aabac00bc 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -237,7 +237,7 @@ pub(in crate::borrow_check) fn explain_why_borrow_contains_point( ); let regioncx = &self.nonlexical_regioncx; - let body = self.body; + let body: &Body<'_> = &self.body; let tcx = self.infcx.tcx; let borrow_region_vid = borrow.region; @@ -297,9 +297,9 @@ pub(in crate::borrow_check) fn explain_why_borrow_contains_point( if let Some(region) = regioncx.to_error_region_vid(borrow_region_vid) { let (category, from_closure, span, region_name) = self.nonlexical_regioncx.free_region_constraint_info( - self.body, - &self.local_names, - &self.upvars, + &self.body, + &self.local_names, + &self.upvars, self.mir_def_id, self.infcx, borrow_region_vid, diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 1d429e3a6de..98679f236db 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -11,7 +11,7 @@ use crate::dataflow::indexes::BorrowIndex; use rustc::ty::{self, TyCtxt}; use rustc::mir::visit::Visitor; -use rustc::mir::{BasicBlock, Location, Body, Place, Rvalue}; +use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyCache, Rvalue}; use rustc::mir::{Statement, StatementKind}; use rustc::mir::TerminatorKind; use rustc::mir::{Operand, BorrowKind}; @@ -22,7 +22,7 @@ pub(super) fn generate_invalidates<'tcx>( param_env: ty::ParamEnv<'tcx>, all_facts: &mut Option, location_table: &LocationTable, - body: &Body<'tcx>, + body: ReadOnlyBodyCache<'_, 'tcx>, borrow_set: &BorrowSet<'tcx>, ) { if all_facts.is_none() { @@ -38,7 +38,7 @@ pub(super) fn generate_invalidates<'tcx>( param_env, tcx, location_table, - body, + body: &body, dominators, }; ig.visit_body(body); diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 4d67b72c98c..16182fe24fa 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -12,7 +12,8 @@ use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, - Local, Location, Body, LocalKind, BasicBlock, Promoted}; + Local, Location, Body, BodyCache, LocalKind, BasicBlock, + Promoted, ReadOnlyBodyCache}; use rustc::ty::{self, RegionKind, RegionVid}; use rustc_index::vec::IndexVec; use rustc_errors::Diagnostic; @@ -54,8 +55,8 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, def_id: DefId, param_env: ty::ParamEnv<'tcx>, - body: &mut Body<'tcx>, - promoted: &mut IndexVec>, + body: &mut BodyCache<'tcx>, + promoted: &mut IndexVec>, ) -> UniversalRegions<'tcx> { debug!("replace_regions_in_mir(def_id={:?})", def_id); @@ -157,8 +158,8 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, def_id: DefId, universal_regions: UniversalRegions<'tcx>, - body: &Body<'tcx>, - promoted: &IndexVec>, + body: ReadOnlyBodyCache<'_, 'tcx>, + promoted: &IndexVec>, local_names: &IndexVec>, upvars: &[Upvar], location_table: &LocationTable, @@ -180,7 +181,8 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( let universal_regions = Rc::new(universal_regions); - let elements = &Rc::new(RegionValueElements::new(body)); + let elements + = &Rc::new(RegionValueElements::new(&body)); // Run the MIR type-checker. let MirTypeckResults { @@ -205,7 +207,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( all_facts .universal_region .extend(universal_regions.universal_regions()); - populate_polonius_move_facts(all_facts, move_data, location_table, body); + populate_polonius_move_facts(all_facts, move_data, location_table, &body); } // Create the region inference context, taking ownership of the @@ -238,7 +240,6 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( universal_regions, placeholder_indices, universal_region_relations, - body, outlives_constraints, member_constraints, closure_bounds_mapping, @@ -253,7 +254,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( param_env, &mut all_facts, location_table, - &body, + body, borrow_set, ); @@ -283,7 +284,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( // Solve the region constraints. let closure_region_requirements = - regioncx.solve(infcx, body, local_names, upvars, def_id, errors_buffer); + regioncx.solve(infcx, &body, local_names, upvars, def_id, errors_buffer); // Dump MIR results into a file, if that is enabled. This let us // write unit-tests, as well as helping with debugging. @@ -297,7 +298,13 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( // We also have a `#[rustc_nll]` annotation that causes us to dump // information - dump_annotation(infcx, &body, def_id, ®ioncx, &closure_region_requirements, errors_buffer); + dump_annotation( + infcx, + &body, + def_id, + ®ioncx, + &closure_region_requirements, + errors_buffer); (regioncx, polonius_output, closure_region_requirements) } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index d44e85fa790..bd9e97e5b63 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -239,7 +239,6 @@ pub(crate) fn new( universal_regions: Rc>, placeholder_indices: Rc, universal_region_relations: Rc>, - _body: &Body<'tcx>, outlives_constraints: OutlivesConstraintSet, member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, closure_bounds_mapping: FxHashMap< diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 7a86536573d..b4414c514c5 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -1,4 +1,4 @@ -use rustc::mir::{BasicBlock, Location, Body}; +use rustc::mir::{BasicBlock, Location, Body, ReadOnlyBodyCache}; use rustc::ty::{self, RegionVid}; use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix}; use rustc_data_structures::fx::FxHashMap; @@ -92,7 +92,7 @@ impl RegionValueElements { /// Pushes all predecessors of `index` onto `stack`. crate fn push_predecessors( &self, - body: &Body<'_>, + body: ReadOnlyBodyCache<'_, '_>, index: PointIndex, stack: &mut Vec, ) { diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index d949c7e01aa..db15d2c54fd 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -1,6 +1,6 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::mir::{Body, Location, PlaceElem, Promoted}; +use rustc::mir::{BodyCache, Location, PlaceElem, Promoted}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc_index::vec::IndexVec; @@ -9,8 +9,8 @@ /// inference variables, returning the number of variables created. pub fn renumber_mir<'tcx>( infcx: &InferCtxt<'_, 'tcx>, - body: &mut Body<'tcx>, - promoted: &mut IndexVec>, + body: &mut BodyCache<'tcx>, + promoted: &mut IndexVec>, ) { debug!("renumber_mir()"); debug!("renumber_mir: body.arg_count={:?}", body.arg_count); diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs index 7dee00b3eca..d6aa31449da 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs @@ -1,7 +1,7 @@ use crate::borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements}; use crate::util::liveness::{categorize, DefUse}; use rustc::mir::visit::{PlaceContext, Visitor}; -use rustc::mir::{Body, Local, Location}; +use rustc::mir::{Local, Location, ReadOnlyBodyCache}; use rustc_index::vec::{Idx, IndexVec}; use rustc_data_structures::vec_linked_list as vll; @@ -60,7 +60,7 @@ impl LocalUseMap { crate fn build( live_locals: &Vec, elements: &RegionValueElements, - body: &Body<'_>, + body: ReadOnlyBodyCache<'_, '_>, ) -> Self { let nones = IndexVec::from_elem_n(None, body.local_decls.len()); let mut local_use_map = LocalUseMap { diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs index a01b528833b..dfd505f6b61 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs @@ -7,7 +7,7 @@ use crate::dataflow::move_paths::MoveData; use crate::dataflow::FlowAtLocation; use crate::dataflow::MaybeInitializedPlaces; -use rustc::mir::{Body, Local}; +use rustc::mir::{Body, Local, ReadOnlyBodyCache}; use rustc::ty::{RegionVid, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use std::rc::Rc; @@ -28,7 +28,7 @@ /// performed before pub(super) fn generate<'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, - body: &Body<'tcx>, + body: ReadOnlyBodyCache<'_, 'tcx>, elements: &Rc, flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>, move_data: &MoveData<'tcx>, @@ -41,10 +41,9 @@ pub(super) fn generate<'tcx>( &typeck.borrowck_context.universal_regions, &typeck.borrowck_context.constraints.outlives_constraints, ); - let live_locals = compute_live_locals(typeck.tcx(), &free_regions, body); + let live_locals = compute_live_locals(typeck.tcx(), &free_regions, &body); let facts_enabled = AllFacts::enabled(typeck.tcx()); - let polonius_drop_used = if facts_enabled { let mut drop_used = Vec::new(); polonius::populate_access_facts( diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs index 526ad7fb905..e67de6c99f0 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs @@ -3,7 +3,7 @@ use crate::dataflow::move_paths::{LookupResult, MoveData}; use crate::util::liveness::{categorize, DefUse}; use rustc::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; -use rustc::mir::{Body, Local, Location, Place}; +use rustc::mir::{Local, Location, Place, ReadOnlyBodyCache}; use rustc::ty::subst::GenericArg; use rustc::ty::Ty; @@ -97,7 +97,7 @@ fn add_var_uses_regions(typeck: &mut TypeChecker<'_, 'tcx>, local: Local, ty: Ty pub(super) fn populate_access_facts( typeck: &mut TypeChecker<'_, 'tcx>, - body: &Body<'tcx>, + body: ReadOnlyBodyCache<'_, 'tcx>, location_table: &LocationTable, move_data: &MoveData<'_>, drop_used: &mut Vec<(Local, Location)>, diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs index eacc4d084db..229cbed64c2 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs @@ -7,7 +7,7 @@ use crate::dataflow::move_paths::MoveData; use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces}; use rustc::infer::canonical::QueryRegionConstraints; -use rustc::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; +use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, ReadOnlyBodyCache}; use rustc::traits::query::dropck_outlives::DropckOutlivesResult; use rustc::traits::query::type_op::outlives::DropckOutlives; use rustc::traits::query::type_op::TypeOp; @@ -32,7 +32,7 @@ /// this respects `#[may_dangle]` annotations). pub(super) fn trace( typeck: &mut TypeChecker<'_, 'tcx>, - body: &Body<'tcx>, + body: ReadOnlyBodyCache<'_, 'tcx>, elements: &Rc, flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>, move_data: &MoveData<'tcx>, @@ -71,7 +71,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { elements: &'me RegionValueElements, /// MIR we are analyzing. - body: &'me Body<'tcx>, + body: ReadOnlyBodyCache<'me, 'tcx>, /// Mapping to/from the various indices used for initialization tracking. move_data: &'me MoveData<'tcx>, @@ -302,7 +302,8 @@ fn compute_drop_live_points_for_block(&mut self, mpi: MovePathIndex, term_point: } } - for &pred_block in self.cx.body.predecessors_for(block).iter() { + let body = self.cx.body; + for &pred_block in body.predecessors_for(block).iter() { debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,); // Check whether the variable is (at least partially) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 99bcfa9bc25..a554867389e 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1,57 +1,59 @@ //! This pass type-checks the MIR to ensure it is not broken. -use crate::borrow_check::borrow_set::BorrowSet; -use crate::borrow_check::location::LocationTable; -use crate::borrow_check::nll::constraints::{OutlivesConstraintSet, OutlivesConstraint}; -use crate::borrow_check::nll::member_constraints::MemberConstraintSet; -use crate::borrow_check::nll::facts::AllFacts; -use crate::borrow_check::nll::region_infer::values::LivenessValues; -use crate::borrow_check::nll::region_infer::values::PlaceholderIndex; -use crate::borrow_check::nll::region_infer::values::PlaceholderIndices; -use crate::borrow_check::nll::region_infer::values::RegionValueElements; -use crate::borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest}; -use crate::borrow_check::nll::renumber; -use crate::borrow_check::nll::type_check::free_region_relations::{ - CreateResult, UniversalRegionRelations, -}; -use crate::borrow_check::nll::universal_regions::{DefiningTy, UniversalRegions}; -use crate::borrow_check::nll::ToRegionVid; -use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute; -use crate::dataflow::move_paths::MoveData; -use crate::dataflow::FlowAtLocation; -use crate::dataflow::MaybeInitializedPlaces; +use std::{fmt, iter, mem}; +use std::rc::Rc; + use either::Either; + use rustc::hir; use rustc::hir::def_id::DefId; +use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin}; use rustc::infer::canonical::QueryRegionConstraints; use rustc::infer::outlives::env::RegionBoundPairs; -use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin}; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::mir::*; use rustc::mir::interpret::PanicInfo; use rustc::mir::tcx::PlaceTy; -use rustc::mir::visit::{PlaceContext, Visitor, NonMutatingUseContext}; -use rustc::mir::*; +use rustc::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; +use rustc::traits::{self, ObligationCause, PredicateObligations}; +use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::query::type_op; use rustc::traits::query::type_op::custom::CustomTypeOp; -use rustc::traits::query::{Fallible, NoSolution}; -use rustc::traits::{self, ObligationCause, PredicateObligations}; -use rustc::ty::adjustment::{PointerCast}; -use rustc::ty::cast::CastTy; -use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::{Subst, SubstsRef, GenericArgKind, UserSubsts}; use rustc::ty::{ - self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, UserType, - CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, + self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPolyTraitRef, Ty, + TyCtxt, UserType, UserTypeAnnotationIndex, }; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_index::vec::{IndexVec, Idx}; +use rustc::ty::adjustment::PointerCast; +use rustc::ty::cast::CastTy; +use rustc::ty::fold::TypeFoldable; use rustc::ty::layout::VariantIdx; -use std::rc::Rc; -use std::{fmt, iter, mem}; -use syntax_pos::{Span, DUMMY_SP}; - +use rustc::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_error_codes::*; +use rustc_index::vec::{Idx, IndexVec}; +use syntax_pos::{DUMMY_SP, Span}; + +use crate::borrow_check::borrow_set::BorrowSet; +use crate::borrow_check::location::LocationTable; +use crate::borrow_check::nll::constraints::{OutlivesConstraint, OutlivesConstraintSet}; +use crate::borrow_check::nll::facts::AllFacts; +use crate::borrow_check::nll::member_constraints::MemberConstraintSet; +use crate::borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest}; +use crate::borrow_check::nll::region_infer::values::LivenessValues; +use crate::borrow_check::nll::region_infer::values::PlaceholderIndex; +use crate::borrow_check::nll::region_infer::values::PlaceholderIndices; +use crate::borrow_check::nll::region_infer::values::RegionValueElements; +use crate::borrow_check::nll::renumber; +use crate::borrow_check::nll::ToRegionVid; +use crate::borrow_check::nll::type_check::free_region_relations::{ + CreateResult, UniversalRegionRelations, +}; +use crate::borrow_check::nll::universal_regions::{DefiningTy, UniversalRegions}; +use crate::dataflow::FlowAtLocation; +use crate::dataflow::MaybeInitializedPlaces; +use crate::dataflow::move_paths::MoveData; +use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute; macro_rules! span_mirbug { ($context:expr, $elem:expr, $($message:tt)*) => ({ @@ -115,8 +117,8 @@ macro_rules! span_mirbug_and_err { pub(crate) fn type_check<'tcx>( infcx: &InferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, - body: &Body<'tcx>, - promoted: &IndexVec>, + body: ReadOnlyBodyCache<'_, 'tcx>, + promoted: &IndexVec>, mir_def_id: DefId, universal_regions: &Rc>, location_table: &LocationTable, @@ -168,8 +170,17 @@ pub(crate) fn type_check<'tcx>( &mut borrowck_context, &universal_region_relations, |mut cx| { - cx.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output); - liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); + cx.equate_inputs_and_outputs( + &body, + universal_regions, + &normalized_inputs_and_output); + liveness::generate( + &mut cx, + body, + elements, + flow_inits, + move_data, + location_table); translate_outlives_facts(cx.borrowck_context); }, @@ -185,17 +196,17 @@ fn type_check_internal<'a, 'tcx, R>( infcx: &'a InferCtxt<'a, 'tcx>, mir_def_id: DefId, param_env: ty::ParamEnv<'tcx>, - body: &'a Body<'tcx>, - promoted: &'a IndexVec>, + body: ReadOnlyBodyCache<'a, 'tcx>, + promoted: &'a IndexVec>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, universal_region_relations: &'a UniversalRegionRelations<'tcx>, mut extra: impl FnMut(&mut TypeChecker<'a, 'tcx>) -> R, -) -> R where { +) -> R { let mut checker = TypeChecker::new( infcx, - body, + body.body(), mir_def_id, param_env, region_bound_pairs, @@ -204,7 +215,7 @@ fn type_check_internal<'a, 'tcx, R>( universal_region_relations, ); let errors_reported = { - let mut verifier = TypeVerifier::new(&mut checker, body, promoted); + let mut verifier = TypeVerifier::new(&mut checker, body.body(), promoted); verifier.visit_body(body); verifier.errors_reported }; @@ -261,7 +272,7 @@ enum FieldAccessError { struct TypeVerifier<'a, 'b, 'tcx> { cx: &'a mut TypeChecker<'b, 'tcx>, body: &'b Body<'tcx>, - promoted: &'b IndexVec>, + promoted: &'b IndexVec>, last_span: Span, mir_def_id: DefId, errors_reported: bool, @@ -385,7 +396,7 @@ fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { } } - fn visit_body(&mut self, body: &Body<'tcx>) { + fn visit_body(&mut self, body: ReadOnlyBodyCache<'_, 'tcx>) { self.sanitize_type(&"return type", body.return_ty()); for local_decl in &body.local_decls { self.sanitize_type(local_decl, local_decl.ty); @@ -401,7 +412,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { fn new( cx: &'a mut TypeChecker<'b, 'tcx>, body: &'b Body<'tcx>, - promoted: &'b IndexVec>, + promoted: &'b IndexVec>, ) -> Self { TypeVerifier { body, @@ -464,10 +475,10 @@ fn sanitize_place( match kind { StaticKind::Promoted(promoted, _) => { if !self.errors_reported { - let promoted_body = &self.promoted[*promoted]; - self.sanitize_promoted(promoted_body, location); + let promoted_body_cache = self.promoted[*promoted]; + self.sanitize_promoted(promoted_body_cache, location); - let promoted_ty = promoted_body.return_ty(); + let promoted_ty = promoted_body_cache.return_ty(); check_err(self, place, promoted_ty, san_ty); } } @@ -535,12 +546,16 @@ fn sanitize_place( place_ty } - fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) { + fn sanitize_promoted( + &mut self, + promoted_body: ReadOnlyBodyCache<'b, 'tcx>, + location: Location + ) { // Determine the constraints from the promoted MIR by running the type // checker on the promoted MIR, then transfer the constraints back to // the main MIR, changing the locations to the provided location. - let parent_body = mem::replace(&mut self.body, promoted_body); + let parent_body = mem::replace(&mut self.body, promoted_body.body()); // Use new sets of constraints and closure bounds so that we can // modify their locations. @@ -548,7 +563,7 @@ fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Locatio let mut constraints = Default::default(); let mut closure_bounds = Default::default(); let mut liveness_constraints = LivenessValues::new( - Rc::new(RegionValueElements::new(promoted_body)), + Rc::new(RegionValueElements::new(&promoted_body)), ); // Don't try to add borrow_region facts for the promoted MIR @@ -1361,7 +1376,12 @@ fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } - fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) { + fn check_stmt( + &mut self, + body: ReadOnlyBodyCache<'_, 'tcx>, + stmt: &Statement<'tcx>, + location: Location) + { debug!("check_stmt: {:?}", stmt); let tcx = self.tcx(); match stmt.kind { @@ -1393,9 +1413,9 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo _ => ConstraintCategory::Assignment, }; - let place_ty = place.ty(body, tcx).ty; + let place_ty = place.ty(&*body, tcx).ty; let place_ty = self.normalize(place_ty, location); - let rv_ty = rv.ty(body, tcx); + let rv_ty = rv.ty(&*body, tcx); let rv_ty = self.normalize(rv_ty, location); if let Err(terr) = self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) @@ -1447,7 +1467,7 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo ref place, variant_index, } => { - let place_type = place.ty(body, tcx).ty; + let place_type = place.ty(&*body, tcx).ty; let adt = match place_type.kind { ty::Adt(adt, _) if adt.is_enum() => adt, _ => { @@ -1469,7 +1489,7 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo }; } StatementKind::AscribeUserType(box(ref place, ref projection), variance) => { - let place_ty = place.ty(body, tcx).ty; + let place_ty = place.ty(&*body, tcx).ty; if let Err(terr) = self.relate_type_and_user_type( place_ty, variance, @@ -1972,12 +1992,17 @@ fn aggregate_field_ty( } } - fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { + fn check_rvalue( + &mut self, + body: ReadOnlyBodyCache<'_, 'tcx>, + rvalue: &Rvalue<'tcx>, + location: Location) + { let tcx = self.tcx(); match rvalue { Rvalue::Aggregate(ak, ops) => { - self.check_aggregate_rvalue(body, rvalue, ak, ops, location) + self.check_aggregate_rvalue(&body, rvalue, ak, ops, location) } Rvalue::Repeat(operand, len) => if *len > 1 { @@ -1985,7 +2010,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L // While this is located in `nll::typeck` this error is not an NLL error, it's // a required check to make sure that repeated elements implement `Copy`. let span = body.source_info(location).span; - let ty = operand.ty(body, tcx); + let ty = operand.ty(&*body, tcx); if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) { // To determine if `const_in_array_repeat_expressions` feature gate should // be mentioned, need to check if the rvalue is promotable. @@ -2039,7 +2064,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L Rvalue::Cast(cast_kind, op, ty) => { match cast_kind { CastKind::Pointer(PointerCast::ReifyFnPointer) => { - let fn_sig = op.ty(body, tcx).fn_sig(tcx); + let fn_sig = op.ty(&*body, tcx).fn_sig(tcx); // The type that we see in the fcx is like // `foo::<'a, 'b>`, where `foo` is the path to a @@ -2068,7 +2093,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L } CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => { - let sig = match op.ty(body, tcx).kind { + let sig = match op.ty(&*body, tcx).kind { ty::Closure(def_id, substs) => { substs.as_closure().sig_ty(def_id, tcx).fn_sig(tcx) } @@ -2094,7 +2119,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L } CastKind::Pointer(PointerCast::UnsafeFnPointer) => { - let fn_sig = op.ty(body, tcx).fn_sig(tcx); + let fn_sig = op.ty(&*body, tcx).fn_sig(tcx); // The type that we see in the fcx is like // `foo::<'a, 'b>`, where `foo` is the path to a @@ -2126,7 +2151,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L let &ty = ty; let trait_ref = ty::TraitRef { def_id: tcx.lang_items().coerce_unsized_trait().unwrap(), - substs: tcx.mk_substs_trait(op.ty(body, tcx), &[ty.into()]), + substs: tcx.mk_substs_trait(op.ty(&*body, tcx), &[ty.into()]), }; self.prove_trait_ref( @@ -2137,7 +2162,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L } CastKind::Pointer(PointerCast::MutToConstPointer) => { - let ty_from = match op.ty(body, tcx).kind { + let ty_from = match op.ty(&*body, tcx).kind { ty::RawPtr(ty::TypeAndMut { ty: ty_from, mutbl: hir::Mutability::Mutable, @@ -2185,7 +2210,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L } CastKind::Pointer(PointerCast::ArrayToPointer) => { - let ty_from = op.ty(body, tcx); + let ty_from = op.ty(&*body, tcx); let opt_ty_elem = match ty_from.kind { ty::RawPtr( @@ -2247,7 +2272,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L } CastKind::Misc => { - let ty_from = op.ty(body, tcx); + let ty_from = op.ty(&*body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(ty); match (cast_ty_from, cast_ty_to) { @@ -2305,7 +2330,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L } Rvalue::Ref(region, _borrow_kind, borrowed_place) => { - self.add_reborrow_constraint(body, location, region, borrowed_place); + self.add_reborrow_constraint(&body, location, region, borrowed_place); } Rvalue::BinaryOp(BinOp::Eq, left, right) @@ -2314,9 +2339,9 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L | Rvalue::BinaryOp(BinOp::Le, left, right) | Rvalue::BinaryOp(BinOp::Gt, left, right) | Rvalue::BinaryOp(BinOp::Ge, left, right) => { - let ty_left = left.ty(body, tcx); + let ty_left = left.ty(&*body, tcx); if let ty::RawPtr(_) | ty::FnPtr(_) = ty_left.kind { - let ty_right = right.ty(body, tcx); + let ty_right = right.ty(&*body, tcx); let common_ty = self.infcx.next_ty_var( TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, @@ -2741,12 +2766,12 @@ fn prove_predicate( }) } - fn typeck_mir(&mut self, body: &Body<'tcx>) { + fn typeck_mir(&mut self, body: ReadOnlyBodyCache<'_, 'tcx>) { self.last_span = body.span; debug!("run_on_mir: {:?}", body.span); for (local, local_decl) in body.local_decls.iter_enumerated() { - self.check_local(body, local, local_decl); + self.check_local(&body, local, local_decl); } for (block, block_data) in body.basic_blocks().iter_enumerated() { @@ -2762,8 +2787,8 @@ fn typeck_mir(&mut self, body: &Body<'tcx>) { location.statement_index += 1; } - self.check_terminator(body, block_data.terminator(), location); - self.check_iscleanup(body, block_data); + self.check_terminator(&body, block_data.terminator(), location); + self.check_iscleanup(&body, block_data); } } diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index 57833cac9cb..06b9d4dbde0 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -11,7 +11,7 @@ use rustc::hir; use rustc::ty::{self, TyCtxt}; -use rustc::mir::{Body, Place, PlaceBase, PlaceRef, ProjectionElem}; +use rustc::mir::{Place, PlaceBase, PlaceRef, ProjectionElem, ReadOnlyBodyCache}; pub trait IsPrefixOf<'cx, 'tcx> { fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool; @@ -26,7 +26,7 @@ fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool { } pub(super) struct Prefixes<'cx, 'tcx> { - body: &'cx Body<'tcx>, + body: ReadOnlyBodyCache<'cx, 'tcx>, tcx: TyCtxt<'tcx>, kind: PrefixSet, next: Option>, @@ -143,7 +143,7 @@ fn next(&mut self) -> Option { // derefs, except we stop at the deref of a shared // reference. - let ty = Place::ty_from(cursor.base, proj_base, self.body, self.tcx).ty; + let ty = Place::ty_from(cursor.base, proj_base, &*self.body, self.tcx).ty; match ty.kind { ty::RawPtr(_) | ty::Ref( diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 91ddd5a5623..b84461d6b92 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -24,7 +24,7 @@ use super::lints; /// Construct the MIR for a given `DefId`. -pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> { +pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyCache<'_> { let id = tcx.hir().as_local_hir_id(def_id).unwrap(); // Figure out what primary body this item has. @@ -196,6 +196,8 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> { lints::check(tcx, &body, def_id); + let mut body = BodyCache::new(body); + body.ensure_predecessors(); body }) } @@ -309,7 +311,6 @@ struct Builder<'a, 'tcx> { /// The vector of all scopes that we have created thus far; /// we track this for debuginfo later. source_scopes: IndexVec, - source_scope_local_data: IndexVec, source_scope: SourceScope, /// The guard-context: each time we build the guard expression for @@ -704,7 +705,6 @@ fn new(hir: Cx<'a, 'tcx>, block_context: BlockContext::new(), source_scopes: IndexVec::new(), source_scope: OUTERMOST_SOURCE_SCOPE, - source_scope_local_data: IndexVec::new(), guard_context: vec![], push_unsafe_count: 0, unpushed_unsafe: safety, @@ -741,7 +741,6 @@ fn finish(self) -> Body<'tcx> { Body::new( self.cfg.basic_blocks, self.source_scopes, - ClearCrossCrate::Set(self.source_scope_local_data), self.local_decls, self.canonical_user_type_annotations, self.arg_count, @@ -942,7 +941,11 @@ fn set_correct_source_scope_for_arg( self.hir.root_lint_level ); let parent_root = tcx.maybe_lint_level_root_bounded( - self.source_scope_local_data[original_source_scope].lint_root, + self.source_scopes[original_source_scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root, self.hir.root_lint_level, ); if current_root != parent_root { diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index bb25b285269..00a30af806a 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -436,7 +436,11 @@ pub fn in_scope(&mut self, // We estimate the true lint roots here to avoid creating a lot of source scopes. let parent_root = tcx.maybe_lint_level_root_bounded( - self.source_scope_local_data[source_scope].lint_root, + self.source_scopes[source_scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root, self.hir.root_lint_level, ); let current_root = tcx.maybe_lint_level_root_bounded( @@ -654,23 +658,22 @@ pub fn new_source_scope(&mut self, let parent = self.source_scope; debug!("new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}", span, lint_level, safety, - parent, self.source_scope_local_data.get(parent)); - let scope = self.source_scopes.push(SourceScopeData { - span, - parent_scope: Some(parent), - }); + parent, self.source_scopes.get(parent)); let scope_local_data = SourceScopeLocalData { lint_root: if let LintLevel::Explicit(lint_root) = lint_level { lint_root } else { - self.source_scope_local_data[parent].lint_root + self.source_scopes[parent].local_data.as_ref().assert_crate_local().lint_root }, safety: safety.unwrap_or_else(|| { - self.source_scope_local_data[parent].safety + self.source_scopes[parent].local_data.as_ref().assert_crate_local().safety }) }; - self.source_scope_local_data.push(scope_local_data); - scope + self.source_scopes.push(SourceScopeData { + span, + parent_scope: Some(parent), + local_data: ClearCrossCrate::Set(scope_local_data), + }) } /// Given a span and the current source scope, make a SourceInfo. diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 0967b257885..a3eac1eecf0 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -23,7 +23,7 @@ use crate::interpret::{self, PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer, RawConst, ConstValue, Machine, - InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup, + InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup, AssertMessage, Allocation, AllocId, MemoryKind, Memory, snapshot, RefTracking, intern_const_alloc_recursive, }; @@ -354,7 +354,7 @@ fn find_fn( } // This is a const fn. Call it. Ok(Some(match ecx.load_mir(instance.def, None) { - Ok(body) => body, + Ok(body) => body.body(), Err(err) => { if let err_unsup!(NoMirFor(ref path)) = err.kind { return Err( @@ -395,6 +395,40 @@ fn call_intrinsic( ) } + fn assert_panic( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + _span: Span, + msg: &AssertMessage<'tcx>, + _unwind: Option, + ) -> InterpResult<'tcx> { + use rustc::mir::interpret::PanicInfo::*; + Err(match msg { + BoundsCheck { ref len, ref index } => { + let len = ecx + .read_immediate(ecx.eval_operand(len, None)?) + .expect("can't eval len") + .to_scalar()? + .to_machine_usize(&*ecx)?; + let index = ecx + .read_immediate(ecx.eval_operand(index, None)?) + .expect("can't eval index") + .to_scalar()? + .to_machine_usize(&*ecx)?; + err_panic!(BoundsCheck { len, index }) + } + Overflow(op) => err_panic!(Overflow(*op)), + OverflowNeg => err_panic!(OverflowNeg), + DivisionByZero => err_panic!(DivisionByZero), + RemainderByZero => err_panic!(RemainderByZero), + ResumedAfterReturn(generator_kind) + => err_panic!(ResumedAfterReturn(*generator_kind)), + ResumedAfterPanic(generator_kind) + => err_panic!(ResumedAfterPanic(*generator_kind)), + Panic { .. } => bug!("`Panic` variant cannot occur in MIR"), + } + .into()) + } + fn ptr_to_int( _mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer, @@ -423,7 +457,7 @@ fn find_foreign_static( } #[inline(always)] - fn tag_allocation<'b>( + fn init_allocation_extra<'b>( _memory_extra: &(), _id: AllocId, alloc: Cow<'b, Allocation>, @@ -518,7 +552,7 @@ pub fn const_caller_location<'tcx>( tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None)) .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())), ); - let loc_place = ecx.alloc_caller_location(file, line, col).unwrap(); + let loc_place = ecx.alloc_caller_location(file, line, col); intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap(); let loc_const = ty::Const { ty: loc_ty, @@ -697,7 +731,7 @@ pub fn const_eval_raw_provider<'tcx>( let res = ecx.load_mir(cid.instance.def, cid.promoted); res.and_then( - |body| eval_body_using_ecx(&mut ecx, cid, body) + |body| eval_body_using_ecx(&mut ecx, cid, body.body()) ).and_then(|place| { Ok(RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 402e5aeacbf..7e7652cdab5 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -98,7 +98,7 @@ fn precompute_borrows_out_of_scope<'tcx>( // Add successor BBs to the work list, if necessary. let bb_data = &body[bb]; assert!(hi == bb_data.statements.len()); - for &succ_bb in bb_data.terminator.as_ref().unwrap().successors() { + for &succ_bb in bb_data.terminator().successors() { visited.entry(succ_bb) .and_modify(|lo| { // `succ_bb` has been seen before. If it wasn't @@ -153,8 +153,8 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { } Borrows { - tcx: tcx, - body: body, + tcx, + body, param_env, borrow_set: borrow_set.clone(), borrows_out_of_scope_at_location, diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 6f860d00a22..0fb912b5fcb 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -71,7 +71,7 @@ pub struct MaybeInitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - MaybeInitializedPlaces { tcx: tcx, body: body, mdpe: mdpe } + MaybeInitializedPlaces { tcx, body, mdpe } } } @@ -122,7 +122,7 @@ pub struct MaybeUninitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - MaybeUninitializedPlaces { tcx: tcx, body: body, mdpe: mdpe } + MaybeUninitializedPlaces { tcx, body, mdpe } } } @@ -172,7 +172,7 @@ pub struct DefinitelyInitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - DefinitelyInitializedPlaces { tcx: tcx, body: body, mdpe: mdpe } + DefinitelyInitializedPlaces { tcx, body, mdpe } } } @@ -217,7 +217,7 @@ pub struct EverInitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self { - EverInitializedPlaces { tcx: tcx, body: body, mdpe: mdpe } + EverInitializedPlaces { tcx, body, mdpe } } } diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index 1b81032bfe6..c4b97d12e62 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -75,24 +75,26 @@ impl<'a, 'tcx> BottomValue for MaybeStorageLive<'a, 'tcx> { /// Dataflow analysis that determines whether each local requires storage at a /// given location; i.e. whether its storage can go away without being observed. pub struct RequiresStorage<'mir, 'tcx> { - body: &'mir Body<'tcx>, + body: ReadOnlyBodyCache<'mir, 'tcx>, borrowed_locals: RefCell>>, } impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> { pub fn new( - body: &'mir Body<'tcx>, + body: ReadOnlyBodyCache<'mir, 'tcx>, borrowed_locals: &'mir DataflowResults<'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>, ) -> Self { RequiresStorage { body, - borrowed_locals: RefCell::new(DataflowResultsCursor::new(borrowed_locals, body)), + borrowed_locals: RefCell::new( + DataflowResultsCursor::new(borrowed_locals, body.body()) + ), } } pub fn body(&self) -> &Body<'tcx> { - self.body + &self.body } } diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 1fb8b3ca63f..e9602ecfa4c 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -55,7 +55,7 @@ pub fn cast( ).ok_or_else(|| err_inval!(TooGeneric))?; let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); - self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?; + self.write_scalar(fn_ptr, dest)?; } _ => bug!("reify fn pointer on {:?}", src.layout.ty), } @@ -88,8 +88,7 @@ pub fn cast( ty::ClosureKind::FnOnce, ); let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); - let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into()); - self.write_immediate(val, dest)?; + self.write_scalar(fn_ptr, dest)?; } _ => bug!("closure fn pointer on {:?}", src.layout.ty), } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 228e5cad4e3..9af47f3e77f 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -164,6 +164,20 @@ pub fn access_mut( } } +impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> { + /// Return the `SourceInfo` of the current instruction. + pub fn current_source_info(&self) -> Option { + self.block.map(|block| { + let block = &self.body.basic_blocks()[block]; + if self.stmt < block.statements.len() { + block.statements[self.stmt].source_info + } else { + block.terminator().source_info + } + }) + } +} + impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &layout::TargetDataLayout { @@ -236,6 +250,12 @@ pub fn force_bits( self.memory.force_bits(scalar, size) } + /// Call this to turn untagged "global" pointers (obtained via `tcx`) into + /// the *canonical* machine pointer to the allocation. Must never be used + /// for any other pointers! + /// + /// This represents a *direct* access to that memory, as opposed to access + /// through a pointer that was created by the program. #[inline(always)] pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer { self.memory.tag_static_base_pointer(ptr) @@ -292,7 +312,7 @@ pub fn load_mir( &self, instance: ty::InstanceDef<'tcx>, promoted: Option, - ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { + ) -> InterpResult<'tcx, mir::ReadOnlyBodyCache<'tcx, 'tcx>> { // do not continue if typeck errors occurred (can only occur in local crate) let did = instance.def_id(); if did.is_local() @@ -303,11 +323,11 @@ pub fn load_mir( } trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); if let Some(promoted) = promoted { - return Ok(&self.tcx.promoted_mir(did)[promoted]); + return Ok(self.tcx.promoted_mir(did)[promoted].unwrap_read_only()); } match instance { ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) { - Ok(self.tcx.optimized_mir(did)) + Ok(self.tcx.optimized_mir(did).unwrap_read_only()) } else { throw_unsup!(NoMirFor(self.tcx.def_path_str(def_id))) }, @@ -828,34 +848,28 @@ pub fn dump_place(&self, place: Place) { pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec> { let mut last_span = None; let mut frames = Vec::new(); - for &Frame { instance, span, body, block, stmt, .. } in self.stack().iter().rev() { + for frame in self.stack().iter().rev() { // make sure we don't emit frames that are duplicates of the previous - if explicit_span == Some(span) { - last_span = Some(span); + if explicit_span == Some(frame.span) { + last_span = Some(frame.span); continue; } if let Some(last) = last_span { - if last == span { + if last == frame.span { continue; } } else { - last_span = Some(span); + last_span = Some(frame.span); } - let lint_root = block.and_then(|block| { - let block = &body.basic_blocks()[block]; - let source_info = if stmt < block.statements.len() { - block.statements[stmt].source_info - } else { - block.terminator().source_info - }; - match body.source_scope_local_data { - mir::ClearCrossCrate::Set(ref ivs) => Some(ivs[source_info.scope].lint_root), + let lint_root = frame.current_source_info().and_then(|source_info| { + match &frame.body.source_scopes[source_info.scope].local_data { + mir::ClearCrossCrate::Set(data) => Some(data.lint_root), mir::ClearCrossCrate::Clear => None, } }); - frames.push(FrameInfo { call_site: span, instance, lint_root }); + frames.push(FrameInfo { call_site: frame.span, instance: frame.instance, lint_root }); } trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span); frames diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 7bcf84a7b2d..75fc6b389e8 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -110,13 +110,7 @@ pub fn emulate_intrinsic( match intrinsic_name { "caller_location" => { - let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); - let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); - let location = self.alloc_caller_location( - Symbol::intern(&caller.file.name.to_string()), - caller.line as u32, - caller.col_display as u32 + 1, - )?; + let location = self.alloc_caller_location_for_span(span); self.write_scalar(location.ptr, dest)?; } @@ -430,13 +424,13 @@ pub fn exact_div( if self.binary_op(BinOp::Rem, a, b)?.to_bits()? != 0 { // Then, check if `b` is -1, which is the "min_value / -1" case. let minus1 = Scalar::from_int(-1, dest.layout.size); - let b = b.to_scalar().unwrap(); - if b == minus1 { + let b_scalar = b.to_scalar().unwrap(); + if b_scalar == minus1 { throw_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented") } else { throw_ub_format!( "exact_div: {} cannot be divided by {} without remainder", - a.to_scalar().unwrap(), + a, b, ) } diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs index 9e07a3f1072..ecf4b7a39b7 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -1,50 +1,48 @@ use rustc::middle::lang_items::PanicLocationLangItem; -use rustc::mir::interpret::{Pointer, PointerArithmetic, Scalar}; use rustc::ty::subst::Subst; -use rustc_target::abi::{LayoutOf, Size}; -use syntax_pos::Symbol; +use rustc_target::abi::LayoutOf; +use syntax_pos::{Symbol, Span}; -use crate::interpret::{MemoryKind, MPlaceTy, intrinsics::{InterpCx, InterpResult, Machine}}; +use crate::interpret::{Scalar, MemoryKind, MPlaceTy, intrinsics::{InterpCx, Machine}}; impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - pub fn alloc_caller_location( + crate fn alloc_caller_location( &mut self, filename: Symbol, line: u32, col: u32, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + ) -> MPlaceTy<'tcx, M::PointerTag> { + let file = self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation); let line = Scalar::from_u32(line); let col = Scalar::from_u32(col); - let ptr_size = self.pointer_size(); - let u32_size = Size::from_bits(32); - + // Allocate memory for `CallerLocation` struct. let loc_ty = self.tcx.type_of(self.tcx.require_lang_item(PanicLocationLangItem, None)) .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_static.into()].iter())); - let loc_layout = self.layout_of(loc_ty)?; - - let file_alloc = self.tcx.allocate_bytes(filename.as_str().as_bytes()); - let file_ptr = Pointer::new(file_alloc, Size::ZERO); - let file = Scalar::Ptr(self.tag_static_base_pointer(file_ptr)); - let file_len = Scalar::from_uint(filename.as_str().len() as u128, ptr_size); - + let loc_layout = self.layout_of(loc_ty).unwrap(); let location = self.allocate(loc_layout, MemoryKind::CallerLocation); - let file_out = self.mplace_field(location, 0)?; - let file_ptr_out = self.force_ptr(self.mplace_field(file_out, 0)?.ptr)?; - let file_len_out = self.force_ptr(self.mplace_field(file_out, 1)?.ptr)?; - let line_out = self.force_ptr(self.mplace_field(location, 1)?.ptr)?; - let col_out = self.force_ptr(self.mplace_field(location, 2)?.ptr)?; + // Initialize fields. + self.write_immediate(file.to_ref(), self.mplace_field(location, 0).unwrap().into()) + .expect("writing to memory we just allocated cannot fail"); + self.write_scalar(line, self.mplace_field(location, 1).unwrap().into()) + .expect("writing to memory we just allocated cannot fail"); + self.write_scalar(col, self.mplace_field(location, 2).unwrap().into()) + .expect("writing to memory we just allocated cannot fail"); - let layout = &self.tcx.data_layout; - // We just allocated this, so we can skip the bounds checks. - let alloc = self.memory.get_raw_mut(file_ptr_out.alloc_id)?; - - alloc.write_scalar(layout, file_ptr_out, file.into(), ptr_size)?; - alloc.write_scalar(layout, file_len_out, file_len.into(), ptr_size)?; - alloc.write_scalar(layout, line_out, line.into(), u32_size)?; - alloc.write_scalar(layout, col_out, col.into(), u32_size)?; + location + } - Ok(location) + pub fn alloc_caller_location_for_span( + &mut self, + span: Span, + ) -> MPlaceTy<'tcx, M::PointerTag> { + let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); + let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); + self.alloc_caller_location( + Symbol::intern(&caller.file.name.to_string()), + caller.line as u32, + caller.col_display as u32 + 1, + ) } } diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index b7cde626415..2ecc8d88ad3 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -11,7 +11,7 @@ use syntax_pos::Span; use super::{ - Allocation, AllocId, InterpResult, Scalar, AllocationExtra, + Allocation, AllocId, InterpResult, Scalar, AllocationExtra, AssertMessage, InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory, Frame, Operand, }; @@ -175,6 +175,14 @@ fn call_intrinsic( unwind: Option, ) -> InterpResult<'tcx>; + /// Called to evaluate `Assert` MIR terminators that trigger a panic. + fn assert_panic( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + span: Span, + msg: &AssertMessage<'tcx>, + unwind: Option, + ) -> InterpResult<'tcx>; + /// Called for read access to a foreign static item. /// /// This will only be called once per static and machine; the result is cached in @@ -233,20 +241,19 @@ fn before_access_static( /// cache the result. (This relies on `AllocMap::get_or` being able to add the /// owned allocation to the map even when the map is shared.) /// - /// For static allocations, the tag returned must be the same as the one returned by - /// `tag_static_base_pointer`. - fn tag_allocation<'b>( + /// Also return the "base" tag to use for this allocation: the one that is used for direct + /// accesses to this allocation. If `kind == STATIC_KIND`, this tag must be consistent + /// with `tag_static_base_pointer`. + fn init_allocation_extra<'b>( memory_extra: &Self::MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, ) -> (Cow<'b, Allocation>, Self::PointerTag); - /// Return the "base" tag for the given static allocation: the one that is used for direct - /// accesses to this static/const/fn allocation. - /// - /// Be aware that requesting the `Allocation` for that `id` will lead to cycles - /// for cyclic statics! + /// Return the "base" tag for the given *static* allocation: the one that is used for direct + /// accesses to this static/const/fn allocation. If `id` is not a static allocation, + /// this will return an unusable tag (i.e., accesses will be UB)! fn tag_static_base_pointer( memory_extra: &Self::MemoryExtra, id: AllocId, diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index a8011f7abb1..ee7fb18fd05 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -143,6 +143,12 @@ pub fn new(tcx: TyCtxtAt<'tcx>, extra: M::MemoryExtra) -> Self { } } + /// Call this to turn untagged "global" pointers (obtained via `tcx`) into + /// the *canonical* machine pointer to the allocation. Must never be used + /// for any other pointers! + /// + /// This represents a *direct* access to that memory, as opposed to access + /// through a pointer that was created by the program. #[inline] pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer { ptr.with_tag(M::tag_static_base_pointer(&self.extra, ptr.alloc_id)) @@ -191,7 +197,9 @@ pub fn allocate_with( kind: MemoryKind, ) -> Pointer { let id = self.tcx.alloc_map.lock().reserve(); - let (alloc, tag) = M::tag_allocation(&self.extra, id, Cow::Owned(alloc), Some(kind)); + debug_assert_ne!(Some(kind), M::STATIC_KIND.map(MemoryKind::Machine), + "dynamically allocating static memory"); + let (alloc, tag) = M::init_allocation_extra(&self.extra, id, Cow::Owned(alloc), Some(kind)); self.alloc_map.insert(id, (kind, alloc.into_owned())); Pointer::from(id).with_tag(tag) } @@ -350,7 +358,7 @@ fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> { sptr } else { // A "real" access, we must get a pointer. - Scalar::Ptr(self.force_ptr(sptr)?) + Scalar::from(self.force_ptr(sptr)?) }; Ok(match normalized.to_bits_or_ptr(self.pointer_size(), self) { Ok(bits) => { @@ -473,14 +481,15 @@ fn get_static_alloc( } } }; - // We got tcx memory. Let the machine figure out whether and how to - // turn that into memory with the right pointer tag. - Ok(M::tag_allocation( + // We got tcx memory. Let the machine initialize its "extra" stuff. + let (alloc, tag) = M::init_allocation_extra( memory_extra, id, // always use the ID we got as input, not the "hidden" one. alloc, M::STATIC_KIND.map(MemoryKind::Machine), - ).0) + ); + debug_assert_eq!(tag, M::tag_static_base_pointer(memory_extra, id)); + Ok(alloc) } /// Gives raw access to the `Allocation`, without bounds or alignment checks. diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 8dd5807f7cf..48e7193ec39 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -19,12 +19,13 @@ }; pub use rustc::mir::interpret::ScalarMaybeUndef; use rustc_macros::HashStable; +use syntax::ast; /// An `Immediate` represents a single immediate self-contained Rust value. /// /// For optimization of a few very common cases, there is also a representation for a pair of /// primitive values (`ScalarPair`). It allows Miri to avoid making allocations for checked binary -/// operations and fat pointers. This idea was taken from rustc's codegen. +/// operations and wide pointers. This idea was taken from rustc's codegen. /// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely /// defined on `Immediate`, and do not have to work with a `Place`. #[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, Hash)] @@ -47,6 +48,13 @@ fn from(val: Scalar) -> Self { } } +impl From> for Immediate { + #[inline(always)] + fn from(val: Pointer) -> Self { + Immediate::Scalar(Scalar::from(val).into()) + } +} + impl<'tcx, Tag> Immediate { pub fn new_slice( val: Scalar, @@ -60,14 +68,14 @@ pub fn new_slice( } pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self { - Immediate::ScalarPair(val.into(), Scalar::Ptr(vtable).into()) + Immediate::ScalarPair(val.into(), vtable.into()) } #[inline] pub fn to_scalar_or_undef(self) -> ScalarMaybeUndef { match self { Immediate::Scalar(val) => val, - Immediate::ScalarPair(..) => bug!("Got a fat pointer where a scalar was expected"), + Immediate::ScalarPair(..) => bug!("Got a wide pointer where a scalar was expected"), } } @@ -93,6 +101,42 @@ pub struct ImmTy<'tcx, Tag=()> { pub layout: TyLayout<'tcx>, } +// `Tag: Copy` because some methods on `Scalar` consume them by value +impl std::fmt::Display for ImmTy<'tcx, Tag> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.imm { + Immediate::Scalar(ScalarMaybeUndef::Scalar(s)) => match s.to_bits(self.layout.size) { + Ok(s) => { + match self.layout.ty.kind { + ty::Int(_) => return write!( + fmt, "{}", + super::sign_extend(s, self.layout.size) as i128, + ), + ty::Uint(_) => return write!(fmt, "{}", s), + ty::Bool if s == 0 => return fmt.write_str("false"), + ty::Bool if s == 1 => return fmt.write_str("true"), + ty::Char => if let Some(c) = + u32::try_from(s).ok().and_then(std::char::from_u32) { + return write!(fmt, "{}", c); + }, + ty::Float(ast::FloatTy::F32) => if let Ok(u) = u32::try_from(s) { + return write!(fmt, "{}", f32::from_bits(u)); + }, + ty::Float(ast::FloatTy::F64) => if let Ok(u) = u64::try_from(s) { + return write!(fmt, "{}", f64::from_bits(u)); + }, + _ => {}, + } + write!(fmt, "{:x}", s) + }, + Err(_) => fmt.write_str("{pointer}"), + }, + Immediate::Scalar(ScalarMaybeUndef::Undef) => fmt.write_str("{undef}"), + Immediate::ScalarPair(..) => fmt.write_str("{wide pointer or tuple}"), + } + } +} + impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> { type Target = Immediate; #[inline(always)] @@ -324,7 +368,7 @@ pub fn read_scalar( Ok(self.read_immediate(op)?.to_scalar_or_undef()) } - // Turn the MPlace into a string (must already be dereferenced!) + // Turn the wide MPlace into a string (must already be dereferenced!) pub fn read_str( &self, mplace: MPlaceTy<'tcx, M::PointerTag>, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 5b263f76801..da601c3a9f0 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -125,7 +125,7 @@ pub fn from_ptr(ptr: Pointer, align: Align) -> Self { Self::from_scalar_ptr(ptr.into(), align) } - /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space. + /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. /// This is the inverse of `ref_to_mplace`. #[inline(always)] pub fn to_ref(self) -> Immediate { @@ -278,7 +278,7 @@ impl<'mir, 'tcx, Tag, M> InterpCx<'mir, 'tcx, M> M::MemoryMap: AllocMap, Allocation)>, M::AllocExtra: AllocationExtra, { - /// Take a value, which represents a (thin or fat) reference, and make it a place. + /// Take a value, which represents a (thin or wide) reference, and make it a place. /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. /// /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not @@ -651,20 +651,28 @@ pub fn eval_place( use rustc::mir::PlaceBase; let mut place_ty = match &place.base { - PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place { - Some(return_place) => { - // We use our layout to verify our assumption; caller will validate - // their layout on return. - PlaceTy { - place: *return_place, - layout: self.layout_of( - self.subst_from_frame_and_normalize_erasing_regions( - self.frame().body.return_ty() - ) - )?, - } + PlaceBase::Local(mir::RETURN_PLACE) => { + // `return_place` has the *caller* layout, but we want to use our + // `layout to verify our assumption. The caller will validate + // their layout on return. + PlaceTy { + place: match self.frame().return_place { + Some(p) => *p, + // Even if we don't have a return place, we sometimes need to + // create this place, but any attempt to read from / write to it + // (even a ZST read/write) needs to error, so let us make this + // a NULL place. + // + // FIXME: Ideally we'd make sure that the place projections also + // bail out. + None => Place::null(&*self), + }, + layout: self.layout_of( + self.subst_from_frame_and_normalize_erasing_regions( + self.frame().body.return_ty() + ) + )?, } - None => throw_unsup!(InvalidNullPointerUsage), }, PlaceBase::Local(local) => PlaceTy { // This works even for dead/uninitialized locals; we check further when writing @@ -686,6 +694,7 @@ pub fn eval_place( } /// Write a scalar to a place + #[inline(always)] pub fn write_scalar( &mut self, val: impl Into>, @@ -791,8 +800,8 @@ fn write_immediate_to_mplace_no_validate( // to handle padding properly, which is only correct if we never look at this data with the // wrong type. - let ptr = match self.check_mplace_access(dest, None) - .expect("places should be checked on creation") + // Invalid places are a thing: the return place of a diverging function + let ptr = match self.check_mplace_access(dest, None)? { Some(ptr) => ptr, None => return Ok(()), // zero-sized access @@ -1033,6 +1042,24 @@ pub fn allocate( MPlaceTy::from_aligned_ptr(ptr, layout) } + /// Returns a wide MPlace. + pub fn allocate_str( + &mut self, + str: &str, + kind: MemoryKind, + ) -> MPlaceTy<'tcx, M::PointerTag> { + let ptr = self.memory.allocate_static_bytes(str.as_bytes(), kind); + let meta = Scalar::from_uint(str.len() as u128, self.pointer_size()); + let mplace = MemPlace { + ptr: ptr.into(), + align: Align::from_bytes(1).unwrap(), + meta: Some(meta), + }; + + let layout = self.layout_of(self.tcx.mk_static_str()).unwrap(); + MPlaceTy { mplace, layout } + } + pub fn write_discriminant_index( &mut self, variant_index: VariantIdx, diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 50cd3188510..06c3969fbc5 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -7,8 +7,8 @@ use rustc_target::spec::abi::Abi; use super::{ - GlobalId, InterpResult, PointerArithmetic, - InterpCx, Machine, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal, + GlobalId, InterpResult, InterpCx, Machine, + OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal, }; impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { @@ -115,40 +115,14 @@ pub(super) fn eval_terminator( expected, ref msg, target, - .. + cleanup, } => { let cond_val = self.read_immediate(self.eval_operand(cond, None)?)? .to_scalar()?.to_bool()?; if expected == cond_val { self.go_to_block(target); } else { - // Compute error message - use rustc::mir::interpret::PanicInfo::*; - return Err(match msg { - BoundsCheck { ref len, ref index } => { - let len = self - .read_immediate(self.eval_operand(len, None)?) - .expect("can't eval len") - .to_scalar()? - .to_bits(self.memory.pointer_size())? as u64; - let index = self - .read_immediate(self.eval_operand(index, None)?) - .expect("can't eval index") - .to_scalar()? - .to_bits(self.memory.pointer_size())? as u64; - err_panic!(BoundsCheck { len, index }) - } - Overflow(op) => err_panic!(Overflow(*op)), - OverflowNeg => err_panic!(OverflowNeg), - DivisionByZero => err_panic!(DivisionByZero), - RemainderByZero => err_panic!(RemainderByZero), - ResumedAfterReturn(generator_kind) - => err_panic!(ResumedAfterReturn(*generator_kind)), - ResumedAfterPanic(generator_kind) - => err_panic!(ResumedAfterPanic(*generator_kind)), - Panic { .. } => bug!("`Panic` variant cannot occur in MIR"), - } - .into()); + M::assert_panic(self, terminator.source_info.span, msg, cleanup)?; } } @@ -164,15 +138,21 @@ pub(super) fn eval_terminator( return Ok(()) }, + // It is UB to ever encounter this. + Unreachable => throw_ub!(Unreachable), + + // These should never occur for MIR we actually run. + DropAndReplace { .. } | + FalseEdges { .. } | + FalseUnwind { .. } => + bug!("{:#?} should have been eliminated by MIR pass", terminator.kind), + + // These are not (yet) supported. It is unclear if they even can occur in + // MIR that we actually run. Yield { .. } | GeneratorDrop | - DropAndReplace { .. } | - Abort => unimplemented!("{:#?}", terminator.kind), - FalseEdges { .. } => bug!("should have been eliminated by\ - `simplify_branches` mir pass"), - FalseUnwind { .. } => bug!("should have been eliminated by\ - `simplify_branches` mir pass"), - Unreachable => throw_ub!(Unreachable), + Abort => + throw_unsup_format!("Unsupported terminator kind: {:#?}", terminator.kind), } Ok(()) diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 3a7f47a2aac..efa0d266cbc 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -67,7 +67,7 @@ pub fn get_vtable( // allocation is correctly aligned as we created it above. Also we're only offsetting by // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`. let vtable_alloc = self.memory.get_raw_mut(vtable.alloc_id)?; - vtable_alloc.write_ptr_sized(tcx, vtable, Scalar::Ptr(drop).into())?; + vtable_alloc.write_ptr_sized(tcx, vtable, drop.into())?; let size_ptr = vtable.offset(ptr_size, tcx)?; vtable_alloc.write_ptr_sized(tcx, size_ptr, Scalar::from_uint(size, ptr_size).into())?; @@ -87,7 +87,7 @@ pub fn get_vtable( // We cannot use `vtable_allic` as we are creating fn ptrs in this loop. let method_ptr = vtable.offset(ptr_size * (3 + i as u64), tcx)?; self.memory.get_raw_mut(vtable.alloc_id)? - .write_ptr_sized(tcx, method_ptr, Scalar::Ptr(fn_ptr).into())?; + .write_ptr_sized(tcx, method_ptr, fn_ptr.into())?; } } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index cca76700ed1..f4fb9a5e4f2 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -29,6 +29,7 @@ #![feature(stmt_expr_attributes)] #![feature(bool_to_option)] #![feature(trait_alias)] +#![feature(matches_macro)] #![recursion_limit="256"] diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index a4c4c7ff616..4fe53cf35e5 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1255,7 +1255,7 @@ fn collect_neighbours<'tcx>( body: &body, output, param_substs: instance.substs, - }.visit_body(&body); + }.visit_body(body); } fn def_id_to_string(tcx: TyCtxt<'_>, def_id: DefId) -> String { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 08af271ff46..680f75eb84e 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -26,7 +26,7 @@ pub fn provide(providers: &mut Providers<'_>) { providers.mir_shims = make_shim; } -fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { +fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx BodyCache<'tcx> { debug!("make_shim({:?})", instance); let mut result = match instance { @@ -125,6 +125,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx debug!("make_shim({:?}) = {:?}", instance, result); + result.ensure_predecessors(); tcx.arena.alloc(result) } @@ -164,7 +165,9 @@ fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>, span: Span) .collect() } -fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) -> Body<'tcx> { +fn build_drop_shim<'tcx>( + tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option> +) -> BodyCache<'tcx> { debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty); // Check if this is a generator, if so, return the drop glue for it @@ -196,15 +199,14 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) block(&mut blocks, TerminatorKind::Goto { target: return_block }); block(&mut blocks, TerminatorKind::Return); - let mut body = new_body( + let body = new_body( blocks, - IndexVec::from_elem_n( - SourceScopeData { span, parent_scope: None }, 1 - ), local_decls_for_sig(&sig, span), sig.inputs().len(), span); + let mut body = BodyCache::new(body); + if let Some(..) = ty { // The first argument (index 0), but add 1 for the return value. let dropee_ptr = Place::from(Local::new(1+0)); @@ -244,15 +246,16 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) fn new_body<'tcx>( basic_blocks: IndexVec>, - source_scopes: IndexVec, local_decls: IndexVec>, arg_count: usize, span: Span, ) -> Body<'tcx> { Body::new( basic_blocks, - source_scopes, - ClearCrossCrate::Clear, + IndexVec::from_elem_n( + SourceScopeData { span, parent_scope: None, local_data: ClearCrossCrate::Clear }, + 1, + ), local_decls, IndexVec::new(), arg_count, @@ -316,7 +319,7 @@ fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> { +fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> BodyCache<'tcx> { debug!("build_clone_shim(def_id={:?})", def_id); let param_env = tcx.param_env(def_id); @@ -345,7 +348,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - } }; - builder.into_mir() + BodyCache::new(builder.into_mir()) } struct CloneShimBuilder<'tcx> { @@ -380,9 +383,6 @@ fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self { fn into_mir(self) -> Body<'tcx> { new_body( self.blocks, - IndexVec::from_elem_n( - SourceScopeData { span: self.span, parent_scope: None }, 1 - ), self.local_decls, self.sig.inputs().len(), self.span, @@ -709,7 +709,7 @@ fn build_call_shim<'tcx>( rcvr_adjustment: Adjustment, call_kind: CallKind, untuple_args: Option<&[Ty<'tcx>]>, -) -> Body<'tcx> { +) -> BodyCache<'tcx> { debug!("build_call_shim(def_id={:?}, rcvr_adjustment={:?}, \ call_kind={:?}, untuple_args={:?})", def_id, rcvr_adjustment, call_kind, untuple_args); @@ -836,9 +836,6 @@ fn build_call_shim<'tcx>( let mut body = new_body( blocks, - IndexVec::from_elem_n( - SourceScopeData { span, parent_scope: None }, 1 - ), local_decls, sig.inputs().len(), span, @@ -847,10 +844,10 @@ fn build_call_shim<'tcx>( if let Abi::RustCall = sig.abi { body.spread_arg = Some(Local::new(sig.inputs().len())); } - body + BodyCache::new(body) } -pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> { +pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &BodyCache<'_> { debug_assert!(tcx.is_constructor(ctor_id)); let span = tcx.hir().span_if_local(ctor_id) @@ -919,9 +916,6 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> { let body = new_body( IndexVec::from_elem_n(start_block, 1), - IndexVec::from_elem_n( - SourceScopeData { span, parent_scope: None }, 1 - ), local_decls, sig.inputs().len(), span, @@ -937,5 +931,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> { |_, _| Ok(()), ); + let mut body = BodyCache::new(body); + body.ensure_predecessors(); tcx.arena.alloc(body) } diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index bf3df1ae2fd..35238e2d08a 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -31,15 +31,16 @@ pub enum AddCallGuards { */ impl<'tcx> MirPass<'tcx> for AddCallGuards { - fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass( + &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx> + ) { self.add_call_guards(body); } } impl AddCallGuards { - pub fn add_call_guards(&self, body: &mut Body<'_>) { - let pred_count: IndexVec<_, _> = - body.predecessors().iter().map(|ps| ps.len()).collect(); + pub fn add_call_guards(&self, body: &mut BodyCache<'_>) { + let pred_count: IndexVec<_, _> = body.predecessors().iter().map(|ps| ps.len()).collect(); // We need a place to store the new blocks generated let mut new_blocks = Vec::new(); diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/src/librustc_mir/transform/add_moves_for_packed_drops.rs index 052631ddff3..98c6a5ed077 100644 --- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs +++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs @@ -40,13 +40,15 @@ pub struct AddMovesForPackedDrops; impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops { - fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { debug!("add_moves_for_packed_drops({:?} @ {:?})", src, body.span); add_moves_for_packed_drops(tcx, body, src.def_id()); } } -pub fn add_moves_for_packed_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, def_id: DefId) { +pub fn add_moves_for_packed_drops<'tcx>( + tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>, def_id: DefId +) { let patch = add_moves_for_packed_drops_patch(tcx, body, def_id); patch.apply(body); } diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index b56a1b263fd..e6ad37ae113 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -59,7 +59,7 @@ fn may_be_reference<'tcx>(ty: Ty<'tcx>) -> bool { } impl<'tcx> MirPass<'tcx> for AddRetag { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { if !tcx.sess.opts.debugging_opts.mir_emit_retag { return; } diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs index 4d00aaf7abc..7095b3fa0aa 100644 --- a/src/librustc_mir/transform/check_consts/mod.rs +++ b/src/librustc_mir/transform/check_consts/mod.rs @@ -20,7 +20,7 @@ /// Information about the item currently being const-checked, as well as a reference to the global /// context. pub struct Item<'mir, 'tcx> { - pub body: &'mir mir::Body<'tcx>, + pub body: mir::ReadOnlyBodyCache<'mir, 'tcx>, pub tcx: TyCtxt<'tcx>, pub def_id: DefId, pub param_env: ty::ParamEnv<'tcx>, @@ -31,7 +31,7 @@ impl Item<'mir, 'tcx> { pub fn new( tcx: TyCtxt<'tcx>, def_id: DefId, - body: &'mir mir::Body<'tcx>, + body: mir::ReadOnlyBodyCache<'mir, 'tcx>, ) -> Self { let param_env = tcx.param_env(def_id); let const_kind = ConstKind::for_item(tcx, def_id); diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index 9ed1ca740b8..62b4a4ccc98 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -5,7 +5,7 @@ use rustc::hir::def_id::DefId; use syntax_pos::DUMMY_SP; -use super::{ConstKind, Item as ConstCx}; +use super::Item as ConstCx; pub fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> ConstQualifs { ConstQualifs { @@ -33,9 +33,10 @@ pub trait Qualif { /// of the type. fn in_any_value_of_ty(_cx: &ConstCx<'_, 'tcx>, _ty: Ty<'tcx>) -> bool; - fn in_static(_cx: &ConstCx<'_, 'tcx>, _def_id: DefId) -> bool { - // FIXME(eddyb) should we do anything here for value properties? - false + fn in_static(cx: &ConstCx<'_, 'tcx>, def_id: DefId) -> bool { + // `mir_const_qualif` does return the qualifs in the final value of a `static`, so we could + // use value-based qualification here, but we shouldn't do this without a good reason. + Self::in_any_value_of_ty(cx, cx.tcx.type_of(def_id)) } fn in_projection_structurally( @@ -50,7 +51,7 @@ fn in_projection_structurally( }); let qualif = base_qualif && Self::in_any_value_of_ty( cx, - Place::ty_from(place.base, proj_base, cx.body, cx.tcx) + Place::ty_from(place.base, proj_base, &*cx.body, cx.tcx) .projection_ty(cx.tcx, elem) .ty, ); @@ -154,7 +155,7 @@ fn in_rvalue_structurally( // Special-case reborrows to be more like a copy of the reference. if let &[ref proj_base @ .., elem] = place.projection.as_ref() { if ProjectionElem::Deref == elem { - let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty; + let base_ty = Place::ty_from(&place.base, proj_base, &*cx.body, cx.tcx).ty; if let ty::Ref(..) = base_ty.kind { return Self::in_place(cx, per_local, PlaceRef { base: &place.base, @@ -217,38 +218,10 @@ fn in_rvalue( rvalue: &Rvalue<'tcx>, ) -> bool { match *rvalue { - // Returning `true` for `Rvalue::Ref` indicates the borrow isn't - // allowed in constants (and the `Checker` will error), and/or it - // won't be promoted, due to `&mut ...` or interior mutability. - Rvalue::Ref(_, kind, ref place) => { - let ty = place.ty(cx.body, cx.tcx).ty; - - if let BorrowKind::Mut { .. } = kind { - // In theory, any zero-sized value could be borrowed - // mutably without consequences. - match ty.kind { - // Inside a `static mut`, &mut [...] is also allowed. - | ty::Array(..) - | ty::Slice(_) - if cx.const_kind == Some(ConstKind::StaticMut) - => {}, - - // FIXME(eddyb): We only return false for `&mut []` outside a const - // context which seems unnecessary given that this is merely a ZST. - | ty::Array(_, len) - if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0) - && cx.const_kind == None - => {}, - - _ => return true, - } - } - } - Rvalue::Aggregate(ref kind, _) => { if let AggregateKind::Adt(def, ..) = **kind { if Some(def.did) == cx.tcx.lang_items().unsafe_cell_type() { - let ty = rvalue.ty(cx.body, cx.tcx); + let ty = rvalue.ty(&*cx.body, cx.tcx); assert_eq!(Self::in_any_value_of_ty(cx, ty), true); return true; } diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs index 8909ef7db68..9004c5be987 100644 --- a/src/librustc_mir/transform/check_consts/resolver.rs +++ b/src/librustc_mir/transform/check_consts/resolver.rs @@ -77,7 +77,7 @@ fn apply_call_return_effect( args: &[mir::Operand<'tcx>], return_place: &mir::Place<'tcx>, ) { - let return_ty = return_place.ty(self.item.body, self.item.tcx).ty; + let return_ty = return_place.ty(&*self.item.body, self.item.tcx).ty; let qualif = Q::in_call( self.item, &|l| self.qualifs_per_local.contains(l), diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 829d9ee6faf..9d477bfbae8 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -23,13 +23,6 @@ use super::resolver::FlowSensitiveAnalysis; use super::{ConstKind, Item, Qualif, is_lang_panic_fn}; -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum CheckOpResult { - Forbidden, - Unleashed, - Allowed, -} - pub type IndirectlyMutableResults<'mir, 'tcx> = old_dataflow::DataflowResultsCursor<'mir, 'tcx, IndirectlyMutableLocals<'mir, 'tcx>>; @@ -46,9 +39,9 @@ pub fn new( ) -> Self { let analysis = FlowSensitiveAnalysis::new(q, item); let results = - dataflow::Engine::new(item.tcx, item.body, item.def_id, dead_unwinds, analysis) + dataflow::Engine::new(item.tcx, &item.body, item.def_id, dead_unwinds, analysis) .iterate_to_fixpoint(); - let cursor = dataflow::ResultsCursor::new(item.body, results); + let cursor = dataflow::ResultsCursor::new(item.body.body(), results); let mut in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len()); for (local, decl) in item.body.local_decls.iter_enumerated() { @@ -149,17 +142,6 @@ pub struct Validator<'a, 'mir, 'tcx> { /// The span of the current statement. span: Span, - - /// True if the local was assigned the result of an illegal borrow (`ops::MutBorrow`). - /// - /// This is used to hide errors from {re,}borrowing the newly-assigned local, instead pointing - /// the user to the place where the illegal borrow occurred. This set is only populated once an - /// error has been emitted, so it will never cause an erroneous `mir::Body` to pass validation. - /// - /// FIXME(ecstaticmorse): assert at the end of checking that if `tcx.has_errors() == false`, - /// this set is empty. Note that if we start removing locals from - /// `derived_from_illegal_borrow`, just checking at the end won't be enough. - derived_from_illegal_borrow: BitSet, } impl Deref for Validator<'_, 'mir, 'tcx> { @@ -190,17 +172,17 @@ pub fn new( let indirectly_mutable = old_dataflow::do_dataflow( item.tcx, - item.body, + &*item.body, item.def_id, &item.tcx.get_attrs(item.def_id), &dead_unwinds, - old_dataflow::IndirectlyMutableLocals::new(item.tcx, item.body, item.param_env), + old_dataflow::IndirectlyMutableLocals::new(item.tcx, item.body.body(), item.param_env), |_, local| old_dataflow::DebugFormatted::new(&local), ); let indirectly_mutable = old_dataflow::DataflowResultsCursor::new( indirectly_mutable, - item.body, + item.body.body(), ); let qualifs = Qualifs { @@ -213,7 +195,6 @@ pub fn new( span: item.body.span, item, qualifs, - derived_from_illegal_borrow: BitSet::new_empty(item.body.local_decls.len()), } } @@ -227,7 +208,7 @@ pub fn check_body(&mut self) { if use_min_const_fn_checks { // Enforce `min_const_fn` for stable `const fn`s. use crate::transform::qualify_min_const_fn::is_min_const_fn; - if let Err((span, err)) = is_min_const_fn(tcx, def_id, body) { + if let Err((span, err)) = is_min_const_fn(tcx, def_id, &body) { error_min_const_fn_violation(tcx, span, err); return; } @@ -249,7 +230,7 @@ pub fn check_body(&mut self) { if should_check_for_sync { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - check_return_ty_is_sync(tcx, body, hir_id); + check_return_ty_is_sync(tcx, &body, hir_id); } } @@ -258,15 +239,15 @@ pub fn qualifs_in_return_place(&mut self) -> ConstQualifs { } /// Emits an error at the given `span` if an expression cannot be evaluated in the current - /// context. Returns `Forbidden` if an error was emitted. - pub fn check_op_spanned(&mut self, op: O, span: Span) -> CheckOpResult + /// context. + pub fn check_op_spanned(&mut self, op: O, span: Span) where O: NonConstOp { trace!("check_op: op={:?}", op); if op.is_allowed_in_item(self) { - return CheckOpResult::Allowed; + return; } // If an operation is supported in miri (and is not already controlled by a feature gate) it @@ -276,20 +257,19 @@ pub fn check_op_spanned(&mut self, op: O, span: Span) -> CheckOpResult if is_unleashable && self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { self.tcx.sess.span_warn(span, "skipping const checks"); - return CheckOpResult::Unleashed; + return; } op.emit_error(self, span); - CheckOpResult::Forbidden } /// Emits an error if an expression cannot be evaluated in the current context. - pub fn check_op(&mut self, op: impl NonConstOp) -> CheckOpResult { + pub fn check_op(&mut self, op: impl NonConstOp) { let span = self.span; self.check_op_spanned(op, span) } - fn check_static(&mut self, def_id: DefId, span: Span) -> CheckOpResult { + fn check_static(&mut self, def_id: DefId, span: Span) { let is_thread_local = self.tcx.has_attr(def_id, sym::thread_local); if is_thread_local { self.check_op_spanned(ops::ThreadLocalAccess, span) @@ -322,20 +302,9 @@ fn visit_basic_block_data( fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location); - // Check nested operands and places. + // Special-case reborrows to be more like a copy of a reference. if let Rvalue::Ref(_, kind, ref place) = *rvalue { - // Special-case reborrows to be more like a copy of a reference. - let mut reborrow_place = None; - if let &[ref proj_base @ .., elem] = place.projection.as_ref() { - if elem == ProjectionElem::Deref { - let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; - if let ty::Ref(..) = base_ty.kind { - reborrow_place = Some(proj_base); - } - } - } - - if let Some(proj) = reborrow_place { + if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, &*self.body, place) { let ctx = match kind { BorrowKind::Shared => PlaceContext::NonMutatingUse( NonMutatingUseContext::SharedBorrow, @@ -351,14 +320,13 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { ), }; self.visit_place_base(&place.base, ctx, location); - self.visit_projection(&place.base, proj, ctx, location); - } else { - self.super_rvalue(rvalue, location); + self.visit_projection(&place.base, reborrowed_proj, ctx, location); + return; } - } else { - self.super_rvalue(rvalue, location); } + self.super_rvalue(rvalue, location); + match *rvalue { Rvalue::Use(_) | Rvalue::Repeat(..) | @@ -369,11 +337,60 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { Rvalue::Cast(CastKind::Pointer(_), ..) | Rvalue::Discriminant(..) | Rvalue::Len(_) | - Rvalue::Ref(..) | Rvalue::Aggregate(..) => {} + | Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place) + | Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) + => { + let ty = place.ty(&*self.body, self.tcx).ty; + let is_allowed = match ty.kind { + // Inside a `static mut`, `&mut [...]` is allowed. + ty::Array(..) | ty::Slice(_) if self.const_kind() == ConstKind::StaticMut + => true, + + // FIXME(ecstaticmorse): We could allow `&mut []` inside a const context given + // that this is merely a ZST and it is already eligible for promotion. + // This may require an RFC? + /* + ty::Array(_, len) if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0) + => true, + */ + + _ => false, + }; + + if !is_allowed { + self.check_op(ops::MutBorrow(kind)); + } + } + + // At the moment, `PlaceBase::Static` is only used for promoted MIR. + | Rvalue::Ref(_, BorrowKind::Shared, ref place) + | Rvalue::Ref(_, BorrowKind::Shallow, ref place) + if matches!(place.base, PlaceBase::Static(_)) + => bug!("Saw a promoted during const-checking, which must run before promotion"), + + | Rvalue::Ref(_, kind @ BorrowKind::Shared, ref place) + | Rvalue::Ref(_, kind @ BorrowKind::Shallow, ref place) + => { + // FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually + // seek the cursors beforehand. + self.qualifs.has_mut_interior.cursor.seek_before(location); + self.qualifs.indirectly_mutable.seek(location); + + let borrowed_place_has_mut_interior = HasMutInterior::in_place( + &self.item, + &|local| self.qualifs.has_mut_interior_eager_seek(local), + place.as_ref(), + ); + + if borrowed_place_has_mut_interior { + self.check_op(ops::MutBorrow(kind)); + } + } + Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { - let operand_ty = operand.ty(self.body, self.tcx); + let operand_ty = operand.ty(&*self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); @@ -384,7 +401,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { } Rvalue::BinaryOp(op, ref lhs, _) => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind { + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(&*self.body, self.tcx).kind { assert!(op == BinOp::Eq || op == BinOp::Ne || op == BinOp::Le || op == BinOp::Lt || op == BinOp::Ge || op == BinOp::Gt || @@ -436,58 +453,6 @@ fn visit_operand( } } - fn visit_assign(&mut self, dest: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { - trace!("visit_assign: dest={:?} rvalue={:?} location={:?}", dest, rvalue, location); - - // Error on mutable borrows or shared borrows of values with interior mutability. - // - // This replicates the logic at the start of `assign` in the old const checker. Note that - // it depends on `HasMutInterior` being set for mutable borrows as well as values with - // interior mutability. - if let Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue { - // FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually seek - // the cursors beforehand. - self.qualifs.has_mut_interior.cursor.seek_before(location); - self.qualifs.indirectly_mutable.seek(location); - - let rvalue_has_mut_interior = HasMutInterior::in_rvalue( - &self.item, - &|local| self.qualifs.has_mut_interior_eager_seek(local), - rvalue, - ); - - if rvalue_has_mut_interior { - let is_derived_from_illegal_borrow = match borrowed_place.as_local() { - // If an unprojected local was borrowed and its value was the result of an - // illegal borrow, suppress this error and mark the result of this borrow as - // illegal as well. - Some(borrowed_local) - if self.derived_from_illegal_borrow.contains(borrowed_local) => - { - true - } - - // Otherwise proceed normally: check the legality of a mutable borrow in this - // context. - _ => self.check_op(ops::MutBorrow(kind)) == CheckOpResult::Forbidden, - }; - - // When the target of the assignment is a local with no projections, mark it as - // derived from an illegal borrow if necessary. - // - // FIXME: should we also clear `derived_from_illegal_borrow` when a local is - // assigned a new value? - if is_derived_from_illegal_borrow { - if let Some(dest) = dest.as_local() { - self.derived_from_illegal_borrow.insert(dest); - } - } - } - } - - self.super_assign(dest, rvalue, location); - } - fn visit_projection_elem( &mut self, place_base: &PlaceBase<'tcx>, @@ -510,7 +475,7 @@ fn visit_projection_elem( match elem { ProjectionElem::Deref => { - let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty; + let base_ty = Place::ty_from(place_base, proj_base, &*self.body, self.tcx).ty; if let ty::RawPtr(_) = base_ty.kind { if proj_base.is_empty() { if let (PlaceBase::Local(local), []) = (place_base, proj_base) { @@ -534,7 +499,7 @@ fn visit_projection_elem( ProjectionElem::Subslice {..} | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty; + let base_ty = Place::ty_from(place_base, proj_base, &*self.body, self.tcx).ty; match base_ty.ty_adt_def() { Some(def) if def.is_union() => { self.check_op(ops::UnionAccess); @@ -583,7 +548,7 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Locat match kind { TerminatorKind::Call { func, .. } => { - let fn_ty = func.ty(self.body, self.tcx); + let fn_ty = func.ty(&*self.body, self.tcx); let def_id = match fn_ty.kind { ty::FnDef(def_id, _) => def_id, @@ -644,7 +609,7 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Locat // Check to see if the type of this place can ever have a drop impl. If not, this // `Drop` terminator is frivolous. let ty_needs_drop = dropped_place - .ty(self.body, self.tcx) + .ty(&*self.body, self.tcx) .ty .needs_drop(self.tcx, self.param_env); @@ -724,3 +689,36 @@ fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) } }); } + +fn place_as_reborrow( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + place: &'a Place<'tcx>, +) -> Option<&'a [PlaceElem<'tcx>]> { + place + .projection + .split_last() + .and_then(|(outermost, inner)| { + if outermost != &ProjectionElem::Deref { + return None; + } + + // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const` + // that points to the allocation for the static. Don't treat these as reborrows. + if let PlaceBase::Local(local) = place.base { + if body.local_decls[local].is_ref_to_static() { + return None; + } + } + + // Ensure the type being derefed is a reference and not a raw pointer. + // + // This is sufficient to prevent an access to a `static mut` from being marked as a + // reborrow, even if the check above were to disappear. + let inner_ty = Place::ty_from(&place.base, inner, body, tcx).ty; + match inner_ty.kind { + ty::Ref(..) => Some(inner), + _ => None, + } + }) +} diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index b7cc4e9fcf6..2c45dcfbe26 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -1,6 +1,4 @@ use rustc_data_structures::fx::FxHashSet; -use rustc_index::vec::IndexVec; -use rustc_data_structures::sync::Lrc; use rustc::ty::query::Providers; use rustc::ty::{self, TyCtxt}; @@ -24,7 +22,6 @@ pub struct UnsafetyChecker<'a, 'tcx> { body: &'a Body<'tcx>, const_context: bool, min_const_fn: bool, - source_scope_local_data: &'a IndexVec, violations: Vec, source_info: SourceInfo, tcx: TyCtxt<'tcx>, @@ -39,7 +36,6 @@ fn new( const_context: bool, min_const_fn: bool, body: &'a Body<'tcx>, - source_scope_local_data: &'a IndexVec, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Self { @@ -51,7 +47,6 @@ fn new( body, const_context, min_const_fn, - source_scope_local_data, violations: vec![], source_info: SourceInfo { span: body.span, @@ -219,8 +214,11 @@ fn visit_place(&mut self, if context.is_borrow() { if util::is_disaligned(self.tcx, self.body, self.param_env, place) { let source_info = self.source_info; - let lint_root = - self.source_scope_local_data[source_info.scope].lint_root; + let lint_root = self.body.source_scopes[source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; self.register_violations(&[UnsafetyViolation { source_info, description: Symbol::intern("borrow of packed field"), @@ -346,7 +344,11 @@ fn require_unsafe( fn register_violations(&mut self, violations: &[UnsafetyViolation], unsafe_blocks: &[(hir::HirId, bool)]) { - let safety = self.source_scope_local_data[self.source_info.scope].safety; + let safety = self.body.source_scopes[self.source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .safety; let within_unsafe = match safety { // `unsafe` blocks are required in safe code Safety::Safe => { @@ -516,17 +518,6 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: DefId) -> UnsafetyCheckResult // `mir_built` force this. let body = &tcx.mir_built(def_id).borrow(); - let source_scope_local_data = match body.source_scope_local_data { - ClearCrossCrate::Set(ref data) => data, - ClearCrossCrate::Clear => { - debug!("unsafety_violations: {:?} - remote, skipping", def_id); - return UnsafetyCheckResult { - violations: Lrc::new([]), - unsafe_blocks: Lrc::new([]) - } - } - }; - let param_env = tcx.param_env(def_id); let id = tcx.hir().as_local_hir_id(def_id).unwrap(); @@ -536,9 +527,10 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: DefId) -> UnsafetyCheckResult hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false), }; - let mut checker = UnsafetyChecker::new( - const_context, min_const_fn, - body, source_scope_local_data, tcx, param_env); + let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body, tcx, param_env); + // mir_built ensures that body has a computed cache, so we don't (and can't) attempt to + // recompute it here. + let body = body.unwrap_read_only(); checker.visit_body(body); check_unused_unsafe(tcx, def_id, &checker.used_unsafe, &mut checker.inherited_blocks); diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index 4fd4fe45cd4..d9dd7c9d847 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -16,7 +16,7 @@ //! [`FakeRead`]: rustc::mir::StatementKind::FakeRead //! [`Nop`]: rustc::mir::StatementKind::Nop -use rustc::mir::{BorrowKind, Rvalue, Location, Body}; +use rustc::mir::{BodyCache, BorrowKind, Rvalue, Location}; use rustc::mir::{Statement, StatementKind}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; @@ -29,7 +29,9 @@ pub struct DeleteNonCodegenStatements<'tcx> { } impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass( + &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyCache<'tcx> + ) { let mut delete = DeleteNonCodegenStatements { tcx }; delete.visit_body(body); } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 0fe75301fc1..a99ca71d167 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -7,9 +7,10 @@ use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; use rustc::mir::{ - AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, Local, UnOp, - StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, - BinOp, SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock, RETURN_PLACE, + AggregateKind, Constant, Location, Place, PlaceBase, Body, BodyCache, Operand, Local, UnOp, + Rvalue, StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate, + SourceInfo, BinOp, SourceScope, SourceScopeData, LocalDecl, BasicBlock, ReadOnlyBodyCache, + read_only, RETURN_PLACE }; use rustc::mir::visit::{ Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, @@ -41,7 +42,9 @@ pub struct ConstProp; impl<'tcx> MirPass<'tcx> for ConstProp { - fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass( + &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx> + ) { // will be evaluated by miri and produce its errors there if source.promoted.is_some() { return; @@ -74,17 +77,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<' trace!("ConstProp starting for {:?}", source.def_id()); - // Steal some data we need from `body`. - let source_scope_local_data = std::mem::replace( - &mut body.source_scope_local_data, - ClearCrossCrate::Clear - ); - let dummy_body = &Body::new( body.basic_blocks().clone(), - Default::default(), - ClearCrossCrate::Clear, + body.source_scopes.clone(), body.local_decls.clone(), Default::default(), body.arg_count, @@ -99,21 +95,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<' // That would require an uniform one-def no-mutation analysis // and RPO (or recursing when needing the value of a local). let mut optimization_finder = ConstPropagator::new( - body, + read_only!(body), dummy_body, - source_scope_local_data, tcx, source ); optimization_finder.visit_body(body); - // put back the data we stole from `mir` - let source_scope_local_data = optimization_finder.release_stolen_data(); - std::mem::replace( - &mut body.source_scope_local_data, - source_scope_local_data - ); - trace!("ConstProp done for {:?}", source.def_id()); } } @@ -171,6 +159,15 @@ fn call_intrinsic( throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp")); } + fn assert_panic( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _span: Span, + _msg: &rustc::mir::interpret::AssertMessage<'tcx>, + _unwind: Option, + ) -> InterpResult<'tcx> { + bug!("panics terminators are not evaluated in ConstProp"); + } + fn ptr_to_int( _mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer, @@ -197,7 +194,7 @@ fn find_foreign_static( } #[inline(always)] - fn tag_allocation<'b>( + fn init_allocation_extra<'b>( _memory_extra: &(), _id: AllocId, alloc: Cow<'b, Allocation>, @@ -267,7 +264,9 @@ struct ConstPropagator<'mir, 'tcx> { source: MirSource<'tcx>, can_const_prop: IndexVec, param_env: ParamEnv<'tcx>, - source_scope_local_data: ClearCrossCrate>, + // FIXME(eddyb) avoid cloning these two fields more than once, + // by accessing them through `ecx` instead. + source_scopes: IndexVec, local_decls: IndexVec>, ret: Option>, } @@ -297,9 +296,8 @@ fn tcx(&self) -> TyCtxt<'tcx> { impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn new( - body: &Body<'tcx>, + body: ReadOnlyBodyCache<'_, 'tcx>, dummy_body: &'mir Body<'tcx>, - source_scope_local_data: ClearCrossCrate>, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, ) -> ConstPropagator<'mir, 'tcx> { @@ -337,17 +335,15 @@ fn new( source, param_env, can_const_prop, - source_scope_local_data, + // FIXME(eddyb) avoid cloning these two fields more than once, + // by accessing them through `ecx` instead. + source_scopes: body.source_scopes.clone(), //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it local_decls: body.local_decls.clone(), ret: ret.map(Into::into), } } - fn release_stolen_data(self) -> ClearCrossCrate> { - self.source_scope_local_data - } - fn get_const(&self, local: Local) -> Option> { if local == RETURN_PLACE { // Try to read the return place as an immediate so that if it is representable as a @@ -377,14 +373,11 @@ fn use_ecx( F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, { self.ecx.tcx.span = source_info.span; - let lint_root = match self.source_scope_local_data { - ClearCrossCrate::Set(ref ivs) => { - //FIXME(#51314): remove this check - if source_info.scope.index() >= ivs.len() { - return None; - } - ivs[source_info.scope].lint_root - }, + // FIXME(eddyb) move this to the `Panic(_)` error case, so that + // `f(self)` is always called, and that the only difference when the + // scope's `local_data` is missing, is that the lint isn't emitted. + let lint_root = match &self.source_scopes[source_info.scope].local_data { + ClearCrossCrate::Set(data) => data.lint_root, ClearCrossCrate::Clear => return None, }; let r = match f(self) { @@ -396,7 +389,7 @@ fn use_ecx( InterpError::* }; match error.kind { - Exit(_) => bug!("the CTFE program cannot exit"), + MachineStop(_) => bug!("ConstProp does not stop"), // Some error shouldn't come up because creating them causes // an allocation, which we should avoid. When that happens, @@ -525,8 +518,8 @@ fn const_prop( let right_size = r.layout.size; let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { - let source_scope_local_data = match self.source_scope_local_data { - ClearCrossCrate::Set(ref data) => data, + let lint_root = match &self.source_scopes[source_info.scope].local_data { + ClearCrossCrate::Set(data) => data.lint_root, ClearCrossCrate::Clear => return None, }; let dir = if *op == BinOp::Shr { @@ -534,10 +527,9 @@ fn const_prop( } else { "left" }; - let hir_id = source_scope_local_data[source_info.scope].lint_root; self.tcx.lint_hir( ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, - hir_id, + lint_root, span, &format!("attempt to shift {} with overflow", dir)); return None; @@ -698,7 +690,7 @@ struct CanConstProp { impl CanConstProp { /// returns true if `local` can be propagated - fn check(body: &Body<'_>) -> IndexVec { + fn check(body: ReadOnlyBodyCache<'_, '_>) -> IndexVec { let mut cpv = CanConstProp { can_const_prop: IndexVec::from_elem(true, &body.local_decls), found_assignment: IndexVec::from_elem(false, &body.local_decls), diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 4c26feac4af..5e4caf2f36d 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -19,7 +19,10 @@ //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the //! future. -use rustc::mir::{Constant, Local, LocalKind, Location, Place, Body, Operand, Rvalue, StatementKind}; +use rustc::mir::{ + Constant, Local, LocalKind, Location, Place, Body, BodyCache, Operand, Rvalue, + StatementKind, read_only +}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; use crate::transform::{MirPass, MirSource}; @@ -28,7 +31,9 @@ pub struct CopyPropagation; impl<'tcx> MirPass<'tcx> for CopyPropagation { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass( + &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyCache<'tcx> + ) { // We only run when the MIR optimization level is > 1. // This avoids a slow pass, and messing up debug info. if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { @@ -37,10 +42,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body< let mut def_use_analysis = DefUseAnalysis::new(body); loop { - def_use_analysis.analyze(body); + def_use_analysis.analyze(read_only!(body)); if eliminate_self_assignments(body, &def_use_analysis) { - def_use_analysis.analyze(body); + def_use_analysis.analyze(read_only!(body)); } let mut changed = false; @@ -97,7 +102,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body< let maybe_action = match operand { Operand::Copy(ref src_place) | Operand::Move(ref src_place) => { - Action::local_copy(&body, &def_use_analysis, src_place) + Action::local_copy( + &body, + &def_use_analysis, + src_place) } Operand::Constant(ref src_constant) => { Action::constant(src_constant) @@ -126,8 +134,8 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body< } } - changed = - action.perform(body, &def_use_analysis, dest_local, location, tcx) || changed; + changed = action.perform(body, &def_use_analysis, dest_local, location, tcx) + || changed; // FIXME(pcwalton): Update the use-def chains to delete the instructions instead of // regenerating the chains. break @@ -242,7 +250,7 @@ fn constant(src_constant: &Constant<'tcx>) -> Option> { } fn perform(self, - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, def_use_analysis: &DefUseAnalysis, dest_local: Local, location: Location, @@ -270,7 +278,8 @@ fn perform(self, } // Replace all uses of the destination local with the source local. - def_use_analysis.replace_all_defs_and_uses_with(dest_local, body, src_local, tcx); + def_use_analysis + .replace_all_defs_and_uses_with(dest_local, body, src_local, tcx); // Finally, zap the now-useless assignment instruction. debug!(" Deleting assignment"); diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index cdde9e12edc..933936e7eff 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -6,7 +6,9 @@ pub struct Deaggregator; impl<'tcx> MirPass<'tcx> for Deaggregator { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass( + &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyCache<'tcx> + ) { let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); let local_decls = &*local_decls; for bb in basic_blocks { diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index ed0eff943a1..13b3bb6da4e 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -5,7 +5,7 @@ use std::fs::File; use std::io; -use rustc::mir::Body; +use rustc::mir::{Body, BodyCache}; use rustc::session::config::{OutputFilenames, OutputType}; use rustc::ty::TyCtxt; use crate::transform::{MirPass, MirSource}; @@ -18,8 +18,9 @@ fn name(&self) -> Cow<'_, str> { Cow::Borrowed(self.0) } - fn run_pass(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut Body<'tcx>) { - } + fn run_pass( + &self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut BodyCache<'tcx> + ) {} } pub struct Disambiguator { diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index f91a08bcd9a..42daba93bd2 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -21,7 +21,7 @@ pub struct ElaborateDrops; impl<'tcx> MirPass<'tcx> for ElaborateDrops { - fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", src, body.span); let def_id = src.def_id(); diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index b30e2de4ca0..882e67432a5 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -62,7 +62,7 @@ fn process_projection_elem( pub struct EraseRegions; impl<'tcx> MirPass<'tcx> for EraseRegions { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { EraseRegionsVisitor::new(tcx).visit_body(body); } } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 5d88629435b..e55737e8859 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -368,7 +368,7 @@ fn visit_basic_block_data(&mut self, VariantIdx::new(RETURNED) // state for returned }; data.statements.push(self.set_discr(state, source_info)); - data.terminator.as_mut().unwrap().kind = TerminatorKind::Return; + data.terminator_mut().kind = TerminatorKind::Return; } self.super_basic_block_data(block, data); @@ -378,7 +378,7 @@ fn visit_basic_block_data(&mut self, fn make_generator_state_argument_indirect<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, ) { let gen_ty = body.local_decls.raw[1].ty; @@ -401,7 +401,7 @@ fn make_generator_state_argument_indirect<'tcx>( DerefArgVisitor { tcx }.visit_body(body); } -fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>) { let ref_gen_ty = body.local_decls.raw[1].ty; let pin_did = tcx.lang_items().pin_type().unwrap(); @@ -418,7 +418,7 @@ fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body fn replace_result_variable<'tcx>( ret_ty: Ty<'tcx>, - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, tcx: TyCtxt<'tcx>, ) -> Local { let source_info = source_info(body); @@ -481,20 +481,21 @@ struct LivenessInfo { fn locals_live_across_suspend_points( tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, + body: ReadOnlyBodyCache<'_, 'tcx>, source: MirSource<'tcx>, movable: bool, ) -> LivenessInfo { let dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); let def_id = source.def_id(); + let body_ref: &Body<'_> = &body; // Calculate when MIR locals have live storage. This gives us an upper bound of their // lifetimes. - let storage_live_analysis = MaybeStorageLive::new(body); + let storage_live_analysis = MaybeStorageLive::new(body_ref); let storage_live_results = - do_dataflow(tcx, body, def_id, &[], &dead_unwinds, storage_live_analysis, + do_dataflow(tcx, body_ref, def_id, &[], &dead_unwinds, storage_live_analysis, |bd, p| DebugFormatted::new(&bd.body().local_decls[p])); - let mut storage_live_cursor = DataflowResultsCursor::new(&storage_live_results, body); + let mut storage_live_cursor = DataflowResultsCursor::new(&storage_live_results, body_ref); // Find the MIR locals which do not use StorageLive/StorageDead statements. // The storage of these locals are always live. @@ -503,19 +504,20 @@ fn locals_live_across_suspend_points( // Calculate the MIR locals which have been previously // borrowed (even if they are still active). - let borrowed_locals_analysis = HaveBeenBorrowedLocals::new(body); + let borrowed_locals_analysis = HaveBeenBorrowedLocals::new(body_ref); let borrowed_locals_results = - do_dataflow(tcx, body, def_id, &[], &dead_unwinds, borrowed_locals_analysis, + do_dataflow(tcx, body_ref, def_id, &[], &dead_unwinds, borrowed_locals_analysis, |bd, p| DebugFormatted::new(&bd.body().local_decls[p])); - let mut borrowed_locals_cursor = DataflowResultsCursor::new(&borrowed_locals_results, body); + let mut borrowed_locals_cursor = DataflowResultsCursor::new(&borrowed_locals_results, body_ref); // Calculate the MIR locals that we actually need to keep storage around // for. let requires_storage_analysis = RequiresStorage::new(body, &borrowed_locals_results); let requires_storage_results = - do_dataflow(tcx, body, def_id, &[], &dead_unwinds, requires_storage_analysis, + do_dataflow(tcx, body_ref, def_id, &[], &dead_unwinds, requires_storage_analysis, |bd, p| DebugFormatted::new(&bd.body().local_decls[p])); - let mut requires_storage_cursor = DataflowResultsCursor::new(&requires_storage_results, body); + let mut requires_storage_cursor + = DataflowResultsCursor::new(&requires_storage_results, body_ref); // Calculate the liveness of MIR locals ignoring borrows. let mut live_locals = liveness::LiveVarSet::new_empty(body.local_decls.len()); @@ -526,7 +528,7 @@ fn locals_live_across_suspend_points( tcx, "generator_liveness", source, - body, + body_ref, &liveness, ); @@ -593,7 +595,7 @@ fn locals_live_across_suspend_points( .collect(); let storage_conflicts = compute_storage_conflicts( - body, + body_ref, &live_locals, &ignored, requires_storage_results); @@ -749,7 +751,7 @@ fn compute_layout<'tcx>( upvars: &Vec>, interior: Ty<'tcx>, movable: bool, - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, ) -> ( FxHashMap, VariantIdx, usize)>, GeneratorLayout<'tcx>, @@ -758,7 +760,7 @@ fn compute_layout<'tcx>( // Use a liveness analysis to compute locals which are live across a suspension point let LivenessInfo { live_locals, live_locals_at_suspension_points, storage_conflicts, storage_liveness - } = locals_live_across_suspend_points(tcx, body, source, movable); + } = locals_live_across_suspend_points(tcx, read_only!(body), source, movable); // Erase regions from the types passed in from typeck so we can compare them with // MIR types @@ -828,7 +830,7 @@ fn compute_layout<'tcx>( } fn insert_switch<'tcx>( - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, cases: Vec<(usize, BasicBlock)>, transform: &TransformVisitor<'tcx>, default: TerminatorKind<'tcx>, @@ -859,7 +861,9 @@ fn insert_switch<'tcx>( } } -fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut Body<'tcx>) { +fn elaborate_generator_drops<'tcx>( + tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut BodyCache<'tcx> +) { use crate::util::elaborate_drops::{elaborate_drop, Unwind}; use crate::util::patch::MirPatch; use crate::shim::DropShimElaborator; @@ -872,7 +876,7 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut let gen = self_arg(); let mut elaborator = DropShimElaborator { - body: body, + body, patch: MirPatch::new(body), tcx, param_env @@ -924,9 +928,9 @@ fn create_generator_drop_shim<'tcx>( def_id: DefId, source: MirSource<'tcx>, gen_ty: Ty<'tcx>, - body: &Body<'tcx>, + body: &mut BodyCache<'tcx>, drop_clean: BasicBlock, -) -> Body<'tcx> { +) -> BodyCache<'tcx> { let mut body = body.clone(); let source_info = source_info(&body); @@ -992,7 +996,9 @@ fn create_generator_drop_shim<'tcx>( body } -fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock { +fn insert_term_block<'tcx>( + body: &mut BodyCache<'tcx>, kind: TerminatorKind<'tcx> +) -> BasicBlock { let term_block = BasicBlock::new(body.basic_blocks().len()); let source_info = source_info(body); body.basic_blocks_mut().push(BasicBlockData { @@ -1008,7 +1014,7 @@ fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> fn insert_panic_block<'tcx>( tcx: TyCtxt<'tcx>, - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, message: AssertMessage<'tcx>, ) -> BasicBlock { let assert_block = BasicBlock::new(body.basic_blocks().len()); @@ -1042,7 +1048,7 @@ fn create_generator_resume_function<'tcx>( transform: TransformVisitor<'tcx>, def_id: DefId, source: MirSource<'tcx>, - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, ) { // Poison the generator when it unwinds for block in body.basic_blocks_mut() { @@ -1095,7 +1101,7 @@ fn source_info(body: &Body<'_>) -> SourceInfo { } } -fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock { +fn insert_clean_drop(body: &mut BodyCache<'_>) -> BasicBlock { let return_block = insert_term_block(body, TerminatorKind::Return); // Create a block to destroy an unresumed generators. This can only destroy upvars. @@ -1119,7 +1125,7 @@ fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock { } fn create_cases<'tcx, F>( - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, transform: &TransformVisitor<'tcx>, target: F, ) -> Vec<(usize, BasicBlock)> @@ -1163,7 +1169,9 @@ fn create_cases<'tcx, F>( } impl<'tcx> MirPass<'tcx> for StateTransform { - fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass( + &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx> + ) { let yield_ty = if let Some(yield_ty) = body.yield_ty { yield_ty } else { @@ -1252,12 +1260,12 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<' // Create a copy of our MIR and use it to create the drop shim for the generator let drop_shim = create_generator_drop_shim(tcx, - &transform, - def_id, - source, - gen_ty, - &body, - drop_clean); + &transform, + def_id, + source, + gen_ty, + body, + drop_clean); body.generator_drop = Some(box drop_shim); diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 867673beb35..79cb7fb0b76 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -38,7 +38,9 @@ struct CallSite<'tcx> { } impl<'tcx> MirPass<'tcx> for Inline { - fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass( + &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx> + ) { if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { Inliner { tcx, source }.run_pass(body); } @@ -51,7 +53,7 @@ struct Inliner<'tcx> { } impl Inliner<'tcx> { - fn run_pass(&self, caller_body: &mut Body<'tcx>) { + fn run_pass(&self, caller_body: &mut BodyCache<'tcx>) { // Keep a queue of callsites to try inlining on. We take // advantage of the fact that queries detect cycles here to // allow us to try and fetch the fully optimized MIR of a @@ -75,9 +77,9 @@ fn run_pass(&self, caller_body: &mut Body<'tcx>) { { for (bb, bb_data) in caller_body.basic_blocks().iter_enumerated() { if let Some(callsite) = self.get_valid_function_call(bb, - bb_data, - caller_body, - param_env) { + bb_data, + caller_body, + param_env) { callsites.push_back(callsite); } } @@ -136,7 +138,8 @@ fn run_pass(&self, caller_body: &mut Body<'tcx>) { debug!("attempting to inline callsite {:?} - success", callsite); // Add callsites from inlined function - for (bb, bb_data) in caller_body.basic_blocks().iter_enumerated().skip(start) { + for (bb, bb_data) in caller_body.basic_blocks().iter_enumerated().skip(start) + { if let Some(new_callsite) = self.get_valid_function_call(bb, bb_data, caller_body, @@ -377,8 +380,8 @@ fn should_inline(&self, fn inline_call(&self, callsite: CallSite<'tcx>, - caller_body: &mut Body<'tcx>, - mut callee_body: Body<'tcx>) -> bool { + caller_body: &mut BodyCache<'tcx>, + mut callee_body: BodyCache<'tcx>) -> bool { let terminator = caller_body[callsite.bb].terminator.take().unwrap(); match terminator.kind { // FIXME: Handle inlining of diverging calls @@ -391,9 +394,14 @@ fn inline_call(&self, for mut scope in callee_body.source_scopes.iter().cloned() { if scope.parent_scope.is_none() { scope.parent_scope = Some(callsite.location.scope); + // FIXME(eddyb) is this really needed? + // (also note that it's always overwritten below) scope.span = callee_body.span; } + // FIXME(eddyb) this doesn't seem right at all. + // The inlined source scopes should probably be annotated as + // such, but also contain all of the original information. scope.span = callsite.location.span; let idx = caller_body.source_scopes.push(scope); @@ -440,7 +448,7 @@ fn dest_needs_borrow(place: &Place<'_>) -> bool { BorrowKind::Mut { allow_two_phase_borrow: false }, destination.0); - let ty = dest.ty(caller_body, self.tcx); + let ty = dest.ty(&**caller_body, self.tcx); let temp = LocalDecl::new_temp(ty, callsite.location.span); @@ -509,7 +517,7 @@ fn make_call_args( &self, args: Vec>, callsite: &CallSite<'tcx>, - caller_body: &mut Body<'tcx>, + caller_body: &mut BodyCache<'tcx>, ) -> Vec { let tcx = self.tcx; @@ -538,12 +546,14 @@ fn make_call_args( // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. if tcx.is_closure(callsite.callee) { let mut args = args.into_iter(); - let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); - let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); + let self_ + = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); + let tuple + = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); assert!(args.next().is_none()); let tuple = Place::from(tuple); - let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind { + let tuple_tys = if let ty::Tuple(s) = tuple.ty(&**caller_body, tcx).ty.kind { s } else { bug!("Closure arguments are not passed as a tuple"); @@ -580,7 +590,7 @@ fn create_temp_if_necessary( &self, arg: Operand<'tcx>, callsite: &CallSite<'tcx>, - caller_body: &mut Body<'tcx>, + caller_body: &mut BodyCache<'tcx>, ) -> Local { // FIXME: Analysis of the usage of the arguments to avoid // unnecessary temporaries. @@ -598,7 +608,7 @@ fn create_temp_if_necessary( // Otherwise, create a temporary for the arg let arg = Rvalue::Use(arg); - let ty = arg.ty(caller_body, self.tcx); + let ty = arg.ty(&**caller_body, self.tcx); let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span); let arg_tmp = caller_body.local_decls.push(arg_tmp); diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index a567ed668bf..bd237b58132 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -1,7 +1,8 @@ //! Performs various peephole optimizations. use rustc::mir::{ - Constant, Location, Place, PlaceBase, PlaceRef, Body, Operand, ProjectionElem, Rvalue, Local + Constant, Location, Place, PlaceBase, PlaceRef, Body, BodyCache, Operand, ProjectionElem, + Rvalue, Local, read_only }; use rustc::mir::visit::{MutVisitor, Visitor}; use rustc::ty::{self, TyCtxt}; @@ -13,7 +14,7 @@ pub struct InstCombine; impl<'tcx> MirPass<'tcx> for InstCombine { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { // We only run when optimizing MIR (at any level). if tcx.sess.opts.debugging_opts.mir_opt_level == 0 { return @@ -23,8 +24,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) // read-only so that we can do global analyses on the MIR in the process (e.g. // `Place::ty()`). let optimizations = { + let read_only_cache = read_only!(body); let mut optimization_finder = OptimizationFinder::new(body, tcx); - optimization_finder.visit_body(body); + optimization_finder.visit_body(read_only_cache); optimization_finder.optimizations }; diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 2b2b52971ef..df4cb761533 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -1,7 +1,7 @@ use crate::{build, shim}; use rustc_index::vec::IndexVec; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc::mir::{Body, MirPhase, Promoted, ConstQualifs}; +use rustc::mir::{BodyCache, MirPhase, Promoted, ConstQualifs}; use rustc::ty::{TyCtxt, InstanceDef, TypeFoldable}; use rustc::ty::query::Providers; use rustc::ty::steal::Steal; @@ -97,7 +97,7 @@ fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> { tcx.arena.alloc(set) } -fn mir_built(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { +fn mir_built(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { let mir = build::mir_build(tcx, def_id); tcx.alloc_steal_mir(mir) } @@ -144,12 +144,12 @@ fn name(&self) -> Cow<'_, str> { default_name::() } - fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>); + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>); } pub fn run_passes( tcx: TyCtxt<'tcx>, - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, instance: InstanceDef<'tcx>, promoted: Option, mir_phase: MirPhase, @@ -205,7 +205,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs { } let item = check_consts::Item { - body, + body: body.unwrap_read_only(), tcx, def_id, const_kind, @@ -220,7 +220,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs { validator.qualifs_in_return_place().into() } -fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { +fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { // Unsafety check uses the raw mir, so make sure it is run let _ = tcx.unsafety_check_result(def_id); @@ -231,13 +231,14 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { &rustc_peek::SanityCheck, &uniform_array_move_out::UniformArrayMoveOut, ]); + body.ensure_predecessors(); tcx.alloc_steal_mir(body) } fn mir_validated( tcx: TyCtxt<'tcx>, def_id: DefId, -) -> (&'tcx Steal>, &'tcx Steal>>) { +) -> (&'tcx Steal>, &'tcx Steal>>) { // Ensure that we compute the `mir_const_qualif` for constants at // this point, before we steal the mir-const result. let _ = tcx.mir_const_qualif(def_id); @@ -249,13 +250,14 @@ fn mir_validated( &promote_pass, &simplify::SimplifyCfg::new("qualify-consts"), ]); + let promoted = promote_pass.promoted_fragments.into_inner(); (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted)) } fn run_optimization_passes<'tcx>( tcx: TyCtxt<'tcx>, - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, def_id: DefId, promoted: Option, ) { @@ -317,7 +319,7 @@ fn run_optimization_passes<'tcx>( ]); } -fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> { +fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &BodyCache<'_> { if tcx.is_constructor(def_id) { // There's no reason to run all of the MIR passes on constructors when // we can just output the MIR we want directly. This also saves const @@ -333,10 +335,11 @@ fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> { let (body, _) = tcx.mir_validated(def_id); let mut body = body.steal(); run_optimization_passes(tcx, &mut body, def_id, None); + body.ensure_predecessors(); tcx.arena.alloc(body) } -fn promoted_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx IndexVec> { +fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &IndexVec> { if tcx.is_constructor(def_id) { return tcx.intern_promoted(IndexVec::new()); } @@ -347,6 +350,7 @@ fn promoted_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx IndexVec) -> Self { } impl<'tcx> MirPass<'tcx> for NoLandingPads<'tcx> { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { no_landing_pads(tcx, body) } } -pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>) { if tcx.sess.no_landing_pads() { NoLandingPads::new(tcx).visit_body(body); } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index cc6108c7dc0..c99824bd356 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -41,11 +41,11 @@ /// newly created `StaticKind::Promoted`. #[derive(Default)] pub struct PromoteTemps<'tcx> { - pub promoted_fragments: Cell>>, + pub promoted_fragments: Cell>>, } impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { - fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { // There's not really any point in promoting errorful MIR. // // This does not include MIR that failed const-checking, which we still try to promote. @@ -63,7 +63,8 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx let mut rpo = traversal::reverse_postorder(body); let (temps, all_candidates) = collect_temps_and_candidates(tcx, body, &mut rpo); - let promotable_candidates = validate_candidates(tcx, body, def_id, &temps, &all_candidates); + let promotable_candidates + = validate_candidates(tcx, read_only!(body), def_id, &temps, &all_candidates); let promoted = promote_candidates(def_id, body, tcx, temps, promotable_candidates); self.promoted_fragments.set(promoted); @@ -346,10 +347,14 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> { while let [proj_base @ .., elem] = place_projection { // FIXME(eddyb) this is probably excessive, with // the exception of `union` member accesses. - let ty = - Place::ty_from(&place.base, proj_base, self.body, self.tcx) - .projection_ty(self.tcx, elem) - .ty; + let ty = Place::ty_from( + &place.base, + proj_base, + &*self.body, + self.tcx + ) + .projection_ty(self.tcx, elem) + .ty; if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) { has_mut_interior = false; break; @@ -368,7 +373,7 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> { } if let BorrowKind::Mut { .. } = kind { - let ty = place.ty(self.body, self.tcx).ty; + let ty = place.ty(&*self.body, self.tcx).ty; // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] @@ -517,7 +522,7 @@ fn validate_place(&self, place: PlaceRef<'_, 'tcx>) -> Result<(), Unpromotable> ProjectionElem::Field(..) => { if self.const_kind.is_none() { let base_ty = - Place::ty_from(place.base, proj_base, self.body, self.tcx).ty; + Place::ty_from(place.base, proj_base, &*self.body, self.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { // No promotion of union field accesses. if def.is_union() { @@ -566,7 +571,7 @@ fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { match *rvalue { Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.const_kind.is_none() => { - let operand_ty = operand.ty(self.body, self.tcx); + let operand_ty = operand.ty(&*self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); match (cast_in, cast_out) { @@ -580,7 +585,7 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { } Rvalue::BinaryOp(op, ref lhs, _) if self.const_kind.is_none() => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind { + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(&*self.body, self.tcx).kind { assert!(op == BinOp::Eq || op == BinOp::Ne || op == BinOp::Le || op == BinOp::Lt || op == BinOp::Ge || op == BinOp::Gt || @@ -615,7 +620,7 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { Rvalue::Ref(_, kind, place) => { if let BorrowKind::Mut { .. } = kind { - let ty = place.ty(self.body, self.tcx).ty; + let ty = place.ty(&*self.body, self.tcx).ty; // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] @@ -642,7 +647,7 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { let mut place = place.as_ref(); if let [proj_base @ .., ProjectionElem::Deref] = &place.projection { let base_ty = - Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty; + Place::ty_from(&place.base, proj_base, &*self.body, self.tcx).ty; if let ty::Ref(..) = base_ty.kind { place = PlaceRef { base: &place.base, @@ -668,7 +673,7 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { while let [proj_base @ .., elem] = place_projection { // FIXME(eddyb) this is probably excessive, with // the exception of `union` member accesses. - let ty = Place::ty_from(place.base, proj_base, self.body, self.tcx) + let ty = Place::ty_from(place.base, proj_base, &*self.body, self.tcx) .projection_ty(self.tcx, elem) .ty; if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) { @@ -701,7 +706,7 @@ fn validate_call( callee: &Operand<'tcx>, args: &[Operand<'tcx>], ) -> Result<(), Unpromotable> { - let fn_ty = callee.ty(self.body, self.tcx); + let fn_ty = callee.ty(&*self.body, self.tcx); if !self.explicit && self.const_kind.is_none() { if let ty::FnDef(def_id, _) = fn_ty.kind { @@ -737,7 +742,7 @@ fn validate_call( // FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`. pub fn validate_candidates( tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, + body: ReadOnlyBodyCache<'_, 'tcx>, def_id: DefId, temps: &IndexVec, candidates: &[Candidate], @@ -770,8 +775,8 @@ pub fn validate_candidates( struct Promoter<'a, 'tcx> { tcx: TyCtxt<'tcx>, - source: &'a mut Body<'tcx>, - promoted: Body<'tcx>, + source: &'a mut BodyCache<'tcx>, + promoted: BodyCache<'tcx>, temps: &'a mut IndexVec, /// If true, all nested temps are also kept in the @@ -919,7 +924,7 @@ fn promote_candidate( def_id: DefId, candidate: Candidate, next_promoted_id: usize, - ) -> Option> { + ) -> Option> { let mut operand = { let promoted = &mut self.promoted; let promoted_id = Promoted::new(next_promoted_id); @@ -1040,11 +1045,11 @@ fn process_projection_elem( pub fn promote_candidates<'tcx>( def_id: DefId, - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, tcx: TyCtxt<'tcx>, mut temps: IndexVec, candidates: Vec, -) -> IndexVec> { +) -> IndexVec> { // Visit candidates in reverse, in case they're nested. debug!("promote_candidates({:?})", candidates); @@ -1076,12 +1081,11 @@ pub fn promote_candidates<'tcx>( ).collect(); let promoter = Promoter { - promoted: Body::new( + promoted: BodyCache::new(Body::new( IndexVec::new(), // FIXME: maybe try to filter this to avoid blowing up // memory usage? body.source_scopes.clone(), - body.source_scope_local_data.clone(), initial_locals, IndexVec::new(), 0, @@ -1089,7 +1093,7 @@ pub fn promote_candidates<'tcx>( body.span, vec![], body.generator_kind, - ), + )), tcx, source: body, temps: &mut temps, @@ -1146,11 +1150,11 @@ pub fn promote_candidates<'tcx>( crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>( tcx: TyCtxt<'tcx>, mir_def_id: DefId, - body: &Body<'tcx>, + body: ReadOnlyBodyCache<'_, 'tcx>, operand: &Operand<'tcx>, ) -> bool { - let mut rpo = traversal::reverse_postorder(body); - let (temps, _) = collect_temps_and_candidates(tcx, body, &mut rpo); + let mut rpo = traversal::reverse_postorder(&body); + let (temps, _) = collect_temps_and_candidates(tcx, &body, &mut rpo); let validator = Validator { item: Item::new(tcx, mir_def_id, body), temps: &temps, diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index 130393e2c4c..c636aba9fc6 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -9,7 +9,7 @@ /// code for these. pub struct RemoveNoopLandingPads; -pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>) { if tcx.sess.no_landing_pads() { return } @@ -19,7 +19,7 @@ pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) } impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { remove_noop_landing_pads(tcx, body); } } @@ -84,7 +84,7 @@ fn is_nop_landing_pad( } } - fn remove_nop_landing_pads(&self, body: &mut Body<'_>) { + fn remove_nop_landing_pads(&self, body: &mut BodyCache<'_>) { // make sure there's a single resume block let resume_block = { let patch = MirPatch::new(body); diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index aada7641df6..794ced1cb0e 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -5,7 +5,7 @@ use rustc::ty::{self, TyCtxt, Ty}; use rustc::hir::def_id::DefId; -use rustc::mir::{self, Body, Location, Local}; +use rustc::mir::{self, Body, BodyCache, Location, Local}; use rustc_index::bit_set::BitSet; use crate::transform::{MirPass, MirSource}; @@ -26,7 +26,7 @@ pub struct SanityCheck; impl<'tcx> MirPass<'tcx> for SanityCheck { - fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { let def_id = src.def_id(); if !tcx.has_attr(def_id, sym::rustc_mir) { debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); @@ -64,10 +64,20 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_uninits); } if has_rustc_mir_with(&attributes, sym::rustc_peek_definite_init).is_some() { - sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_def_inits); + sanity_check_via_rustc_peek( + tcx, + body, + def_id, + &attributes, + &flow_def_inits); } if has_rustc_mir_with(&attributes, sym::rustc_peek_indirectly_mutable).is_some() { - sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_indirectly_mut); + sanity_check_via_rustc_peek( + tcx, + body, + def_id, + &attributes, + &flow_indirectly_mut); } if has_rustc_mir_with(&attributes, sym::stop_after_dataflow).is_some() { tcx.sess.fatal("stop_after_dataflow ended compilation"); diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index c9185d14148..900752d3ce0 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -43,7 +43,7 @@ pub fn new(label: &str) -> Self { } } -pub fn simplify_cfg(body: &mut Body<'_>) { +pub fn simplify_cfg(body: &mut BodyCache<'_>) { CfgSimplifier::new(body).simplify(); remove_dead_blocks(body); @@ -56,7 +56,9 @@ fn name(&self) -> Cow<'_, str> { Cow::Borrowed(&self.label) } - fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass( + &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx> + ) { debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body); simplify_cfg(body); } @@ -68,7 +70,7 @@ pub struct CfgSimplifier<'a, 'tcx> { } impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { - pub fn new(body: &'a mut Body<'tcx>) -> Self { + pub fn new(body: &'a mut BodyCache<'tcx>) -> Self { let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks()); // we can't use mir.predecessors() here because that counts @@ -124,8 +126,9 @@ pub fn simplify(mut self) { changed |= inner_changed; } - self.basic_blocks[bb].statements.extend(new_stmts); - self.basic_blocks[bb].terminator = Some(terminator); + let data = &mut self.basic_blocks[bb]; + data.statements.extend(new_stmts); + data.terminator = Some(terminator); changed |= inner_changed; } @@ -259,7 +262,7 @@ fn strip_nops(&mut self) { } } -pub fn remove_dead_blocks(body: &mut Body<'_>) { +pub fn remove_dead_blocks(body: &mut BodyCache<'_>) { let mut seen = BitSet::new_empty(body.basic_blocks().len()); for (bb, _) in traversal::preorder(body) { seen.insert(bb.index()); @@ -273,8 +276,8 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { for alive_index in seen.iter() { replacements[alive_index] = BasicBlock::new(used_blocks); if alive_index != used_blocks { - // Swap the next alive block data with the current available slot. Since alive_index is - // non-decreasing this is a valid operation. + // Swap the next alive block data with the current available slot. Since + // alive_index is non-decreasing this is a valid operation. basic_blocks.raw.swap(alive_index, used_blocks); } used_blocks += 1; @@ -292,14 +295,17 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { pub struct SimplifyLocals; impl<'tcx> MirPass<'tcx> for SimplifyLocals { - fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass( + &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx> + ) { trace!("running SimplifyLocals on {:?}", source); let locals = { + let read_only_cache = read_only!(body); let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()), body, }; - marker.visit_body(body); + marker.visit_body(read_only_cache); // Return pointer and arguments are always live marker.locals.insert(RETURN_PLACE); for arg in body.args_iter() { diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 0a509666d34..c8d0f37f9a5 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -19,7 +19,7 @@ fn name(&self) -> Cow<'_, str> { Cow::Borrowed(&self.label) } - fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { let param_env = tcx.param_env(src.def_id()); for block in body.basic_blocks_mut() { let terminator = block.terminator_mut(); diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs index 9dc5daa9b07..2235de9a153 100644 --- a/src/librustc_mir/transform/simplify_try.rs +++ b/src/librustc_mir/transform/simplify_try.rs @@ -33,7 +33,7 @@ pub struct SimplifyArmIdentity; impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { - fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); for bb in basic_blocks { // Need 3 statements: @@ -151,7 +151,7 @@ fn match_variant_field_place<'tcx>(place: &Place<'tcx>) -> Option<(Local, VarFie pub struct SimplifyBranchSame; impl<'tcx> MirPass<'tcx> for SimplifyBranchSame { - fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { let mut did_remove_blocks = false; let bbs = body.basic_blocks_mut(); for bb_idx in bbs.indices() { diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index 28f68ac2de0..3fc76ef6b00 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -37,12 +37,14 @@ pub struct UniformArrayMoveOut; impl<'tcx> MirPass<'tcx> for UniformArrayMoveOut { - fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { let mut patch = MirPatch::new(body); let param_env = tcx.param_env(src.def_id()); { - let mut visitor = UniformArrayMoveOutVisitor{body, patch: &mut patch, tcx, param_env}; - visitor.visit_body(body); + let read_only_cache = read_only!(body); + let mut visitor + = UniformArrayMoveOutVisitor{ body, patch: &mut patch, tcx, param_env}; + visitor.visit_body(read_only_cache); } patch.apply(body); } @@ -184,15 +186,16 @@ pub struct RestoreSubsliceArrayMoveOut<'tcx> { } impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut<'tcx> { - fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { let mut patch = MirPatch::new(body); let param_env = tcx.param_env(src.def_id()); { + let read_only_cache = read_only!(body); let mut visitor = RestoreDataCollector { locals_use: IndexVec::from_elem(LocalUse::new(), &body.local_decls), candidates: vec![], }; - visitor.visit_body(body); + visitor.visit_body(read_only_cache); for candidate in &visitor.candidates { let statement = &body[candidate.block].statements[candidate.statement_index]; @@ -217,8 +220,12 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2); let opt_size = opt_src_place.and_then(|src_place| { - let src_ty = - Place::ty_from(src_place.base, src_place.projection, body, tcx).ty; + let src_ty = Place::ty_from( + src_place.base, + src_place.projection, + &**body, + tcx + ).ty; if let ty::Array(_, ref size_o) = src_ty.kind { size_o.try_eval_usize(tcx, param_env) } else { diff --git a/src/librustc_mir/transform/uninhabited_enum_branching.rs b/src/librustc_mir/transform/uninhabited_enum_branching.rs index a6c18aee6a8..de070d75ad8 100644 --- a/src/librustc_mir/transform/uninhabited_enum_branching.rs +++ b/src/librustc_mir/transform/uninhabited_enum_branching.rs @@ -2,7 +2,8 @@ use crate::transform::{MirPass, MirSource}; use rustc::mir::{ - BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, TerminatorKind, + BasicBlock, BasicBlockData, Body, BodyCache, Local, Operand, Rvalue, StatementKind, + TerminatorKind, }; use rustc::ty::layout::{Abi, TyLayout, Variants}; use rustc::ty::{Ty, TyCtxt}; @@ -65,7 +66,7 @@ fn variant_discriminants<'tcx>( } impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { - fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>) { if source.promoted.is_some() { return; } diff --git a/src/librustc_mir/util/collect_writes.rs b/src/librustc_mir/util/collect_writes.rs index c8804dfbaf2..f94bea20024 100644 --- a/src/librustc_mir/util/collect_writes.rs +++ b/src/librustc_mir/util/collect_writes.rs @@ -1,5 +1,5 @@ use rustc::mir::{Local, Location}; -use rustc::mir::Body; +use rustc::mir::ReadOnlyBodyCache; use rustc::mir::visit::PlaceContext; use rustc::mir::visit::Visitor; @@ -9,10 +9,10 @@ fn find_assignments(&self, local: Local) -> Vec; } -impl<'tcx> FindAssignments for Body<'tcx>{ +impl<'a, 'tcx> FindAssignments for ReadOnlyBodyCache<'a, 'tcx>{ fn find_assignments(&self, local: Local) -> Vec{ let mut visitor = FindLocalAssignmentVisitor{ needle: local, locations: vec![]}; - visitor.visit_body(self); + visitor.visit_body(*self); visitor.locations } } diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index 1611caddad1..1907e9bdc97 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -1,6 +1,6 @@ //! Def-use analysis. -use rustc::mir::{Body, Local, Location, PlaceElem, VarDebugInfo}; +use rustc::mir::{Body, BodyCache, Local, Location, PlaceElem, ReadOnlyBodyCache, VarDebugInfo}; use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor}; use rustc::ty::TyCtxt; use rustc_index::vec::IndexVec; @@ -30,7 +30,7 @@ pub fn new(body: &Body<'_>) -> DefUseAnalysis { } } - pub fn analyze(&mut self, body: &Body<'_>) { + pub fn analyze(&mut self, body: ReadOnlyBodyCache<'_, '_>) { self.clear(); let mut finder = DefUseFinder { @@ -55,11 +55,11 @@ pub fn local_info(&self, local: Local) -> &Info { fn mutate_defs_and_uses( &self, local: Local, - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, new_local: Local, tcx: TyCtxt<'tcx>, ) { - let mut visitor = MutateUseVisitor::new(local, new_local, body, tcx); + let mut visitor = MutateUseVisitor::new(local, new_local, tcx); let info = &self.info[local]; for place_use in &info.defs_and_uses { visitor.visit_location(body, place_use.location) @@ -73,7 +73,7 @@ fn mutate_defs_and_uses( // FIXME(pcwalton): this should update the def-use chains. pub fn replace_all_defs_and_uses_with(&self, local: Local, - body: &mut Body<'tcx>, + body: &mut BodyCache<'tcx>, new_local: Local, tcx: TyCtxt<'tcx>) { self.mutate_defs_and_uses(local, body, new_local, tcx) @@ -156,7 +156,6 @@ impl MutateUseVisitor<'tcx> { fn new( query: Local, new_local: Local, - _: &Body<'tcx>, tcx: TyCtxt<'tcx>, ) -> MutateUseVisitor<'tcx> { MutateUseVisitor { query, new_local, tcx } diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 63e4af0a56a..334975373e5 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -57,7 +57,7 @@ pub struct LivenessResult { /// Computes which local variables are live within the given function /// `mir`, including drops. pub fn liveness_of_locals( - body: &Body<'_>, + body: ReadOnlyBodyCache<'_, '_>, ) -> LivenessResult { let num_live_vars = body.local_decls.len(); @@ -83,8 +83,9 @@ pub fn liveness_of_locals( // FIXME(ecstaticmorse): Reverse post-order on the reverse CFG may generate a better iteration // order when cycles are present, but the overhead of computing the reverse CFG may outweigh // any benefits. Benchmark this and find out. - let mut dirty_queue: WorkQueue = WorkQueue::with_none(body.basic_blocks().len()); - for (bb, _) in traversal::postorder(body) { + let mut dirty_queue: WorkQueue + = WorkQueue::with_none(body.basic_blocks().len()); + for (bb, _) in traversal::postorder(&body) { dirty_queue.insert(bb); } diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index a5f7e540157..47bb0b699c0 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -127,7 +127,7 @@ pub fn make_nop(&mut self, loc: Location) { self.make_nop.push(loc); } - pub fn apply(self, body: &mut Body<'tcx>) { + pub fn apply(self, body: &mut BodyCache<'tcx>) { debug!("MirPatch: make nops at: {:?}", self.make_nop); for loc in self.make_nop { body.make_statement_nop(loc); diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs index 26e51e83d62..1bf6e9ecbc0 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_parse/config.rs @@ -101,7 +101,7 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { if !attr.has_name(sym::cfg_attr) { return vec![attr]; } - if attr.get_normal_item().tokens.is_empty() { + if let ast::MacArgs::Empty = attr.get_normal_item().args { self.sess.span_diagnostic .struct_span_err( attr.span, diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 1215c7a199a..a22b383e5f3 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -277,7 +277,9 @@ pub fn parse_in_attr<'a, T>( ) -> PResult<'a, T> { let mut parser = Parser::new( sess, - attr.get_normal_item().tokens.clone(), + // FIXME(#66940, Centril | petrochenkov): refactor this function so it doesn't + // require reconstructing and immediately re-parsing delimiters. + attr.get_normal_item().args.outer_tokens(), None, false, false, @@ -409,7 +411,7 @@ fn prepend_attrs( brackets.push(stream); } - brackets.push(item.tokens.clone()); + brackets.push(item.args.outer_tokens()); // The span we list here for `#` and for `[ ... ]` are both wrong in // that it encompasses more than each token, but it hopefully is "good diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index 524b551e54c..c7261404f54 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -2,8 +2,7 @@ use syntax::attr; use syntax::ast; use syntax::util::comments; -use syntax::token::{self, Nonterminal, DelimToken}; -use syntax::tokenstream::{TokenStream, TokenTree}; +use syntax::token::{self, Nonterminal}; use syntax_pos::{Span, Symbol}; use errors::PResult; @@ -181,31 +180,8 @@ pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { item } else { let path = self.parse_path(PathStyle::Mod)?; - let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) || - self.check(&token::OpenDelim(DelimToken::Bracket)) || - self.check(&token::OpenDelim(DelimToken::Brace)) { - self.parse_token_tree().into() - } else if self.eat(&token::Eq) { - let eq = TokenTree::token(token::Eq, self.prev_span); - let mut is_interpolated_expr = false; - if let token::Interpolated(nt) = &self.token.kind { - if let token::NtExpr(..) = **nt { - is_interpolated_expr = true; - } - } - let token_tree = if is_interpolated_expr { - // We need to accept arbitrary interpolated expressions to continue - // supporting things like `doc = $expr` that work on stable. - // Non-literal interpolated expressions are rejected after expansion. - self.parse_token_tree() - } else { - self.parse_unsuffixed_lit()?.token_tree() - }; - TokenStream::new(vec![eq.into(), token_tree.into()]) - } else { - TokenStream::default() - }; - ast::AttrItem { path, tokens } + let args = self.parse_attr_args()?; + ast::AttrItem { path, args } }) } @@ -244,7 +220,7 @@ pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { Ok(attrs) } - fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { + pub(super) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { let lit = self.parse_lit()?; debug!("checking if {:?} is unusuffixed", lit); diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 43c740f7f93..1112274dc46 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -922,13 +922,11 @@ macro_rules! parse_lit { // `!`, as an operator, is prefix, so we know this isn't that. if self.eat(&token::Not) { // MACRO INVOCATION expression - let (delim, tts) = self.expect_delimited_token_tree()?; + let args = self.parse_mac_args()?; hi = self.prev_span; ex = ExprKind::Mac(Mac { path, - tts, - delim, - span: lo.to(hi), + args, prior_type_ascription: self.last_type_ascription, }); } else if self.check(&token::OpenDelim(token::Brace)) { diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index a0669a2a174..46addba57c6 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -8,12 +8,12 @@ use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit}; use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind}; use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, Variant, VariantData, StructField}; -use syntax::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param}; +use syntax::ast::{Mac, MacArgs, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param}; use syntax::print::pprust; use syntax::ptr::P; use syntax::ThinVec; use syntax::token; -use syntax::tokenstream::{TokenTree, TokenStream}; +use syntax::tokenstream::{DelimSpan, TokenTree, TokenStream}; use syntax::source_map::{self, respan, Span}; use syntax::struct_span_err; use syntax_pos::BytePos; @@ -432,22 +432,18 @@ fn parse_macro_use_or_failure( let prev_span = self.prev_span; self.complain_if_pub_macro(&visibility.node, prev_span); - let mac_lo = self.token.span; - // Item macro let path = self.parse_path(PathStyle::Mod)?; self.expect(&token::Not)?; - let (delim, tts) = self.expect_delimited_token_tree()?; - if delim != MacDelimiter::Brace && !self.eat(&token::Semi) { + let args = self.parse_mac_args()?; + if args.need_semicolon() && !self.eat(&token::Semi) { self.report_invalid_macro_expansion_item(); } let hi = self.prev_span; let mac = Mac { path, - tts, - delim, - span: mac_lo.to(hi), + args, prior_type_ascription: self.last_type_ascription, }; let item = @@ -500,7 +496,6 @@ fn parse_assoc_macro_invoc( if self.token.is_path_start() && !(self.is_async_fn() && self.token.span.rust_2015()) { let prev_span = self.prev_span; - let lo = self.token.span; let path = self.parse_path(PathStyle::Mod)?; if path.segments.len() == 1 { @@ -518,16 +513,14 @@ fn parse_assoc_macro_invoc( *at_end = true; // eat a matched-delimiter token tree: - let (delim, tts) = self.expect_delimited_token_tree()?; - if delim != MacDelimiter::Brace { + let args = self.parse_mac_args()?; + if args.need_semicolon() { self.expect_semi()?; } Ok(Some(Mac { path, - tts, - delim, - span: lo.to(self.prev_span), + args, prior_type_ascription: self.last_type_ascription, })) } else { @@ -1624,33 +1617,31 @@ pub(super) fn eat_macro_def( vis: &Visibility, lo: Span ) -> PResult<'a, Option>> { - let token_lo = self.token.span; let (ident, def) = if self.eat_keyword(kw::Macro) { let ident = self.parse_ident()?; - let tokens = if self.check(&token::OpenDelim(token::Brace)) { - match self.parse_token_tree() { - TokenTree::Delimited(_, _, tts) => tts, - _ => unreachable!(), - } + let body = if self.check(&token::OpenDelim(token::Brace)) { + self.parse_mac_args()? } else if self.check(&token::OpenDelim(token::Paren)) { - let args = self.parse_token_tree(); + let params = self.parse_token_tree(); + let pspan = params.span(); let body = if self.check(&token::OpenDelim(token::Brace)) { self.parse_token_tree() } else { - self.unexpected()?; - unreachable!() + return self.unexpected(); }; - TokenStream::new(vec![ - args.into(), - TokenTree::token(token::FatArrow, token_lo.to(self.prev_span)).into(), + let bspan = body.span(); + let tokens = TokenStream::new(vec![ + params.into(), + TokenTree::token(token::FatArrow, pspan.between(bspan)).into(), body.into(), - ]) + ]); + let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi()); + P(MacArgs::Delimited(dspan, MacDelimiter::Brace, tokens)) } else { - self.unexpected()?; - unreachable!() + return self.unexpected(); }; - (ident, ast::MacroDef { tokens: tokens.into(), legacy: false }) + (ident, ast::MacroDef { body, legacy: false }) } else if self.check_keyword(sym::macro_rules) && self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) { @@ -1660,12 +1651,12 @@ pub(super) fn eat_macro_def( self.bump(); let ident = self.parse_ident()?; - let (delim, tokens) = self.expect_delimited_token_tree()?; - if delim != MacDelimiter::Brace && !self.eat(&token::Semi) { + let body = self.parse_mac_args()?; + if body.need_semicolon() && !self.eat(&token::Semi) { self.report_invalid_macro_expansion_item(); } - (ident, ast::MacroDef { tokens, legacy: true }) + (ident, ast::MacroDef { body, legacy: true }) } else { return Ok(None); }; diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index ea7673767d0..28689720044 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -16,7 +16,7 @@ use syntax::ast::{ self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, StrLit, - IsAsync, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety, + IsAsync, MacArgs, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety, }; use syntax::print::pprust; @@ -1010,27 +1010,49 @@ fn parse_field_name(&mut self) -> PResult<'a, Ident> { } } - fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, TokenStream)> { - let delim = match self.token.kind { - token::OpenDelim(delim) => delim, - _ => { - let msg = "expected open delimiter"; - let mut err = self.fatal(msg); - err.span_label(self.token.span, msg); - return Err(err) + fn parse_mac_args(&mut self) -> PResult<'a, P> { + self.parse_mac_args_common(true).map(P) + } + + fn parse_attr_args(&mut self) -> PResult<'a, MacArgs> { + self.parse_mac_args_common(false) + } + + fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, MacArgs> { + Ok(if self.check(&token::OpenDelim(DelimToken::Paren)) || + self.check(&token::OpenDelim(DelimToken::Bracket)) || + self.check(&token::OpenDelim(DelimToken::Brace)) { + match self.parse_token_tree() { + TokenTree::Delimited(dspan, delim, tokens) => + // We've confirmed above that there is a delimiter so unwrapping is OK. + MacArgs::Delimited(dspan, MacDelimiter::from_token(delim).unwrap(), tokens), + _ => unreachable!(), } - }; - let tts = match self.parse_token_tree() { - TokenTree::Delimited(_, _, tts) => tts, - _ => unreachable!(), - }; - let delim = match delim { - token::Paren => MacDelimiter::Parenthesis, - token::Bracket => MacDelimiter::Bracket, - token::Brace => MacDelimiter::Brace, - token::NoDelim => self.bug("unexpected no delimiter"), - }; - Ok((delim, tts.into())) + } else if !delimited_only { + if self.eat(&token::Eq) { + let eq_span = self.prev_span; + let mut is_interpolated_expr = false; + if let token::Interpolated(nt) = &self.token.kind { + if let token::NtExpr(..) = **nt { + is_interpolated_expr = true; + } + } + let token_tree = if is_interpolated_expr { + // We need to accept arbitrary interpolated expressions to continue + // supporting things like `doc = $expr` that work on stable. + // Non-literal interpolated expressions are rejected after expansion. + self.parse_token_tree() + } else { + self.parse_unsuffixed_lit()?.token_tree() + }; + + MacArgs::Eq(eq_span, token_tree.into()) + } else { + MacArgs::Empty + } + } else { + return self.unexpected(); + }) } fn parse_or_use_outer_attributes( diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index b068a4f16a5..1127c4b2d5f 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -338,7 +338,7 @@ fn parse_pat_with_range_pat( (None, self.parse_path(PathStyle::Expr)?) }; match self.token.kind { - token::Not if qself.is_none() => self.parse_pat_mac_invoc(lo, path)?, + token::Not if qself.is_none() => self.parse_pat_mac_invoc(path)?, token::DotDotDot | token::DotDotEq | token::DotDot => { self.parse_pat_range_starting_with_path(lo, qself, path)? } @@ -593,14 +593,12 @@ fn recover_additional_muts(&mut self) { } /// Parse macro invocation - fn parse_pat_mac_invoc(&mut self, lo: Span, path: Path) -> PResult<'a, PatKind> { + fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> { self.bump(); - let (delim, tts) = self.expect_delimited_token_tree()?; + let args = self.parse_mac_args()?; let mac = Mac { path, - tts, - delim, - span: lo.to(self.prev_span), + args, prior_type_ascription: self.last_type_ascription, }; Ok(PatKind::Mac(mac)) diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 68307440712..75bb67d47bc 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -2,6 +2,7 @@ use crate::maybe_whole; use syntax::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs}; use syntax::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; +use syntax::ast::MacArgs; use syntax::ThinVec; use syntax::token::{self, Token}; use syntax::source_map::{Span, BytePos}; @@ -114,9 +115,9 @@ pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> { fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> { let meta_ident = match self.token.kind { token::Interpolated(ref nt) => match **nt { - token::NtMeta(ref item) => match item.tokens.is_empty() { - true => Some(item.path.clone()), - false => None, + token::NtMeta(ref item) => match item.args { + MacArgs::Empty => Some(item.path.clone()), + _ => None, }, _ => None, }, diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index a5f20691d07..b952e8814a3 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -10,7 +10,7 @@ use syntax::ptr::P; use syntax::ast; use syntax::ast::{DUMMY_NODE_ID, Stmt, StmtKind, Local, Block, BlockCheckMode, Expr, ExprKind}; -use syntax::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac, MacDelimiter}; +use syntax::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac}; use syntax::util::classify; use syntax::token; use syntax::source_map::{respan, Span}; @@ -93,10 +93,11 @@ fn parse_stmt_without_recovery( })); } - let (delim, tts) = self.expect_delimited_token_tree()?; + let args = self.parse_mac_args()?; + let delim = args.delim(); let hi = self.prev_span; - let style = if delim == MacDelimiter::Brace { + let style = if delim == token::Brace { MacStmtStyle::Braces } else { MacStmtStyle::NoBraces @@ -104,12 +105,10 @@ fn parse_stmt_without_recovery( let mac = Mac { path, - tts, - delim, - span: lo.to(hi), + args, prior_type_ascription: self.last_type_ascription, }; - let kind = if delim == MacDelimiter::Brace || + let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { StmtKind::Mac(P((mac, style, attrs.into()))) } @@ -130,7 +129,7 @@ fn parse_stmt_without_recovery( self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs.into()))) } else { - let e = self.mk_expr(mac.span, ExprKind::Mac(mac), ThinVec::new()); + let e = self.mk_expr(lo.to(hi), ExprKind::Mac(mac), ThinVec::new()); let e = self.maybe_recover_from_bad_qpath(e, true)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 8e6bc29be52..32142796905 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -177,12 +177,10 @@ pub(super) fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: let path = self.parse_path(PathStyle::Type)?; if self.eat(&token::Not) { // Macro invocation in type position - let (delim, tts) = self.expect_delimited_token_tree()?; + let args = self.parse_mac_args()?; let mac = Mac { path, - tts, - delim, - span: lo.to(self.prev_span), + args, prior_type_ascription: self.last_type_ascription, }; TyKind::Mac(mac) diff --git a/src/librustc_parse/validate_attr.rs b/src/librustc_parse/validate_attr.rs index a3c9e266593..0fb348efece 100644 --- a/src/librustc_parse/validate_attr.rs +++ b/src/librustc_parse/validate_attr.rs @@ -2,11 +2,9 @@ use errors::{PResult, Applicability}; use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP}; -use syntax::ast::{self, Attribute, AttrKind, Ident, MetaItem, MetaItemKind}; +use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MetaItem, MetaItemKind}; use syntax::attr::mk_name_value_item_str; use syntax::early_buffered_lints::BufferedEarlyLintId; -use syntax::token; -use syntax::tokenstream::TokenTree; use syntax::sess::ParseSess; use syntax_pos::{Symbol, sym}; @@ -19,11 +17,9 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some((name, _, template, _)) if name != sym::rustc_dummy => check_builtin_attribute(sess, attr, name, template), - _ => if let Some(TokenTree::Token(token)) = attr.get_normal_item().tokens.trees().next() { - if token == token::Eq { - // All key-value attributes are restricted to meta-item syntax. - parse_meta(sess, attr).map_err(|mut err| err.emit()).ok(); - } + _ => if let MacArgs::Eq(..) = attr.get_normal_item().args { + // All key-value attributes are restricted to meta-item syntax. + parse_meta(sess, attr).map_err(|mut err| err.emit()).ok(); } } } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 5a29a56ad54..29cfee8408f 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -737,14 +737,6 @@ fn visit_enum_def(&mut self, enum_definition: &'a EnumDef, |this| visit::walk_enum_def(this, enum_definition, generics, item_id)) } - fn visit_mac(&mut self, mac: &Mac) { - // when a new macro kind is added but the author forgets to set it up for expansion - // because that's the only part that won't cause a compiler error - self.session.diagnostic() - .span_bug(mac.span, "macro invocation missed in expansion; did you forget to override \ - the relevant `fold_*()` method in `PlaceholderExpander`?"); - } - fn visit_impl_item(&mut self, ii: &'a ImplItem) { if let ImplItemKind::Method(ref sig, _) = ii.kind { self.check_fn_decl(&sig.decl); diff --git a/src/librustc_plugin_impl/lib.rs b/src/librustc_plugin_impl/lib.rs index f4e90b7b7da..5c4ea39aecc 100644 --- a/src/librustc_plugin_impl/lib.rs +++ b/src/librustc_plugin_impl/lib.rs @@ -10,10 +10,16 @@ #![feature(nll)] -#![recursion_limit="256"] +use rustc::lint::LintStore; -pub use registry::Registry; - -pub mod registry; -pub mod load; pub mod build; +pub mod load; + +/// Structure used to register plugins. +/// +/// A plugin registrar function takes an `&mut Registry` and should call +/// methods to register its plugins. +pub struct Registry<'a> { + /// The `LintStore` allows plugins to register new lints. + pub lint_store: &'a mut LintStore, +} diff --git a/src/librustc_plugin_impl/load.rs b/src/librustc_plugin_impl/load.rs index 31b3b07c3e1..0bd91076592 100644 --- a/src/librustc_plugin_impl/load.rs +++ b/src/librustc_plugin_impl/load.rs @@ -3,33 +3,21 @@ use rustc::middle::cstore::MetadataLoader; use rustc::session::Session; use rustc_metadata::locator; -use crate::registry::Registry; +use crate::Registry; use std::borrow::ToOwned; use std::env; use std::mem; use std::path::PathBuf; -use syntax::ast; +use syntax::ast::{Crate, Ident}; use syntax::struct_span_err; -use syntax::symbol::{Symbol, kw, sym}; -use syntax_pos::{Span, DUMMY_SP}; +use syntax::symbol::sym; +use syntax_pos::Span; use rustc_error_codes::*; /// Pointer to a registrar function. -pub type PluginRegistrarFun = - fn(&mut Registry<'_>); - -pub struct PluginRegistrar { - pub fun: PluginRegistrarFun, - pub args: Vec, -} - -struct PluginLoader<'a> { - sess: &'a Session, - metadata_loader: &'a dyn MetadataLoader, - plugins: Vec, -} +type PluginRegistrarFn = fn(&mut Registry<'_>); fn call_malformed_plugin_attribute(sess: &Session, span: Span) { struct_span_err!(sess, span, E0498, "malformed `plugin` attribute") @@ -40,98 +28,76 @@ fn call_malformed_plugin_attribute(sess: &Session, span: Span) { /// Read plugin metadata and dynamically load registrar functions. pub fn load_plugins(sess: &Session, metadata_loader: &dyn MetadataLoader, - krate: &ast::Crate, - addl_plugins: Option>) -> Vec { - let mut loader = PluginLoader { sess, metadata_loader, plugins: Vec::new() }; - - // do not report any error now. since crate attributes are - // not touched by expansion, every use of plugin without - // the feature enabled will result in an error later... - if sess.features_untracked().plugin { - for attr in &krate.attrs { - if !attr.check_name(sym::plugin) { - continue; - } + krate: &Crate) -> Vec { + let mut plugins = Vec::new(); - let plugins = match attr.meta_item_list() { - Some(xs) => xs, - None => continue, - }; - - for plugin in plugins { - // plugins must have a name and can't be key = value - let name = plugin.name_or_empty(); - if name != kw::Invalid && !plugin.is_value_str() { - let args = plugin.meta_item_list().map(ToOwned::to_owned); - loader.load_plugin(plugin.span(), name, args.unwrap_or_default()); - } else { - call_malformed_plugin_attribute(sess, attr.span); - } - } + for attr in &krate.attrs { + if !attr.check_name(sym::plugin) { + continue; } - } - if let Some(plugins) = addl_plugins { - for plugin in plugins { - loader.load_plugin(DUMMY_SP, Symbol::intern(&plugin), vec![]); + for plugin in attr.meta_item_list().unwrap_or_default() { + match plugin.ident() { + Some(ident) if plugin.is_word() => + load_plugin(&mut plugins, sess, metadata_loader, ident), + _ => call_malformed_plugin_attribute(sess, plugin.span()), + } } } - loader.plugins + plugins } -impl<'a> PluginLoader<'a> { - fn load_plugin(&mut self, span: Span, name: Symbol, args: Vec) { - let registrar = locator::find_plugin_registrar(self.sess, self.metadata_loader, span, name); - - if let Some((lib, disambiguator)) = registrar { - let symbol = self.sess.generate_plugin_registrar_symbol(disambiguator); - let fun = self.dylink_registrar(span, lib, symbol); - self.plugins.push(PluginRegistrar { - fun, - args, - }); - } +fn load_plugin(plugins: &mut Vec, + sess: &Session, + metadata_loader: &dyn MetadataLoader, + ident: Ident) { + let registrar = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name); + + if let Some((lib, disambiguator)) = registrar { + let symbol = sess.generate_plugin_registrar_symbol(disambiguator); + let fun = dylink_registrar(sess, ident.span, lib, symbol); + plugins.push(fun); } +} - // Dynamically link a registrar function into the compiler process. - fn dylink_registrar(&mut self, - span: Span, - path: PathBuf, - symbol: String) -> PluginRegistrarFun { - use rustc_metadata::dynamic_lib::DynamicLibrary; - - // Make sure the path contains a / or the linker will search for it. - let path = env::current_dir().unwrap().join(&path); - - let lib = match DynamicLibrary::open(Some(&path)) { - Ok(lib) => lib, - // this is fatal: there are almost certainly macros we need - // inside this crate, so continue would spew "macro undefined" - // errors - Err(err) => { - self.sess.span_fatal(span, &err) - } - }; - - unsafe { - let registrar = - match lib.symbol(&symbol) { - Ok(registrar) => { - mem::transmute::<*mut u8,PluginRegistrarFun>(registrar) - } - // again fatal if we can't register macros - Err(err) => { - self.sess.span_fatal(span, &err) - } - }; - - // Intentionally leak the dynamic library. We can't ever unload it - // since the library can make things that will live arbitrarily long - // (e.g., an @-box cycle or a thread). - mem::forget(lib); - - registrar +// Dynamically link a registrar function into the compiler process. +fn dylink_registrar(sess: &Session, + span: Span, + path: PathBuf, + symbol: String) -> PluginRegistrarFn { + use rustc_metadata::dynamic_lib::DynamicLibrary; + + // Make sure the path contains a / or the linker will search for it. + let path = env::current_dir().unwrap().join(&path); + + let lib = match DynamicLibrary::open(Some(&path)) { + Ok(lib) => lib, + // this is fatal: there are almost certainly macros we need + // inside this crate, so continue would spew "macro undefined" + // errors + Err(err) => { + sess.span_fatal(span, &err) } + }; + + unsafe { + let registrar = + match lib.symbol(&symbol) { + Ok(registrar) => { + mem::transmute::<*mut u8, PluginRegistrarFn>(registrar) + } + // again fatal if we can't register macros + Err(err) => { + sess.span_fatal(span, &err) + } + }; + + // Intentionally leak the dynamic library. We can't ever unload it + // since the library can make things that will live arbitrarily long + // (e.g., an @-box cycle or a thread). + mem::forget(lib); + + registrar } } diff --git a/src/librustc_plugin_impl/registry.rs b/src/librustc_plugin_impl/registry.rs deleted file mode 100644 index bc684d59e5a..00000000000 --- a/src/librustc_plugin_impl/registry.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! Used by plugin crates to tell `rustc` about the plugins they provide. - -use rustc::lint::LintStore; -use rustc::session::Session; -use syntax::ast; -use syntax_pos::Span; - -use std::borrow::ToOwned; - -/// Structure used to register plugins. -/// -/// A plugin registrar function takes an `&mut Registry` and should call -/// methods to register its plugins. -/// -/// This struct has public fields and other methods for use by `rustc` -/// itself. They are not documented here, and plugin authors should -/// not use them. -pub struct Registry<'a> { - /// Compiler session. Useful if you want to emit diagnostic messages - /// from the plugin registrar. - pub sess: &'a Session, - - /// The `LintStore` allows plugins to register new lints. - pub lint_store: &'a mut LintStore, - - #[doc(hidden)] - pub args_hidden: Option>, - - #[doc(hidden)] - pub krate_span: Span, - - #[doc(hidden)] - pub llvm_passes: Vec, -} - -impl<'a> Registry<'a> { - #[doc(hidden)] - pub fn new(sess: &'a Session, lint_store: &'a mut LintStore, krate_span: Span) -> Registry<'a> { - Registry { - sess, - lint_store, - args_hidden: None, - krate_span, - llvm_passes: vec![], - } - } - - /// Gets the plugin's arguments, if any. - /// - /// These are specified inside the `plugin` crate attribute as - /// - /// ```no_run - /// #![plugin(my_plugin_name(... args ...))] - /// ``` - /// - /// Returns empty slice in case the plugin was loaded - /// with `--extra-plugins` - pub fn args(&self) -> &[ast::NestedMetaItem] { - self.args_hidden.as_ref().map(|v| &v[..]).unwrap_or(&[]) - } - - /// Register an LLVM pass. - /// - /// Registration with LLVM itself is handled through static C++ objects with - /// constructors. This method simply adds a name to the list of passes to - /// execute. - pub fn register_llvm_pass(&mut self, name: &str) { - self.llvm_passes.push(name.to_owned()); - } -} diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 5bec5b5eb6b..396d9484339 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1515,14 +1515,6 @@ fn visit_expr(&mut self, ex: &'l ast::Expr) { } } - fn visit_mac(&mut self, mac: &'l ast::Mac) { - // These shouldn't exist in the AST at this point, log a span bug. - span_bug!( - mac.span, - "macro invocation should have been expanded out of AST" - ); - } - fn visit_pat(&mut self, p: &'l ast::Pat) { self.process_macro_use(p.span); self.process_pat(p); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4b5fc7c2a1e..7ee1054dc48 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -482,7 +482,7 @@ fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemE match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) { LoadedMacro::MacroDef(def, _) => { let matchers: hir::HirVec = if let ast::ItemKind::MacroDef(ref def) = def.kind { - let tts: Vec<_> = def.stream().into_trees().collect(); + let tts: Vec<_> = def.body.inner_tokens().into_trees().collect(); tts.chunks(4).map(|arm| arm[0].span()).collect() } else { unreachable!() diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index b0baf36308e..5b7bef930d1 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -812,9 +812,50 @@ mod loop_keyword { } // /// Control flow based on pattern matching. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// `match` can be used to run code conditionally. Every pattern must +/// be handled exhaustively either explicitly or by using wildcards like +/// `_` in the `match`. Since `match` is an expression, values can also be +/// returned. /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// ```rust +/// let opt = Option::None::; +/// let x = match opt { +/// Some(int) => int, +/// None => 10, +/// }; +/// assert_eq!(x, 10); +/// +/// let a_number = Option::Some(10); +/// match a_number { +/// Some(x) if x <= 5 => println!("0 to 5 num = {}", x), +/// Some(x @ 6..=10) => println!("6 to 10 num = {}", x), +/// None => panic!(), +/// // all other numbers +/// _ => panic!(), +/// } +/// ``` +/// +/// `match` can be used to gain access to the inner members of an enum +/// and use them directly. +/// +/// ```rust +/// enum Outer { +/// Double(Option, Option), +/// Single(Option), +/// Empty +/// } +/// +/// let get_inner = Outer::Double(None, Some(String::new())); +/// match get_inner { +/// Outer::Double(None, Some(st)) => println!("{}", st), +/// Outer::Single(opt) => println!("{:?}", opt), +/// _ => panic!(), +/// } +/// ``` +/// +/// For more information on `match` and matching in general, see the [Reference]. +/// +/// [Reference]: ../reference/expressions/match-expr.html mod match_keyword { } #[doc(keyword = "mod")] @@ -831,10 +872,35 @@ mod mod_keyword { } // /// Capture a [closure]'s environment by value. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// `move` converts any variables captured by reference or mutable reference +/// to owned by value variables. The three [`Fn` trait]'s mirror the ways to capture +/// variables, when `move` is used, the closures is represented by the `FnOnce` trait. /// -/// [closure]: ../book/second-edition/ch13-01-closures.html -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// ```rust +/// let capture = "hello"; +/// let closure = move || { +/// println!("rust says {}", capture); +/// }; +/// ``` +/// +/// `move` is often used when [threads] are involved. +/// +/// ```rust +/// let x = 5; +/// +/// std::thread::spawn(move || { +/// println!("captured {} by value", x) +/// }).join().unwrap(); +/// +/// // x is no longer available +/// ``` +/// +/// For more information on the `move` keyword, see the [closure]'s section +/// of the Rust book or the [threads] section +/// +/// [`Fn` trait]: ../std/ops/trait.Fn.html +/// [closure]: ../book/ch13-01-closures.html +/// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads mod move_keyword { } #[doc(keyword = "mut")] diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs index ccbac1a3e4b..78a3fd05c73 100644 --- a/src/libstd/sys/unix/ext/mod.rs +++ b/src/libstd/sys/unix/ext/mod.rs @@ -15,11 +15,13 @@ //! use std::fs::File; //! use std::os::unix::prelude::*; //! -//! fn main() { -//! let f = File::create("foo.txt").unwrap(); +//! fn main() -> std::io::Result<()> { +//! let f = File::create("foo.txt")?; //! let fd = f.as_raw_fd(); //! //! // use fd with native unix bindings +//! +//! Ok(()) //! } //! ``` diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 42edd5dbbea..5177cce628c 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -142,9 +142,12 @@ fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), false); + /// Ok(()) + /// } /// ``` /// /// An unnamed address: @@ -152,9 +155,12 @@ fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), true); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn is_unnamed(&self) -> bool { @@ -175,9 +181,12 @@ pub fn is_unnamed(&self) -> bool { /// use std::os::unix::net::UnixListener; /// use std::path::Path; /// - /// let socket = UnixListener::bind("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// Ok(()) + /// } /// ``` /// /// Without a pathname: @@ -185,9 +194,12 @@ pub fn is_unnamed(&self) -> bool { /// ``` /// use std::os::unix::net::UnixDatagram; /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), None); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn as_pathname(&self) -> Option<&Path> { @@ -247,11 +259,14 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { /// use std::os::unix::net::UnixStream; /// use std::io::prelude::*; /// -/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); -/// stream.write_all(b"hello world").unwrap(); -/// let mut response = String::new(); -/// stream.read_to_string(&mut response).unwrap(); -/// println!("{}", response); +/// fn main() -> std::io::Result<()> { +/// let mut stream = UnixStream::connect("/path/to/my/socket")?; +/// stream.write_all(b"hello world")?; +/// let mut response = String::new(); +/// stream.read_to_string(&mut response)?; +/// println!("{}", response); +/// Ok(()) +/// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub struct UnixStream(Socket); @@ -336,8 +351,11 @@ pub fn pair() -> io::Result<(UnixStream, UnixStream)> { /// ```no_run /// use std::os::unix::net::UnixStream; /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn try_clone(&self) -> io::Result { @@ -351,8 +369,11 @@ pub fn try_clone(&self) -> io::Result { /// ```no_run /// use std::os::unix::net::UnixStream; /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { @@ -366,8 +387,11 @@ pub fn local_addr(&self) -> io::Result { /// ```no_run /// use std::os::unix::net::UnixStream; /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn peer_addr(&self) -> io::Result { @@ -391,8 +415,11 @@ pub fn peer_addr(&self) -> io::Result { /// use std::os::unix::net::UnixStream; /// use std::time::Duration; /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// Ok(()) + /// } /// ``` /// /// An [`Err`] is returned if the zero [`Duration`] is passed to this @@ -403,10 +430,13 @@ pub fn peer_addr(&self) -> io::Result { /// use std::os::unix::net::UnixStream; /// use std::time::Duration; /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { @@ -430,8 +460,12 @@ pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { /// use std::os::unix::net::UnixStream; /// use std::time::Duration; /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// Ok(()) + /// } /// ``` /// /// An [`Err`] is returned if the zero [`Duration`] is passed to this @@ -442,10 +476,13 @@ pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { /// use std::net::UdpSocket; /// use std::time::Duration; /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// fn main() -> std::io::Result<()> { + /// let socket = UdpSocket::bind("127.0.0.1:34254")?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { @@ -460,9 +497,12 @@ pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { /// use std::os::unix::net::UnixStream; /// use std::time::Duration; /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn read_timeout(&self) -> io::Result> { @@ -477,9 +517,13 @@ pub fn read_timeout(&self) -> io::Result> { /// use std::os::unix::net::UnixStream; /// use std::time::Duration; /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn write_timeout(&self) -> io::Result> { @@ -493,8 +537,11 @@ pub fn write_timeout(&self) -> io::Result> { /// ```no_run /// use std::os::unix::net::UnixStream; /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { @@ -508,9 +555,12 @@ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { /// ```no_run /// use std::os::unix::net::UnixStream; /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) /// } /// ``` /// @@ -535,8 +585,11 @@ pub fn take_error(&self) -> io::Result> { /// use std::os::unix::net::UnixStream; /// use std::net::Shutdown; /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { @@ -697,20 +750,23 @@ fn into_raw_fd(self) -> RawFd { /// // ... /// } /// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; /// -/// // accept connections and process them, spawning a new thread for each one -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// /* connection succeeded */ -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// /* connection failed */ -/// break; +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } /// } /// } +/// Ok(()) /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] @@ -773,11 +829,14 @@ fn inner(path: &Path) -> io::Result { /// ```no_run /// use std::os::unix::net::UnixListener; /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; /// - /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// Ok(()) /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] @@ -800,9 +859,11 @@ pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { /// ```no_run /// use std::os::unix::net::UnixListener; /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn try_clone(&self) -> io::Result { @@ -816,9 +877,11 @@ pub fn try_clone(&self) -> io::Result { /// ```no_run /// use std::os::unix::net::UnixListener; /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { @@ -832,9 +895,11 @@ pub fn local_addr(&self) -> io::Result { /// ```no_run /// use std::os::unix::net::UnixListener; /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { @@ -848,10 +913,13 @@ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { /// ```no_run /// use std::os::unix::net::UnixListener; /// - /// let listener = UnixListener::bind("/tmp/sock").unwrap(); + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/tmp/sock")?; /// - /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) /// } /// ``` /// @@ -880,17 +948,20 @@ pub fn take_error(&self) -> io::Result> { /// // ... /// } /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// thread::spawn(|| handle_client(stream)); - /// } - /// Err(err) => { - /// break; + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } /// } /// } + /// Ok(()) /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] @@ -947,17 +1018,20 @@ fn into_iter(self) -> Incoming<'a> { /// // ... /// } /// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; /// -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// break; +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } /// } /// } +/// Ok(()) /// } /// ``` #[derive(Debug)] @@ -986,11 +1060,14 @@ fn size_hint(&self) -> (usize, Option) { /// ```no_run /// use std::os::unix::net::UnixDatagram; /// -/// let socket = UnixDatagram::bind("/path/to/my/socket").unwrap(); -/// socket.send_to(b"hello world", "/path/to/other/socket").unwrap(); -/// let mut buf = [0; 100]; -/// let (count, address) = socket.recv_from(&mut buf).unwrap(); -/// println!("socket {:?} sent {:?}", address, &buf[..count]); +/// fn main() -> std::io::Result<()> { +/// let socket = UnixDatagram::bind("/path/to/my/socket")?; +/// socket.send_to(b"hello world", "/path/to/other/socket")?; +/// let mut buf = [0; 100]; +/// let (count, address) = socket.recv_from(&mut buf)?; +/// println!("socket {:?} sent {:?}", address, &buf[..count]); +/// Ok(()) +/// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub struct UnixDatagram(Socket); @@ -1099,14 +1176,17 @@ pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { /// ```no_run /// use std::os::unix::net::UnixDatagram; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// match sock.connect("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// match sock.connect("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn connect>(&self, path: P) -> io::Result<()> { @@ -1133,9 +1213,11 @@ fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { /// ```no_run /// use std::os::unix::net::UnixDatagram; /// - /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap(); - /// - /// let sock_copy = sock.try_clone().expect("try_clone failed"); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let sock_copy = sock.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn try_clone(&self) -> io::Result { @@ -1149,9 +1231,11 @@ pub fn try_clone(&self) -> io::Result { /// ```no_run /// use std::os::unix::net::UnixDatagram; /// - /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap(); - /// - /// let addr = sock.local_addr().expect("Couldn't get local address"); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let addr = sock.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { @@ -1169,10 +1253,13 @@ pub fn local_addr(&self) -> io::Result { /// ```no_run /// use std::os::unix::net::UnixDatagram; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.connect("/path/to/the/socket").unwrap(); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/path/to/the/socket")?; /// - /// let addr = sock.peer_addr().expect("Couldn't get peer address"); + /// let addr = sock.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn peer_addr(&self) -> io::Result { @@ -1189,11 +1276,12 @@ pub fn peer_addr(&self) -> io::Result { /// ```no_run /// use std::os::unix::net::UnixDatagram; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// let mut buf = vec![0; 10]; - /// match sock.recv_from(buf.as_mut_slice()) { - /// Ok((size, sender)) => println!("received {} bytes from {:?}", size, sender), - /// Err(e) => println!("recv_from function failed: {:?}", e), + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf = vec![0; 10]; + /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; + /// println!("received {} bytes from {:?}", size, sender); + /// Ok(()) /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] @@ -1229,9 +1317,12 @@ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { /// ```no_run /// use std::os::unix::net::UnixDatagram; /// - /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap(); - /// let mut buf = vec![0; 10]; - /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let mut buf = vec![0; 10]; + /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn recv(&self, buf: &mut [u8]) -> io::Result { @@ -1247,8 +1338,11 @@ pub fn recv(&self, buf: &mut [u8]) -> io::Result { /// ```no_run /// use std::os::unix::net::UnixDatagram; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { @@ -1280,9 +1374,12 @@ fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { /// ```no_run /// use std::os::unix::net::UnixDatagram; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.connect("/some/sock").expect("Couldn't connect"); - /// sock.send(b"omelette au fromage").expect("send_to function failed"); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/some/sock").expect("Couldn't connect"); + /// sock.send(b"omelette au fromage").expect("send_to function failed"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn send(&self, buf: &[u8]) -> io::Result { @@ -1307,8 +1404,12 @@ pub fn send(&self, buf: &[u8]) -> io::Result { /// use std::os::unix::net::UnixDatagram; /// use std::time::Duration; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed"); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// Ok(()) + /// } /// ``` /// /// An [`Err`] is returned if the zero [`Duration`] is passed to this @@ -1319,10 +1420,13 @@ pub fn send(&self, buf: &[u8]) -> io::Result { /// use std::os::unix::net::UnixDatagram; /// use std::time::Duration; /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { @@ -1346,9 +1450,12 @@ pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { /// use std::os::unix::net::UnixDatagram; /// use std::time::Duration; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// Ok(()) + /// } /// ``` /// /// An [`Err`] is returned if the zero [`Duration`] is passed to this @@ -1359,10 +1466,13 @@ pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { /// use std::os::unix::net::UnixDatagram; /// use std::time::Duration; /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { @@ -1377,9 +1487,13 @@ pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { /// use std::os::unix::net::UnixDatagram; /// use std::time::Duration; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed"); - /// assert_eq!(sock.read_timeout().unwrap(), Some(Duration::new(1, 0))); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn read_timeout(&self) -> io::Result> { @@ -1394,10 +1508,13 @@ pub fn read_timeout(&self) -> io::Result> { /// use std::os::unix::net::UnixDatagram; /// use std::time::Duration; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// assert_eq!(sock.write_timeout().unwrap(), Some(Duration::new(1, 0))); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn write_timeout(&self) -> io::Result> { @@ -1411,8 +1528,11 @@ pub fn write_timeout(&self) -> io::Result> { /// ``` /// use std::os::unix::net::UnixDatagram; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { @@ -1426,9 +1546,12 @@ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { /// ```no_run /// use std::os::unix::net::UnixDatagram; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// if let Ok(Some(err)) = sock.take_error() { - /// println!("Got error: {:?}", err); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// if let Ok(Some(err)) = sock.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] @@ -1448,8 +1571,11 @@ pub fn take_error(&self) -> io::Result> { /// use std::os::unix::net::UnixDatagram; /// use std::net::Shutdown; /// - /// let sock = UnixDatagram::unbound().unwrap(); - /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 512f43c86ca..8018e005b12 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -27,7 +27,7 @@ use crate::ptr::P; use crate::source_map::{dummy_spanned, respan, Spanned}; use crate::token::{self, DelimToken}; -use crate::tokenstream::TokenStream; +use crate::tokenstream::{TokenStream, TokenTree, DelimSpan}; use syntax_pos::symbol::{kw, sym, Symbol}; use syntax_pos::{Span, DUMMY_SP, ExpnId}; @@ -40,6 +40,7 @@ use rustc_serialize::{self, Decoder, Encoder}; use rustc_macros::HashStable_Generic; +use std::iter; use std::fmt; #[cfg(test)] @@ -1372,34 +1373,89 @@ pub enum Movability { Movable, } -/// Represents a macro invocation. The `Path` indicates which macro -/// is being invoked, and the vector of token-trees contains the source -/// of the macro invocation. -/// -/// N.B., the additional ident for a `macro_rules`-style macro is actually -/// stored in the enclosing item. +/// Represents a macro invocation. The `path` indicates which macro +/// is being invoked, and the `args` are arguments passed to it. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Mac { pub path: Path, - pub delim: MacDelimiter, - pub tts: TokenStream, - pub span: Span, + pub args: P, pub prior_type_ascription: Option<(Span, bool)>, } -#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] +impl Mac { + pub fn span(&self) -> Span { + self.path.span.to(self.args.span().unwrap_or(self.path.span)) + } +} + +/// Arguments passed to an attribute or a function-like macro. +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] +pub enum MacArgs { + /// No arguments - `#[attr]`. + Empty, + /// Delimited arguments - `#[attr()/[]/{}]` or `mac!()/[]/{}`. + Delimited(DelimSpan, MacDelimiter, TokenStream), + /// Arguments of a key-value attribute - `#[attr = "value"]`. + Eq( + /// Span of the `=` token. + Span, + /// Token stream of the "value". + TokenStream, + ), +} + +impl MacArgs { + pub fn delim(&self) -> DelimToken { + match self { + MacArgs::Delimited(_, delim, _) => delim.to_token(), + MacArgs::Empty | MacArgs::Eq(..) => token::NoDelim, + } + } + + pub fn span(&self) -> Option { + match *self { + MacArgs::Empty => None, + MacArgs::Delimited(dspan, ..) => Some(dspan.entire()), + MacArgs::Eq(eq_span, ref tokens) => Some(eq_span.to(tokens.span().unwrap_or(eq_span))), + } + } + + /// Tokens inside the delimiters or after `=`. + /// Proc macros see these tokens, for example. + pub fn inner_tokens(&self) -> TokenStream { + match self { + MacArgs::Empty => TokenStream::default(), + MacArgs::Delimited(.., tokens) | + MacArgs::Eq(.., tokens) => tokens.clone(), + } + } + + /// Tokens together with the delimiters or `=`. + /// Use of this method generally means that something suboptimal or hacky is happening. + pub fn outer_tokens(&self) -> TokenStream { + match *self { + MacArgs::Empty => TokenStream::default(), + MacArgs::Delimited(dspan, delim, ref tokens) => + TokenTree::Delimited(dspan, delim.to_token(), tokens.clone()).into(), + MacArgs::Eq(eq_span, ref tokens) => iter::once(TokenTree::token(token::Eq, eq_span)) + .chain(tokens.trees()).collect(), + } + } + + /// Whether a macro with these arguments needs a semicolon + /// when used as a standalone item or statement. + pub fn need_semicolon(&self) -> bool { + !matches!(self, MacArgs::Delimited(_, MacDelimiter::Brace ,_)) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub enum MacDelimiter { Parenthesis, Bracket, Brace, } -impl Mac { - pub fn stream(&self) -> TokenStream { - self.tts.clone() - } -} - impl MacDelimiter { crate fn to_token(self) -> DelimToken { match self { @@ -1408,22 +1464,25 @@ impl MacDelimiter { MacDelimiter::Brace => DelimToken::Brace, } } + + pub fn from_token(delim: DelimToken) -> Option { + match delim { + token::Paren => Some(MacDelimiter::Parenthesis), + token::Bracket => Some(MacDelimiter::Bracket), + token::Brace => Some(MacDelimiter::Brace), + token::NoDelim => None, + } + } } /// Represents a macro definition. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct MacroDef { - pub tokens: TokenStream, + pub body: P, /// `true` if macro was defined with `macro_rules`. pub legacy: bool, } -impl MacroDef { - pub fn stream(&self) -> TokenStream { - self.tokens.clone().into() - } -} - // Clippy uses Hash and PartialEq #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq, HashStable_Generic)] pub enum StrStyle { @@ -2323,7 +2382,7 @@ fn decode(d: &mut D) -> Result { #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct AttrItem { pub path: Path, - pub tokens: TokenStream, + pub args: MacArgs, } /// Metadata associated with an item. diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 29eff5c2981..079a0f6fafa 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -10,7 +10,7 @@ use crate::ast; use crate::ast::{AttrItem, AttrId, AttrKind, AttrStyle, Name, Ident, Path, PathSegment}; -use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; +use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; use crate::source_map::{BytePos, Spanned}; @@ -198,7 +198,7 @@ pub fn meta_item_list(&self) -> Option> { pub fn is_word(&self) -> bool { if let AttrKind::Normal(item) = &self.kind { - item.tokens.is_empty() + matches!(item.args, MacArgs::Empty) } else { false } @@ -278,17 +278,9 @@ pub fn is_meta_item_list(&self) -> bool { impl AttrItem { pub fn meta(&self, span: Span) -> Option { - let mut tokens = self.tokens.trees().peekable(); Some(MetaItem { path: self.path.clone(), - kind: if let Some(kind) = MetaItemKind::from_tokens(&mut tokens) { - if tokens.peek().is_some() { - return None; - } - kind - } else { - return None; - }, + kind: MetaItemKind::from_mac_args(&self.args)?, span, }) } @@ -362,8 +354,8 @@ pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem { AttrId(id) } -pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute { - mk_attr_from_item(style, AttrItem { path, tokens }, span) +pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute { + mk_attr_from_item(style, AttrItem { path, args }, span) } pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute { @@ -377,12 +369,12 @@ pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attrib /// Returns an inner attribute with the given value and span. pub fn mk_attr_inner(item: MetaItem) -> Attribute { - mk_attr(AttrStyle::Inner, item.path, item.kind.tokens(item.span), item.span) + mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span) } /// Returns an outer attribute with the given value and span. pub fn mk_attr_outer(item: MetaItem) -> Attribute { - mk_attr(AttrStyle::Outer, item.path, item.kind.tokens(item.span), item.span) + mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span) } pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribute { @@ -520,7 +512,26 @@ fn from_tokens(tokens: &mut iter::Peekable) -> Option } impl MetaItemKind { - pub fn token_trees_and_joints(&self, span: Span) -> Vec { + pub fn mac_args(&self, span: Span) -> MacArgs { + match self { + MetaItemKind::Word => MacArgs::Empty, + MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.token_tree().into()), + MetaItemKind::List(list) => { + let mut tts = Vec::new(); + for (i, item) in list.iter().enumerate() { + if i > 0 { + tts.push(TokenTree::token(token::Comma, span).into()); + } + tts.extend(item.token_trees_and_joints()) + } + MacArgs::Delimited( + DelimSpan::from_single(span), MacDelimiter::Parenthesis, TokenStream::new(tts) + ) + } + } + } + + fn token_trees_and_joints(&self, span: Span) -> Vec { match *self { MetaItemKind::Word => vec![], MetaItemKind::NameValue(ref lit) => { @@ -548,33 +559,8 @@ pub fn token_trees_and_joints(&self, span: Span) -> Vec { } } - // Premature conversions of `TokenTree`s to `TokenStream`s can hurt - // performance. Do not use this function if `token_trees_and_joints()` can - // be used instead. - pub fn tokens(&self, span: Span) -> TokenStream { - TokenStream::new(self.token_trees_and_joints(span)) - } - - fn from_tokens(tokens: &mut iter::Peekable) -> Option - where I: Iterator, - { - let delimited = match tokens.peek().cloned() { - Some(TokenTree::Token(token)) if token == token::Eq => { - tokens.next(); - return if let Some(TokenTree::Token(token)) = tokens.next() { - Lit::from_token(&token).ok().map(MetaItemKind::NameValue) - } else { - None - }; - } - Some(TokenTree::Delimited(_, delim, ref tts)) if delim == token::Paren => { - tokens.next(); - tts.clone() - } - _ => return Some(MetaItemKind::Word), - }; - - let mut tokens = delimited.into_trees().peekable(); + fn list_from_tokens(tokens: TokenStream) -> Option { + let mut tokens = tokens.into_trees().peekable(); let mut result = Vec::new(); while let Some(..) = tokens.peek() { let item = NestedMetaItem::from_tokens(&mut tokens)?; @@ -586,6 +572,47 @@ fn from_tokens(tokens: &mut iter::Peekable) -> Option } Some(MetaItemKind::List(result)) } + + fn name_value_from_tokens( + tokens: &mut impl Iterator, + ) -> Option { + match tokens.next() { + Some(TokenTree::Token(token)) => + Lit::from_token(&token).ok().map(MetaItemKind::NameValue), + _ => None, + } + } + + fn from_mac_args(args: &MacArgs) -> Option { + match args { + MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => + MetaItemKind::list_from_tokens(tokens.clone()), + MacArgs::Delimited(..) => None, + MacArgs::Eq(_, tokens) => { + assert!(tokens.len() == 1); + MetaItemKind::name_value_from_tokens(&mut tokens.trees()) + } + MacArgs::Empty => Some(MetaItemKind::Word), + } + } + + fn from_tokens( + tokens: &mut iter::Peekable>, + ) -> Option { + match tokens.peek() { + Some(TokenTree::Delimited(_, token::Paren, inner_tokens)) => { + let inner_tokens = inner_tokens.clone(); + tokens.next(); + MetaItemKind::list_from_tokens(inner_tokens) + } + Some(TokenTree::Delimited(..)) => None, + Some(TokenTree::Token(Token { kind: token::Eq, .. })) => { + tokens.next(); + MetaItemKind::name_value_from_tokens(tokens) + } + _ => Some(MetaItemKind::Word), + } + } } impl NestedMetaItem { diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 3d4a5d624c1..3dcdd4db637 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -12,6 +12,7 @@ #![feature(const_transmute)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] +#![feature(matches_macro)] #![feature(nll)] #![feature(try_trait)] #![feature(slice_patterns)] diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index fbe28215a56..8889e5df26c 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -359,6 +359,26 @@ pub fn visit_fn_sig(FnSig { header, decl }: &mut FnSig, vis: &mut vis.visit_fn_decl(decl); } +// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. +pub fn visit_mac_args(args: &mut MacArgs, vis: &mut T) { + match args { + MacArgs::Empty => {} + MacArgs::Delimited(dspan, _delim, tokens) => { + visit_delim_span(dspan, vis); + vis.visit_tts(tokens); + } + MacArgs::Eq(eq_span, tokens) => { + vis.visit_span(eq_span); + vis.visit_tts(tokens); + } + } +} + +pub fn visit_delim_span(dspan: &mut DelimSpan, vis: &mut T) { + vis.visit_span(&mut dspan.open); + vis.visit_span(&mut dspan.close); +} + pub fn noop_flat_map_field_pattern( mut fp: FieldPat, vis: &mut T, @@ -550,9 +570,9 @@ pub fn noop_visit_local(local: &mut P, vis: &mut T) { pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { let Attribute { kind, id: _, style: _, span } = attr; match kind { - AttrKind::Normal(AttrItem { path, tokens }) => { + AttrKind::Normal(AttrItem { path, args }) => { vis.visit_path(path); - vis.visit_tts(tokens); + visit_mac_args(args, vis); } AttrKind::DocComment(_) => {} } @@ -560,15 +580,14 @@ pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { } pub fn noop_visit_mac(mac: &mut Mac, vis: &mut T) { - let Mac { path, delim: _, tts, span, prior_type_ascription: _ } = mac; + let Mac { path, args, prior_type_ascription: _ } = mac; vis.visit_path(path); - vis.visit_tts(tts); - vis.visit_span(span); + visit_mac_args(args, vis); } pub fn noop_visit_macro_def(macro_def: &mut MacroDef, vis: &mut T) { - let MacroDef { tokens, legacy: _ } = macro_def; - vis.visit_tts(tokens); + let MacroDef { body, legacy: _ } = macro_def; + visit_mac_args(body, vis); } pub fn noop_visit_meta_list_item(li: &mut NestedMetaItem, vis: &mut T) { @@ -682,9 +701,9 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: token::NtIdent(ident, _is_raw) => vis.visit_ident(ident), token::NtLifetime(ident) => vis.visit_ident(ident), token::NtLiteral(expr) => vis.visit_expr(expr), - token::NtMeta(AttrItem { path, tokens }) => { + token::NtMeta(AttrItem { path, args }) => { vis.visit_path(path); - vis.visit_tts(tokens); + visit_mac_args(args, vis); } token::NtPath(path) => vis.visit_path(path), token::NtTT(tt) => vis.visit_tt(tt), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0d2e8dddce6..4821bbd9ec6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1,6 +1,6 @@ use crate::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use crate::ast::{SelfKind, GenericBound, TraitBoundModifier}; -use crate::ast::{Attribute, MacDelimiter, GenericArg}; +use crate::ast::{Attribute, GenericArg, MacArgs}; use crate::util::parser::{self, AssocOp, Fixity}; use crate::util::comments; use crate::attr; @@ -639,17 +639,22 @@ fn print_attribute_inline(&mut self, attr: &ast::Attribute, fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) { self.ibox(0); - match item.tokens.trees().next() { - Some(TokenTree::Delimited(_, delim, tts)) => { - self.print_mac_common( - Some(MacHeader::Path(&item.path)), false, None, delim, tts, true, span - ); - } - tree => { + match &item.args { + MacArgs::Delimited(_, delim, tokens) => self.print_mac_common( + Some(MacHeader::Path(&item.path)), + false, + None, + delim.to_token(), + tokens.clone(), + true, + span, + ), + MacArgs::Empty | MacArgs::Eq(..) => { self.print_path(&item.path, false, 0); - if tree.is_some() { + if let MacArgs::Eq(_, tokens) = &item.args { self.space(); - self.print_tts(item.tokens.clone(), true); + self.word_space("="); + self.print_tts(tokens.clone(), true); } } } @@ -1097,9 +1102,8 @@ pub fn print_type(&mut self, ty: &ast::Ty) { } ast::ForeignItemKind::Macro(ref m) => { self.print_mac(m); - match m.delim { - MacDelimiter::Brace => {}, - _ => self.s.word(";") + if m.args.need_semicolon() { + self.s.word(";"); } } } @@ -1361,9 +1365,8 @@ fn print_associated_type(&mut self, } ast::ItemKind::Mac(ref mac) => { self.print_mac(mac); - match mac.delim { - MacDelimiter::Brace => {} - _ => self.s.word(";"), + if mac.args.need_semicolon() { + self.s.word(";"); } } ast::ItemKind::MacroDef(ref macro_def) => { @@ -1377,8 +1380,8 @@ fn print_associated_type(&mut self, Some(MacHeader::Keyword(kw)), has_bang, Some(item.ident), - DelimToken::Brace, - macro_def.stream(), + macro_def.body.delim(), + macro_def.body.inner_tokens(), true, item.span, ); @@ -1578,9 +1581,8 @@ fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) { } ast::TraitItemKind::Macro(ref mac) => { self.print_mac(mac); - match mac.delim { - MacDelimiter::Brace => {} - _ => self.s.word(";"), + if mac.args.need_semicolon() { + self.s.word(";"); } } } @@ -1608,9 +1610,8 @@ fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) { } ast::ImplItemKind::Macro(ref mac) => { self.print_mac(mac); - match mac.delim { - MacDelimiter::Brace => {} - _ => self.s.word(";"), + if mac.args.need_semicolon() { + self.s.word(";"); } } } @@ -1775,10 +1776,10 @@ fn print_else(&mut self, els: Option<&ast::Expr>) { Some(MacHeader::Path(&m.path)), true, None, - m.delim.to_token(), - m.stream(), + m.args.delim(), + m.args.inner_tokens(), true, - m.span, + m.span(), ); } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 6a0523dd655..491b9a9ade4 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -225,6 +225,14 @@ pub fn len(&self) -> usize { self.0.len() } + pub fn span(&self) -> Option { + match &**self.0 { + [] => None, + [(tt, _)] => Some(tt.span()), + [(tt_start, _), .., (tt_end, _)] => Some(tt_start.span().to(tt_end.span())), + } + } + pub fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream { match streams.len() { 0 => TokenStream::default(), diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 5ff337fb60e..4ee09b4b87a 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -841,11 +841,19 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) { match attr.kind { - AttrKind::Normal(ref item) => visitor.visit_tts(item.tokens.clone()), + AttrKind::Normal(ref item) => walk_mac_args(visitor, &item.args), AttrKind::DocComment(_) => {} } } +pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) { + match args { + MacArgs::Empty => {} + MacArgs::Delimited(_dspan, _delim, tokens) => visitor.visit_tts(tokens.clone()), + MacArgs::Eq(_eq_span, tokens) => visitor.visit_tts(tokens.clone()), + } +} + pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) { match tt { TokenTree::Token(token) => visitor.visit_token(token), diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index a6ced1439c5..9bfedb3b617 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -11,7 +11,7 @@ use rustc_parse::parser::Parser; use rustc_parse::validate_attr; use syntax::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path}; -use syntax::ast::{MacStmtStyle, StmtKind, ItemKind}; +use syntax::ast::{MacArgs, MacStmtStyle, StmtKind, ItemKind}; use syntax::attr::{self, HasAttrs, is_builtin_attr}; use syntax::source_map::respan; use syntax::feature_gate::{self, feature_err}; @@ -597,13 +597,13 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstF InvocationKind::Bang { mac, .. } => match ext { SyntaxExtensionKind::Bang(expander) => { self.gate_proc_macro_expansion_kind(span, fragment_kind); - let tok_result = expander.expand(self.cx, span, mac.stream()); + let tok_result = expander.expand(self.cx, span, mac.args.inner_tokens()); self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span) } SyntaxExtensionKind::LegacyBang(expander) => { let prev = self.cx.current_expansion.prior_type_ascription; self.cx.current_expansion.prior_type_ascription = mac.prior_type_ascription; - let tok_result = expander.expand(self.cx, span, mac.stream()); + let tok_result = expander.expand(self.cx, span, mac.args.inner_tokens()); let result = if let Some(result) = fragment_kind.make_from(tok_result) { result } else { @@ -642,8 +642,11 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstF => panic!("unexpected annotatable"), })), DUMMY_SP).into(); let item = attr.unwrap_normal_item(); - let input = self.extract_proc_macro_attr_input(item.tokens, span); - let tok_result = expander.expand(self.cx, span, input, item_tok); + if let MacArgs::Eq(..) = item.args { + self.cx.span_err(span, "key-value macro attributes are not supported"); + } + let tok_result = + expander.expand(self.cx, span, item.args.inner_tokens(), item_tok); self.parse_ast_fragment(tok_result, fragment_kind, &item.path, span) } SyntaxExtensionKind::LegacyAttr(expander) => { @@ -687,23 +690,6 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstF } } - fn extract_proc_macro_attr_input(&self, tokens: TokenStream, span: Span) -> TokenStream { - let mut trees = tokens.trees(); - match trees.next() { - Some(TokenTree::Delimited(_, _, tts)) => { - if trees.next().is_none() { - return tts.into() - } - } - Some(TokenTree::Token(..)) => {} - None => return TokenStream::default(), - } - self.cx.span_err(span, "custom attribute invocations must be \ - of the form `#[foo]` or `#[foo(..)]`, the macro name must only be \ - followed by a delimiter token"); - TokenStream::default() - } - fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { let kind = match item { Annotatable::Item(item) => match &item.kind { @@ -1560,7 +1546,7 @@ fn visit_attribute(&mut self, at: &mut ast::Attribute) { let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items); *at = attr::Attribute { kind: ast::AttrKind::Normal( - AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, + AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span) }, ), span: at.span, id: at.id, diff --git a/src/libsyntax_expand/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs index b191527df19..e3c3655bcf8 100644 --- a/src/libsyntax_expand/mbe/macro_rules.rs +++ b/src/libsyntax_expand/mbe/macro_rules.rs @@ -318,8 +318,8 @@ pub fn compile_declarative_macro( let tt_spec = ast::Ident::new(sym::tt, def.span); // Parse the macro_rules! invocation - let body = match def.kind { - ast::ItemKind::MacroDef(ref body) => body, + let (is_legacy, body) = match &def.kind { + ast::ItemKind::MacroDef(macro_def) => (macro_def.legacy, macro_def.body.inner_tokens()), _ => unreachable!(), }; @@ -338,7 +338,7 @@ pub fn compile_declarative_macro( mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec), ], separator: Some(Token::new( - if body.legacy { token::Semi } else { token::Comma }, + if is_legacy { token::Semi } else { token::Comma }, def.span, )), kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span), @@ -350,7 +350,7 @@ pub fn compile_declarative_macro( DelimSpan::dummy(), Lrc::new(mbe::SequenceRepetition { tts: vec![mbe::TokenTree::token( - if body.legacy { token::Semi } else { token::Comma }, + if is_legacy { token::Semi } else { token::Comma }, def.span, )], separator: None, @@ -360,7 +360,7 @@ pub fn compile_declarative_macro( ), ]; - let argument_map = match parse(sess, body.stream(), &argument_gram, None, true) { + let argument_map = match parse(sess, body, &argument_gram, None, true) { Success(m) => m, Failure(token, msg) => { let s = parse_failure_msg(&token); @@ -435,7 +435,7 @@ pub fn compile_declarative_macro( // that is not lint-checked and trigger the "failed to process buffered lint here" bug. valid &= macro_check::check_meta_variables(sess, ast::CRATE_NODE_ID, def.span, &lhses, &rhses); - let (transparency, transparency_error) = attr::find_transparency(&def.attrs, body.legacy); + let (transparency, transparency_error) = attr::find_transparency(&def.attrs, is_legacy); match transparency_error { Some(TransparencyError::UnknownTransparency(value, span)) => diag.span_err(span, &format!("unknown macro transparency: `{}`", value)), diff --git a/src/libsyntax_expand/mbe/transcribe.rs b/src/libsyntax_expand/mbe/transcribe.rs index 4092d4b97de..a1157667df1 100644 --- a/src/libsyntax_expand/mbe/transcribe.rs +++ b/src/libsyntax_expand/mbe/transcribe.rs @@ -30,13 +30,6 @@ fn visit_mac(&mut self, mac: &mut Mac) { } } -impl Marker { - fn visit_delim_span(&mut self, dspan: &mut DelimSpan) { - self.visit_span(&mut dspan.open); - self.visit_span(&mut dspan.close); - } -} - /// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`). enum Frame { Delimited { forest: Lrc, idx: usize, span: DelimSpan }, @@ -271,7 +264,7 @@ pub(super) fn transcribe( // jump back out of the Delimited, pop the result_stack and add the new results back to // the previous results (from outside the Delimited). mbe::TokenTree::Delimited(mut span, delimited) => { - marker.visit_delim_span(&mut span); + mut_visit::visit_delim_span(&mut span, &mut marker); stack.push(Frame::Delimited { forest: delimited, idx: 0, span }); result_stack.push(mem::take(&mut result)); } diff --git a/src/libsyntax_expand/parse/tests.rs b/src/libsyntax_expand/parse/tests.rs index 08950ddefba..30e83c151e2 100644 --- a/src/libsyntax_expand/parse/tests.rs +++ b/src/libsyntax_expand/parse/tests.rs @@ -272,7 +272,7 @@ fn parse_expr_from_source_str( "foo!( fn main() { body } )".to_string(), &sess).unwrap(); let tts: Vec<_> = match expr.kind { - ast::ExprKind::Mac(ref mac) => mac.stream().trees().collect(), + ast::ExprKind::Mac(ref mac) => mac.args.inner_tokens().trees().collect(), _ => panic!("not a macro"), }; diff --git a/src/libsyntax_expand/placeholders.rs b/src/libsyntax_expand/placeholders.rs index 6cbe8c13245..74ade1de20e 100644 --- a/src/libsyntax_expand/placeholders.rs +++ b/src/libsyntax_expand/placeholders.rs @@ -3,7 +3,6 @@ use syntax::ast; use syntax::source_map::{DUMMY_SP, dummy_spanned}; -use syntax::tokenstream::TokenStream; use syntax::mut_visit::*; use syntax::ptr::P; use syntax::ThinVec; @@ -17,9 +16,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId, vis: Option ast::Mac { ast::Mac { path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, - tts: TokenStream::default().into(), - delim: ast::MacDelimiter::Brace, - span: DUMMY_SP, + args: P(ast::MacArgs::Empty), prior_type_ascription: None, } } diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs index 099cf0a4be9..8e56e2bb00b 100644 --- a/src/libsyntax_expand/proc_macro.rs +++ b/src/libsyntax_expand/proc_macro.rs @@ -1,7 +1,7 @@ use crate::base::{self, *}; use crate::proc_macro_server; -use syntax::ast::{self, ItemKind}; +use syntax::ast::{self, ItemKind, MacArgs}; use syntax::errors::{Applicability, FatalError}; use syntax::symbol::sym; use syntax::token; @@ -183,7 +183,7 @@ fn expand(&self, } let parse_derive_paths = |attr: &ast::Attribute| { - if attr.get_normal_item().tokens.is_empty() { + if let MacArgs::Empty = attr.get_normal_item().args { return Ok(Vec::new()); } rustc_parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths()) diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs index c4f3c03813f..c788d062994 100644 --- a/src/libsyntax_ext/assert.rs +++ b/src/libsyntax_ext/assert.rs @@ -6,7 +6,7 @@ use syntax::print::pprust; use syntax::ptr::P; use syntax::symbol::{sym, Symbol}; -use syntax::tokenstream::{TokenStream, TokenTree}; +use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree}; use syntax_expand::base::*; use syntax_pos::{Span, DUMMY_SP}; @@ -26,19 +26,19 @@ pub fn expand_assert<'cx>( // `core::panic` and `std::panic` are different macros, so we use call-site // context to pick up whichever is currently in scope. let sp = cx.with_call_site_ctxt(sp); + let tokens = custom_message.unwrap_or_else(|| { + TokenStream::from(TokenTree::token( + TokenKind::lit(token::Str, Symbol::intern(&format!( + "assertion failed: {}", + pprust::expr_to_string(&cond_expr).escape_debug() + )), None), + DUMMY_SP, + )) + }); + let args = P(MacArgs::Delimited(DelimSpan::from_single(sp), MacDelimiter::Parenthesis, tokens)); let panic_call = Mac { path: Path::from_ident(Ident::new(sym::panic, sp)), - tts: custom_message.unwrap_or_else(|| { - TokenStream::from(TokenTree::token( - TokenKind::lit(token::Str, Symbol::intern(&format!( - "assertion failed: {}", - pprust::expr_to_string(&cond_expr).escape_debug() - )), None), - DUMMY_SP, - )) - }).into(), - delim: MacDelimiter::Parenthesis, - span: sp, + args, prior_type_ascription: None, }; let if_expr = cx.expr_if( diff --git a/src/libsyntax_ext/cmdline_attrs.rs b/src/libsyntax_ext/cmdline_attrs.rs index 5c3009c432c..98cf8a34742 100644 --- a/src/libsyntax_ext/cmdline_attrs.rs +++ b/src/libsyntax_ext/cmdline_attrs.rs @@ -16,7 +16,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - ); let start_span = parser.token.span; - let AttrItem { path, tokens } = panictry!(parser.parse_attr_item()); + let AttrItem { path, args } = panictry!(parser.parse_attr_item()); let end_span = parser.token.span; if parser.token != token::Eof { parse_sess.span_diagnostic @@ -24,7 +24,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - continue; } - krate.attrs.push(mk_attr(AttrStyle::Inner, path, tokens, start_span.to(end_span))); + krate.attrs.push(mk_attr(AttrStyle::Inner, path, args, start_span.to(end_span))); } krate diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index b6bf2f88161..5bd84b43a78 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -340,14 +340,12 @@ pub fn combine_substructure(f: CombineSubstructureFunc<'_>) fn find_type_parameters( ty: &ast::Ty, ty_param_names: &[ast::Name], - span: Span, cx: &ExtCtxt<'_>, ) -> Vec> { use syntax::visit; struct Visitor<'a, 'b> { cx: &'a ExtCtxt<'b>, - span: Span, ty_param_names: &'a [ast::Name], types: Vec>, } @@ -366,18 +364,11 @@ fn visit_ty(&mut self, ty: &'a ast::Ty) { } fn visit_mac(&mut self, mac: &ast::Mac) { - let span = mac.span.with_ctxt(self.span.ctxt()); - self.cx.span_err(span, "`derive` cannot be used on items with type macros"); + self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros"); } } - let mut visitor = Visitor { - ty_param_names, - types: Vec::new(), - span, - cx, - }; - + let mut visitor = Visitor { cx, ty_param_names, types: Vec::new() }; visit::Visitor::visit_ty(&mut visitor, ty); visitor.types @@ -605,7 +596,7 @@ fn create_derived_impl(&self, .collect(); for field_ty in field_tys { - let tys = find_type_parameters(&field_ty, &ty_param_names, self.span, cx); + let tys = find_type_parameters(&field_ty, &ty_param_names, cx); for ty in tys { // if we have already handled this type, skip it diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 7d43c3c8d07..88a325112ac 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -177,6 +177,7 @@ cfg_attr, cfg_attr_multi, cfg_doctest, + cfg_sanitize, cfg_target_feature, cfg_target_has_atomic, cfg_target_thread_local, @@ -279,6 +280,7 @@ Err, Eq, Equal, + enclosing_scope, except, exclusive_range_pattern, exhaustive_integer_patterns, @@ -634,6 +636,7 @@ rust_eh_unwind_resume, rust_oom, rvalue_static_promotion, + sanitize, sanitizer_runtime, _Self, self_in_typedefs, diff --git a/src/test/mir-opt/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline-closure-borrows-arg.rs index b5bfeef5e9c..768f4953228 100644 --- a/src/test/mir-opt/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline-closure-borrows-arg.rs @@ -21,8 +21,8 @@ fn foo(_t: T, q: &i32) -> i32 { // debug _t => _1; // debug q => _2; // let mut _0: i32; -// let _3: [closure@HirId { owner: DefIndex(4), local_id: 31 }]; -// let mut _4: &[closure@HirId { owner: DefIndex(4), local_id: 31 }]; +// let _3: [closure@foo::{{closure}}#0]; +// let mut _4: &[closure@foo::{{closure}}#0]; // let mut _5: (&i32, &i32); // let mut _6: &i32; // let mut _7: &i32; @@ -40,7 +40,7 @@ fn foo(_t: T, q: &i32) -> i32 { // } // bb0: { // ... -// _3 = [closure@HirId { owner: DefIndex(4), local_id: 31 }]; +// _3 = [closure@foo::::{{closure}}#0]; // ... // _4 = &_3; // ... diff --git a/src/test/mir-opt/inline-closure-captures.rs b/src/test/mir-opt/inline-closure-captures.rs index e73dbe48bd1..e000a418d90 100644 --- a/src/test/mir-opt/inline-closure-captures.rs +++ b/src/test/mir-opt/inline-closure-captures.rs @@ -17,10 +17,10 @@ fn foo(t: T, q: i32) -> (i32, T) { // debug t => _1; // debug q => _2; // let mut _0: (i32, T); -// let _3: [closure@HirId { owner: DefIndex(4), local_id: 15 } q:&i32, t:&T]; +// let _3: [closure@foo::{{closure}}#0 q:&i32, t:&T]; // let mut _4: &i32; // let mut _5: &T; -// let mut _6: &[closure@HirId { owner: DefIndex(4), local_id: 15 } q:&i32, t:&T]; +// let mut _6: &[closure@foo::{{closure}}#0 q:&i32, t:&T]; // let mut _7: (i32,); // let mut _8: i32; // let mut _11: i32; @@ -39,7 +39,7 @@ fn foo(t: T, q: i32) -> (i32, T) { // _4 = &_2; // ... // _5 = &_1; -// _3 = [closure@HirId { owner: DefIndex(4), local_id: 15 }] { q: move _4, t: move _5 }; +// _3 = [closure@foo::::{{closure}}#0] { q: move _4, t: move _5 }; // ... // _6 = &_3; // ... diff --git a/src/test/mir-opt/inline-closure.rs b/src/test/mir-opt/inline-closure.rs index ddf027f4be3..bd36e77818e 100644 --- a/src/test/mir-opt/inline-closure.rs +++ b/src/test/mir-opt/inline-closure.rs @@ -17,8 +17,8 @@ fn foo(_t: T, q: i32) -> i32 { // debug _t => _1; // debug q => _2; // let mut _0: i32; -// let _3: [closure@HirId { owner: DefIndex(4), local_id: 15 }]; -// let mut _4: &[closure@HirId { owner: DefIndex(4), local_id: 15 }]; +// let _3: [closure@foo::{{closure}}#0]; +// let mut _4: &[closure@foo::{{closure}}#0]; // let mut _5: (i32, i32); // let mut _6: i32; // let mut _7: i32; @@ -33,7 +33,7 @@ fn foo(_t: T, q: i32) -> i32 { // } // bb0: { // ... -// _3 = [closure@HirId { owner: DefIndex(4), local_id: 15 }]; +// _3 = [closure@foo::::{{closure}}#0]; // ... // _4 = &_3; // ... diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index 96b848eb1d4..32995448a21 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -100,7 +100,7 @@ fn main() { // } // END rustc.main.EraseRegions.after.mir // START rustc.main-{{closure}}.EraseRegions.after.mir -// fn main::{{closure}}#0(_1: &[closure@HirId { owner: DefIndex(13), local_id: 72 }], _2: &i32) -> &i32 { +// fn main::{{closure}}#0(_1: &[closure@main::{{closure}}#0], _2: &i32) -> &i32 { // ... // bb0: { // Retag([fn entry] _1); diff --git a/src/test/ui-fulldeps/auxiliary/llvm-pass-plugin.rs b/src/test/ui-fulldeps/auxiliary/llvm-pass-plugin.rs deleted file mode 100644 index 2ff1c2e363d..00000000000 --- a/src/test/ui-fulldeps/auxiliary/llvm-pass-plugin.rs +++ /dev/null @@ -1,19 +0,0 @@ -// force-host - -#![feature(plugin_registrar)] -#![feature(rustc_private)] - -extern crate rustc; -extern crate rustc_driver; - -use rustc_driver::plugin::Registry; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - // This pass is built in to LLVM. - // - // Normally, we would name a pass that was registered through - // C++ static object constructors in the same .so file as the - // plugin registrar. - reg.register_llvm_pass("gvn"); -} diff --git a/src/test/ui-fulldeps/feature-gate-plugin.rs b/src/test/ui-fulldeps/feature-gate-plugin.rs new file mode 100644 index 00000000000..85eaf533643 --- /dev/null +++ b/src/test/ui-fulldeps/feature-gate-plugin.rs @@ -0,0 +1,8 @@ +// aux-build:empty-plugin.rs +// ignore-stage1 + +#![plugin(empty_plugin)] +//~^ ERROR compiler plugins are deprecated +//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated + +fn main() {} diff --git a/src/test/ui-fulldeps/feature-gate-plugin.stderr b/src/test/ui-fulldeps/feature-gate-plugin.stderr new file mode 100644 index 00000000000..c922325c341 --- /dev/null +++ b/src/test/ui-fulldeps/feature-gate-plugin.stderr @@ -0,0 +1,20 @@ +error[E0658]: compiler plugins are deprecated + --> $DIR/feature-gate-plugin.rs:4:1 + | +LL | #![plugin(empty_plugin)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29597 + = help: add `#![feature(plugin)]` to the crate attributes to enable + +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 + --> $DIR/feature-gate-plugin.rs:4:1 + | +LL | #![plugin(empty_plugin)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version + | + = note: `#[warn(deprecated)]` on by default + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-load.rs b/src/test/ui-fulldeps/lint-plugin-cmdline-load.rs index fd681536b5b..0bd95dfbd14 100644 --- a/src/test/ui-fulldeps/lint-plugin-cmdline-load.rs +++ b/src/test/ui-fulldeps/lint-plugin-cmdline-load.rs @@ -1,9 +1,9 @@ -// run-pass +// check-pass // aux-build:lint-plugin-test.rs // ignore-stage1 -// compile-flags: -Z extra-plugins=lint_plugin_test +// compile-flags: -Z crate-attr=plugin(lint_plugin_test) -#![allow(dead_code)] +#![feature(plugin)] fn lintme() { } //~ WARNING item is named 'lintme' diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr b/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr index 5a6b35433ac..1263a0efe62 100644 --- a/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr +++ b/src/test/ui-fulldeps/lint-plugin-cmdline-load.stderr @@ -1,3 +1,11 @@ +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 + --> :1:1 + | +LL | plugin(lint_plugin_test) + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version + | + = note: `#[warn(deprecated)]` on by default + warning: item is named 'lintme' --> $DIR/lint-plugin-cmdline-load.rs:8:1 | diff --git a/src/test/ui-fulldeps/llvm-pass-plugin.rs b/src/test/ui-fulldeps/llvm-pass-plugin.rs deleted file mode 100644 index fa5cbc1e808..00000000000 --- a/src/test/ui-fulldeps/llvm-pass-plugin.rs +++ /dev/null @@ -1,8 +0,0 @@ -// run-pass -// aux-build:llvm-pass-plugin.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(llvm_pass_plugin)] //~ WARNING compiler plugins are deprecated - -pub fn main() { } diff --git a/src/test/ui-fulldeps/llvm-pass-plugin.stderr b/src/test/ui-fulldeps/llvm-pass-plugin.stderr deleted file mode 100644 index 61b53bb2b7c..00000000000 --- a/src/test/ui-fulldeps/llvm-pass-plugin.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/llvm-pass-plugin.rs:6:1 - | -LL | #![plugin(llvm_pass_plugin)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - diff --git a/src/test/ui-fulldeps/macro-crate-multi-decorator.rs b/src/test/ui-fulldeps/macro-crate-multi-decorator.rs index e396cf01615..f21617be5d2 100644 --- a/src/test/ui-fulldeps/macro-crate-multi-decorator.rs +++ b/src/test/ui-fulldeps/macro-crate-multi-decorator.rs @@ -1,9 +1,4 @@ -// run-pass - -#![allow(plugin_as_library)] -#![allow(dead_code)] -#![allow(unused_variables)] -#![allow(unused_imports)] +// check-pass // aux-build:macro-crate-test.rs // ignore-stage1 diff --git a/src/test/ui-fulldeps/plugin-args-1.rs b/src/test/ui-fulldeps/plugin-args-1.rs deleted file mode 100644 index 1865819053e..00000000000 --- a/src/test/ui-fulldeps/plugin-args-1.rs +++ /dev/null @@ -1,8 +0,0 @@ -// check-pass -// aux-build:empty-plugin.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(empty_plugin)] //~ WARNING compiler plugins are deprecated - -fn main() {} diff --git a/src/test/ui-fulldeps/plugin-args-1.stderr b/src/test/ui-fulldeps/plugin-args-1.stderr deleted file mode 100644 index 4e82961acc2..00000000000 --- a/src/test/ui-fulldeps/plugin-args-1.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/plugin-args-1.rs:6:1 - | -LL | #![plugin(empty_plugin)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - diff --git a/src/test/ui-fulldeps/plugin-args-2.rs b/src/test/ui-fulldeps/plugin-args-2.rs deleted file mode 100644 index c4bd1916b85..00000000000 --- a/src/test/ui-fulldeps/plugin-args-2.rs +++ /dev/null @@ -1,8 +0,0 @@ -// check-pass -// aux-build:empty-plugin.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(empty_plugin())] //~ WARNING compiler plugins are deprecated - -fn main() {} diff --git a/src/test/ui-fulldeps/plugin-args-2.stderr b/src/test/ui-fulldeps/plugin-args-2.stderr deleted file mode 100644 index 92bd69b0e4b..00000000000 --- a/src/test/ui-fulldeps/plugin-args-2.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/plugin-args-2.rs:6:1 - | -LL | #![plugin(empty_plugin())] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - diff --git a/src/test/ui-fulldeps/plugin-args-3.rs b/src/test/ui-fulldeps/plugin-args-3.rs deleted file mode 100644 index c8818cc6c31..00000000000 --- a/src/test/ui-fulldeps/plugin-args-3.rs +++ /dev/null @@ -1,8 +0,0 @@ -// check-pass -// aux-build:empty-plugin.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(empty_plugin(hello(there), how(are="you")))] //~ WARNING compiler plugins are deprecated - -fn main() {} diff --git a/src/test/ui-fulldeps/plugin-args-3.stderr b/src/test/ui-fulldeps/plugin-args-3.stderr deleted file mode 100644 index 278853e0881..00000000000 --- a/src/test/ui-fulldeps/plugin-args-3.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/plugin-args-3.rs:6:1 - | -LL | #![plugin(empty_plugin(hello(there), how(are="you")))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - diff --git a/src/test/ui-fulldeps/plugin-args.rs b/src/test/ui-fulldeps/plugin-args.rs new file mode 100644 index 00000000000..488f2b775bf --- /dev/null +++ b/src/test/ui-fulldeps/plugin-args.rs @@ -0,0 +1,9 @@ +// aux-build:empty-plugin.rs +// ignore-stage1 + +#![feature(plugin)] +#![plugin(empty_plugin(args))] +//~^ ERROR malformed `plugin` attribute +//~| WARNING compiler plugins are deprecated + +fn main() {} diff --git a/src/test/ui-fulldeps/plugin-args.stderr b/src/test/ui-fulldeps/plugin-args.stderr new file mode 100644 index 00000000000..2b9094c4c44 --- /dev/null +++ b/src/test/ui-fulldeps/plugin-args.stderr @@ -0,0 +1,16 @@ +error[E0498]: malformed `plugin` attribute + --> $DIR/plugin-args.rs:5:11 + | +LL | #![plugin(empty_plugin(args))] + | ^^^^^^^^^^^^^^^^^^ malformed attribute + +warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 + --> $DIR/plugin-args.rs:5:1 + | +LL | #![plugin(empty_plugin(args))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version + | + = note: `#[warn(deprecated)]` on by default + +error: aborting due to previous error + diff --git a/src/test/ui-fulldeps/plugin-as-extern-crate.rs b/src/test/ui-fulldeps/plugin-as-extern-crate.rs index fa7826c9df7..f231efc0a9a 100644 --- a/src/test/ui-fulldeps/plugin-as-extern-crate.rs +++ b/src/test/ui-fulldeps/plugin-as-extern-crate.rs @@ -1,11 +1,10 @@ +// check-pass // aux-build:empty-plugin.rs // ignore-cross-compile // // empty_plugin will not compile on a cross-compiled target because // libsyntax is not compiled for it. -#![deny(plugin_as_library)] +extern crate empty_plugin; // OK, plugin crates are still crates -extern crate empty_plugin; //~ ERROR compiler plugin used as an ordinary library - -fn main() { } +fn main() {} diff --git a/src/test/ui-fulldeps/plugin-as-extern-crate.stderr b/src/test/ui-fulldeps/plugin-as-extern-crate.stderr deleted file mode 100644 index d2fbb5d3517..00000000000 --- a/src/test/ui-fulldeps/plugin-as-extern-crate.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: compiler plugin used as an ordinary library - --> $DIR/plugin-as-extern-crate.rs:9:1 - | -LL | extern crate empty_plugin; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: lint level defined here - --> $DIR/plugin-as-extern-crate.rs:7:9 - | -LL | #![deny(plugin_as_library)] - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr index 7d31f60efdc..46f8f41076b 100644 --- a/src/test/ui/async-await/try-on-option-in-async.stderr +++ b/src/test/ui/async-await/try-on-option-in-async.stderr @@ -1,8 +1,14 @@ error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-on-option-in-async.rs:8:9 | -LL | x?; - | ^^ cannot use the `?` operator in an async block that returns `{integer}` +LL | async { + | ___________- +LL | | let x: Option = None; +LL | | x?; + | | ^^ cannot use the `?` operator in an async block that returns `{integer}` +LL | | 22 +LL | | }.await + | |_____- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `{integer}` = note: required by `std::ops::Try::from_error` @@ -10,8 +16,14 @@ LL | x?; error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-on-option-in-async.rs:16:9 | -LL | x?; - | ^^ cannot use the `?` operator in an async closure that returns `u32` +LL | let async_closure = async || { + | __________________________________- +LL | | let x: Option = None; +LL | | x?; + | | ^^ cannot use the `?` operator in an async closure that returns `u32` +LL | | 22_u32 +LL | | }; + | |_____- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `u32` = note: required by `std::ops::Try::from_error` @@ -19,8 +31,14 @@ LL | x?; error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-on-option-in-async.rs:25:5 | -LL | x?; - | ^^ cannot use the `?` operator in an async function that returns `u32` +LL | async fn an_async_function() -> u32 { + | _____________________________________- +LL | | let x: Option = None; +LL | | x?; + | | ^^ cannot use the `?` operator in an async function that returns `u32` +LL | | 22 +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `u32` = note: required by `std::ops::Try::from_error` diff --git a/src/test/ui/consts/const-multi-ref.rs b/src/test/ui/consts/const-multi-ref.rs index 498e99e668b..5e2be0d4f3f 100644 --- a/src/test/ui/consts/const-multi-ref.rs +++ b/src/test/ui/consts/const-multi-ref.rs @@ -1,11 +1,24 @@ -const _X: i32 = { +// Ensure that we point the user to the erroneous borrow but not to any subsequent borrows of that +// initial one. + +const _: i32 = { let mut a = 5; - let p = &mut a; //~ ERROR references in constants may only refer to immutable values + let p = &mut a; //~ ERROR references in constants may only refer to immutable values - let reborrow = {p}; //~ ERROR references in constants may only refer to immutable values + let reborrow = {p}; let pp = &reborrow; let ppp = &pp; ***ppp }; +const _: std::cell::Cell = { + let mut a = std::cell::Cell::new(5); + let p = &a; //~ ERROR cannot borrow a constant which may contain interior mutability + + let reborrow = {p}; + let pp = &reborrow; + let ppp = &pp; + a +}; + fn main() {} diff --git a/src/test/ui/consts/const-multi-ref.stderr b/src/test/ui/consts/const-multi-ref.stderr index 9e525ef9aac..ed3837e9c9e 100644 --- a/src/test/ui/consts/const-multi-ref.stderr +++ b/src/test/ui/consts/const-multi-ref.stderr @@ -1,15 +1,16 @@ error[E0017]: references in constants may only refer to immutable values - --> $DIR/const-multi-ref.rs:3:13 + --> $DIR/const-multi-ref.rs:6:13 | LL | let p = &mut a; | ^^^^^^ constants require immutable values -error[E0017]: references in constants may only refer to immutable values - --> $DIR/const-multi-ref.rs:5:21 +error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead + --> $DIR/const-multi-ref.rs:16:13 | -LL | let reborrow = {p}; - | ^ constants require immutable values +LL | let p = &a; + | ^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0017, E0492. +For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs index 94b6587eb81..3bc518c2c2b 100644 --- a/src/test/ui/error-codes/E0017.rs +++ b/src/test/ui/error-codes/E0017.rs @@ -1,8 +1,11 @@ static X: i32 = 1; const C: i32 = 2; +static mut M: i32 = 3; const CR: &'static mut i32 = &mut C; //~ ERROR E0017 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 + //~| ERROR E0019 //~| ERROR cannot borrow static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 +static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0017 fn main() {} diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index 47863f02214..8c8660adceb 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -1,28 +1,40 @@ error[E0017]: references in constants may only refer to immutable values - --> $DIR/E0017.rs:4:30 + --> $DIR/E0017.rs:5:30 | LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ constants require immutable values +error[E0019]: static contains unimplemented expression type + --> $DIR/E0017.rs:6:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; + | ^^^^^^ + error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0017.rs:5:39 + --> $DIR/E0017.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ statics require immutable values error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:5:39 + --> $DIR/E0017.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0017.rs:7:38 + --> $DIR/E0017.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ statics require immutable values -error: aborting due to 4 previous errors +error[E0017]: references in statics may only refer to immutable values + --> $DIR/E0017.rs:10:52 + | +LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; + | ^^^^^^ statics require immutable values + +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0017, E0596. +Some errors have detailed explanations: E0017, E0019, E0596. For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs deleted file mode 100644 index 3aa4ac9655c..00000000000 --- a/src/test/ui/error-codes/E0388.rs +++ /dev/null @@ -1,9 +0,0 @@ -static X: i32 = 1; -const C: i32 = 2; - -const CR: &'static mut i32 = &mut C; //~ ERROR E0017 -static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 - //~| ERROR cannot borrow -static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 - -fn main() {} diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr deleted file mode 100644 index b52d5260b13..00000000000 --- a/src/test/ui/error-codes/E0388.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error[E0017]: references in constants may only refer to immutable values - --> $DIR/E0388.rs:4:30 - | -LL | const CR: &'static mut i32 = &mut C; - | ^^^^^^ constants require immutable values - -error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0388.rs:5:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ statics require immutable values - -error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0388.rs:5:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ cannot borrow as mutable - -error[E0017]: references in statics may only refer to immutable values - --> $DIR/E0388.rs:7:38 - | -LL | static CONST_REF: &'static mut i32 = &mut C; - | ^^^^^^ statics require immutable values - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0017, E0596. -For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/feature-gates/feature-gate-cfg_sanitize.rs b/src/test/ui/feature-gates/feature-gate-cfg_sanitize.rs new file mode 100644 index 00000000000..c3e7cc9ed8a --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg_sanitize.rs @@ -0,0 +1,3 @@ +#[cfg(not(sanitize = "thread"))] +//~^ `cfg(sanitize)` is experimental +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-cfg_sanitize.stderr b/src/test/ui/feature-gates/feature-gate-cfg_sanitize.stderr new file mode 100644 index 00000000000..f67a0d83bdd --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg_sanitize.stderr @@ -0,0 +1,12 @@ +error[E0658]: `cfg(sanitize)` is experimental and subject to change + --> $DIR/feature-gate-cfg_sanitize.rs:1:11 + | +LL | #[cfg(not(sanitize = "thread"))] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/39699 + = help: add `#![feature(cfg_sanitize)]` 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/feature-gates/feature-gate-plugin.rs b/src/test/ui/feature-gates/feature-gate-plugin.rs deleted file mode 100644 index 8904ec0448a..00000000000 --- a/src/test/ui/feature-gates/feature-gate-plugin.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Test that `#![plugin(...)]` attribute is gated by `plugin` feature gate - -#![plugin(foo)] -//~^ ERROR compiler plugins are deprecated -//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-plugin.stderr b/src/test/ui/feature-gates/feature-gate-plugin.stderr deleted file mode 100644 index f89ddf995c4..00000000000 --- a/src/test/ui/feature-gates/feature-gate-plugin.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0658]: compiler plugins are deprecated - --> $DIR/feature-gate-plugin.rs:3:1 - | -LL | #![plugin(foo)] - | ^^^^^^^^^^^^^^^ - | - = note: for more information, see https://github.com/rust-lang/rust/issues/29597 - = help: add `#![feature(plugin)]` to the crate attributes to enable - -warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/feature-gate-plugin.rs:3:1 - | -LL | #![plugin(foo)] - | ^^^^^^^^^^^^^^^ help: may be removed in a future compiler version - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issues/issue-10536.rs b/src/test/ui/issues/issue-10536.rs index 111078abb37..f536d8f940a 100644 --- a/src/test/ui/issues/issue-10536.rs +++ b/src/test/ui/issues/issue-10536.rs @@ -11,9 +11,9 @@ macro_rules! bar{() => (())} pub fn main() { foo!(); - assert!({one! two()}); //~ ERROR expected open delimiter + assert!({one! two()}); //~ ERROR expected one of `(`, `[`, or `{`, found `two` // regardless of whether nested macro_rules works, the following should at // least throw a conventional error. - assert!({one! two}); //~ ERROR expected open delimiter + assert!({one! two}); //~ ERROR expected one of `(`, `[`, or `{`, found `two` } diff --git a/src/test/ui/issues/issue-10536.stderr b/src/test/ui/issues/issue-10536.stderr index 73f948107f1..cc048445871 100644 --- a/src/test/ui/issues/issue-10536.stderr +++ b/src/test/ui/issues/issue-10536.stderr @@ -1,14 +1,14 @@ -error: expected open delimiter +error: expected one of `(`, `[`, or `{`, found `two` --> $DIR/issue-10536.rs:14:19 | LL | assert!({one! two()}); - | ^^^ expected open delimiter + | ^^^ expected one of `(`, `[`, or `{` -error: expected open delimiter +error: expected one of `(`, `[`, or `{`, found `two` --> $DIR/issue-10536.rs:18:19 | LL | assert!({one! two}); - | ^^^ expected open delimiter + | ^^^ expected one of `(`, `[`, or `{` error: aborting due to 2 previous errors diff --git a/src/test/ui/malformed/malformed-plugin-1.stderr b/src/test/ui/malformed/malformed-plugin-1.stderr index 3860864bd13..2a4f772850e 100644 --- a/src/test/ui/malformed/malformed-plugin-1.stderr +++ b/src/test/ui/malformed/malformed-plugin-1.stderr @@ -2,7 +2,7 @@ error: malformed `plugin` attribute input --> $DIR/malformed-plugin-1.rs:2:1 | LL | #![plugin] - | ^^^^^^^^^^ help: must be of the form: `#[plugin(name|name(args))]` + | ^^^^^^^^^^ help: must be of the form: `#[plugin(name)]` warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 --> $DIR/malformed-plugin-1.rs:2:1 diff --git a/src/test/ui/malformed/malformed-plugin-2.stderr b/src/test/ui/malformed/malformed-plugin-2.stderr index e4bca93f13b..fe116a40610 100644 --- a/src/test/ui/malformed/malformed-plugin-2.stderr +++ b/src/test/ui/malformed/malformed-plugin-2.stderr @@ -2,7 +2,7 @@ error: malformed `plugin` attribute input --> $DIR/malformed-plugin-2.rs:2:1 | LL | #![plugin="bleh"] - | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[plugin(name|name(args))]` + | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[plugin(name)]` warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 --> $DIR/malformed-plugin-2.rs:2:1 diff --git a/src/test/ui/malformed/malformed-plugin-3.stderr b/src/test/ui/malformed/malformed-plugin-3.stderr index 7393072cb1c..4af933c15f6 100644 --- a/src/test/ui/malformed/malformed-plugin-3.stderr +++ b/src/test/ui/malformed/malformed-plugin-3.stderr @@ -1,8 +1,8 @@ error[E0498]: malformed `plugin` attribute - --> $DIR/malformed-plugin-3.rs:2:1 + --> $DIR/malformed-plugin-3.rs:2:11 | LL | #![plugin(foo="bleh")] - | ^^^^^^^^^^^^^^^^^^^^^^ malformed attribute + | ^^^^^^^^^^ malformed attribute warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 --> $DIR/malformed-plugin-3.rs:2:1 diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index 1f15ce5c212..abeffee4d3f 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -6,7 +6,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | = note: defining type: DefId(0:4 ~ escape_argument_callee[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) i32)), + for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) i32)), ] error: lifetime may not live long enough diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index 610a4aed796..f750d15533b 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -6,7 +6,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | = note: defining type: DefId(0:4 ~ escape_argument[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32)), + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)), ] note: No external requirements diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index 43406c05a25..92f30d400f2 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -10,7 +10,7 @@ LL | | }, | = note: defining type: DefId(0:18 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), ] = note: late-bound region is '_#4r = note: late-bound region is '_#5r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index 6f5b813e85e..00bb66afbe5 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: DefId(0:16 ~ propagate_approximated_ref[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 5ebc22da036..2b05503b58d 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -10,7 +10,7 @@ LL | | }) | = note: defining type: DefId(0:9 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]::{{closure}}[0]) with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>)), + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), ] error[E0521]: borrowed data escapes outside of closure @@ -48,7 +48,7 @@ LL | | }) | = note: defining type: DefId(0:11 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]::{{closure}}[0]) with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>)), + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), ] = note: number of external vids: 2 = note: where '_#1r: '_#0r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index 5ebf8e248b3..ee0f0b7e65d 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -12,7 +12,7 @@ LL | | }); | = note: defining type: DefId(0:16 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) u32>)), + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t2)) u32>)), ] = note: late-bound region is '_#2r = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 91caa42c9bf..611a129e00c 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -12,7 +12,7 @@ LL | | }); | = note: defining type: DefId(0:16 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index 243c8b12ecb..9328d05518c 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: DefId(0:16 ~ propagate_approximated_val[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index c5468e73cfa..afac5267c48 100644 --- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -10,7 +10,7 @@ LL | | }, | = note: defining type: DefId(0:14 ~ propagate_despite_same_free_region[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index bf43c893865..9699e8fbdf8 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: DefId(0:16 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), ] = note: late-bound region is '_#2r = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 569bae999dd..2a18079cdc3 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: DefId(0:16 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index 00c56a796d1..8ce0b7758b0 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -6,7 +6,7 @@ LL | expect_sig(|a, b| b); // ought to return `a` | = note: defining type: DefId(0:4 ~ return_wrong_bound_region[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) i32, + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, ] error: lifetime may not live long enough diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index d33f6722298..d9cbc71f954 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -38,7 +38,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:15 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(16), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:15 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(DefId(0:16 ~ projection_one_region_closure[317d]::no_relationships_late[0]::'a[0]), 'a))`... error: lifetime may not live long enough --> $DIR/projection-one-region-closure.rs:45:39 diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index ed548a3b4e2..ed53ce91133 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -39,7 +39,7 @@ error[E0309]: the associated type `>::AssocType` may LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `>::AssocType: ReFree(DefId(0:17 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(18), 'a))`... + = help: consider adding an explicit lifetime bound `>::AssocType: ReFree(DefId(0:17 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(DefId(0:18 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]::'a[0]), 'a))`... note: External requirements --> $DIR/projection-two-region-trait-bound-closure.rs:48:29 diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index fd8d8917c18..e2a9bd7e3cd 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -7,7 +7,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); = note: defining type: DefId(0:11 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]::{{closure}}[0]) with closure substs [ T, i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) T)), + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), ] = note: number of external vids: 2 = note: where T: '_#1r @@ -34,7 +34,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); = note: defining type: DefId(0:15 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [ T, i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) T)), + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), ] = note: late-bound region is '_#2r = note: number of external vids: 3 @@ -59,7 +59,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:12 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(crate0:DefIndex(13), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:12 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(DefId(0:13 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::'a[0]), 'a))`... error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index 97b84d1bdf8..ffd936b58be 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -49,7 +49,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:11 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(12), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:11 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(DefId(0:12 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]::'a[0]), 'a))`... note: External requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26 @@ -139,7 +139,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:19 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(20), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:19 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(DefId(0:20 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::'a[0]), 'a))`... note: External requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26 diff --git a/src/test/ui/on-unimplemented/enclosing-scope.rs b/src/test/ui/on-unimplemented/enclosing-scope.rs new file mode 100644 index 00000000000..881bff63f5f --- /dev/null +++ b/src/test/ui/on-unimplemented/enclosing-scope.rs @@ -0,0 +1,27 @@ +// Test scope annotations from `enclosing_scope` parameter + +#![feature(rustc_attrs)] + +#[rustc_on_unimplemented(enclosing_scope="in this scope")] +trait Trait{} + +struct Foo; + +fn f(x: T) {} + +fn main() { + let x = || { + f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied + let y = || { + f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied + }; + }; + + { + { + f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied + } + } + + f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied +} diff --git a/src/test/ui/on-unimplemented/enclosing-scope.stderr b/src/test/ui/on-unimplemented/enclosing-scope.stderr new file mode 100644 index 00000000000..092e560330b --- /dev/null +++ b/src/test/ui/on-unimplemented/enclosing-scope.stderr @@ -0,0 +1,66 @@ +error[E0277]: the trait bound `Foo: Trait` is not satisfied + --> $DIR/enclosing-scope.rs:14:11 + | +LL | fn f(x: T) {} + | - ----- required by this bound in `f` +... +LL | let x = || { + | _____________- +LL | | f(Foo{}); + | | ^^^^^ the trait `Trait` is not implemented for `Foo` +LL | | let y = || { +LL | | f(Foo{}); +LL | | }; +LL | | }; + | |_____- in this scope + +error[E0277]: the trait bound `Foo: Trait` is not satisfied + --> $DIR/enclosing-scope.rs:16:15 + | +LL | fn f(x: T) {} + | - ----- required by this bound in `f` +... +LL | let y = || { + | _________________- +LL | | f(Foo{}); + | | ^^^^^ the trait `Trait` is not implemented for `Foo` +LL | | }; + | |_________- in this scope + +error[E0277]: the trait bound `Foo: Trait` is not satisfied + --> $DIR/enclosing-scope.rs:22:15 + | +LL | fn f(x: T) {} + | - ----- required by this bound in `f` +LL | +LL | / fn main() { +LL | | let x = || { +LL | | f(Foo{}); +LL | | let y = || { +... | +LL | | f(Foo{}); + | | ^^^^^ the trait `Trait` is not implemented for `Foo` +... | +LL | | f(Foo{}); +LL | | } + | |_- in this scope + +error[E0277]: the trait bound `Foo: Trait` is not satisfied + --> $DIR/enclosing-scope.rs:26:7 + | +LL | fn f(x: T) {} + | - ----- required by this bound in `f` +LL | +LL | / fn main() { +LL | | let x = || { +LL | | f(Foo{}); +LL | | let y = || { +... | +LL | | f(Foo{}); + | | ^^^^^ the trait `Trait` is not implemented for `Foo` +LL | | } + | |_- in this scope + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/parser/macro-bad-delimiter-ident.rs b/src/test/ui/parser/macro-bad-delimiter-ident.rs index 13dec95435b..f461f06b4dc 100644 --- a/src/test/ui/parser/macro-bad-delimiter-ident.rs +++ b/src/test/ui/parser/macro-bad-delimiter-ident.rs @@ -1,3 +1,3 @@ fn main() { - foo! bar < //~ ERROR expected open delimiter + foo! bar < //~ ERROR expected one of `(`, `[`, or `{`, found `bar` } diff --git a/src/test/ui/parser/macro-bad-delimiter-ident.stderr b/src/test/ui/parser/macro-bad-delimiter-ident.stderr index e97839a4f4a..f2365fed273 100644 --- a/src/test/ui/parser/macro-bad-delimiter-ident.stderr +++ b/src/test/ui/parser/macro-bad-delimiter-ident.stderr @@ -1,8 +1,8 @@ -error: expected open delimiter +error: expected one of `(`, `[`, or `{`, found `bar` --> $DIR/macro-bad-delimiter-ident.rs:2:10 | LL | foo! bar < - | ^^^ expected open delimiter + | ^^^ expected one of `(`, `[`, or `{` error: aborting due to previous error diff --git a/src/test/ui/proc-macro/proc-macro-gates.rs b/src/test/ui/proc-macro/proc-macro-gates.rs index 0096a84f14c..591c1e039bd 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.rs +++ b/src/test/ui/proc-macro/proc-macro-gates.rs @@ -18,7 +18,7 @@ mod _test2_inner { //~| ERROR: non-builtin inner attributes are unstable } -#[empty_attr = "y"] //~ ERROR: must only be followed by a delimiter token +#[empty_attr = "y"] //~ ERROR: key-value macro attributes are not supported fn _test3() {} fn attrs() { diff --git a/src/test/ui/proc-macro/proc-macro-gates.stderr b/src/test/ui/proc-macro/proc-macro-gates.stderr index 14a4f8c0fbc..e939434243b 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.stderr +++ b/src/test/ui/proc-macro/proc-macro-gates.stderr @@ -34,7 +34,7 @@ LL | #![empty_attr] = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable -error: custom attribute invocations must be of the form `#[foo]` or `#[foo(..)]`, the macro name must only be followed by a delimiter token +error: key-value macro attributes are not supported --> $DIR/proc-macro-gates.rs:21:1 | LL | #[empty_attr = "y"] diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index f24ea0505e7..1143bddfe45 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -575,8 +575,17 @@ LL | if (let 0 = 0)? {} error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/disallowed-positions.rs:46:8 | -LL | if (let 0 = 0)? {} - | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` +LL | / fn nested_within_if_expr() { +LL | | if &let 0 = 0 {} +LL | | +LL | | +... | +LL | | if (let 0 = 0)? {} + | | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` +... | +LL | | if let true = let true = true {} +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `()` = note: required by `std::ops::Try::from_error` @@ -754,8 +763,17 @@ LL | while (let 0 = 0)? {} error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/disallowed-positions.rs:110:11 | -LL | while (let 0 = 0)? {} - | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` +LL | / fn nested_within_while_expr() { +LL | | while &let 0 = 0 {} +LL | | +LL | | +... | +LL | | while (let 0 = 0)? {} + | | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` +... | +LL | | while let true = let true = true {} +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `()` = note: required by `std::ops::Try::from_error` @@ -924,8 +942,17 @@ LL | (let 0 = 0)?; error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/disallowed-positions.rs:183:5 | -LL | (let 0 = 0)?; - | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` +LL | / fn outside_if_and_while_expr() { +LL | | &let 0 = 0; +LL | | +LL | | !let 0 = 0; +... | +LL | | (let 0 = 0)?; + | | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` +... | +LL | | +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `()` = note: required by `std::ops::Try::from_error` diff --git a/src/test/ui/sanitize-cfg.rs b/src/test/ui/sanitize-cfg.rs new file mode 100644 index 00000000000..9c198543a86 --- /dev/null +++ b/src/test/ui/sanitize-cfg.rs @@ -0,0 +1,26 @@ +// Verifies that when compiling with -Zsanitizer=option, +// the `#[cfg(sanitize = "option")]` attribute is configured. + +// needs-sanitizer-support +// only-linux +// only-x86_64 +// check-pass +// revisions: address leak memory thread +//[address]compile-flags: -Zsanitizer=address --cfg address +//[leak]compile-flags: -Zsanitizer=leak --cfg leak +//[memory]compile-flags: -Zsanitizer=memory --cfg memory +//[thread]compile-flags: -Zsanitizer=thread --cfg thread + +#![feature(cfg_sanitize)] + +#[cfg(all(sanitize = "address", address))] +fn main() {} + +#[cfg(all(sanitize = "leak", leak))] +fn main() {} + +#[cfg(all(sanitize = "memory", memory))] +fn main() {} + +#[cfg(all(sanitize = "thread", thread))] +fn main() {} diff --git a/src/test/ui/try-on-option-diagnostics.stderr b/src/test/ui/try-on-option-diagnostics.stderr index 4dd515e1b5a..ce3aca39fb8 100644 --- a/src/test/ui/try-on-option-diagnostics.stderr +++ b/src/test/ui/try-on-option-diagnostics.stderr @@ -1,8 +1,13 @@ error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-on-option-diagnostics.rs:7:5 | -LL | x?; - | ^^ cannot use the `?` operator in a function that returns `u32` +LL | / fn a_function() -> u32 { +LL | | let x: Option = None; +LL | | x?; + | | ^^ cannot use the `?` operator in a function that returns `u32` +LL | | 22 +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `u32` = note: required by `std::ops::Try::from_error` @@ -10,8 +15,14 @@ LL | x?; error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-on-option-diagnostics.rs:14:9 | -LL | x?; - | ^^ cannot use the `?` operator in a closure that returns `{integer}` +LL | let a_closure = || { + | _____________________- +LL | | let x: Option = None; +LL | | x?; + | | ^^ cannot use the `?` operator in a closure that returns `{integer}` +LL | | 22 +LL | | }; + | |_____- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `{integer}` = note: required by `std::ops::Try::from_error` diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr index db5046f8c15..07615b52a48 100644 --- a/src/test/ui/try-on-option.stderr +++ b/src/test/ui/try-on-option.stderr @@ -10,8 +10,13 @@ LL | x?; error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-on-option.rs:13:5 | -LL | x?; - | ^^ cannot use the `?` operator in a function that returns `u32` +LL | / fn bar() -> u32 { +LL | | let x: Option = None; +LL | | x?; + | | ^^ cannot use the `?` operator in a function that returns `u32` +LL | | 22 +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `u32` = note: required by `std::ops::Try::from_error` diff --git a/src/test/ui/try-operator-on-main.stderr b/src/test/ui/try-operator-on-main.stderr index d2f1a04837b..d8ba264583e 100644 --- a/src/test/ui/try-operator-on-main.stderr +++ b/src/test/ui/try-operator-on-main.stderr @@ -1,8 +1,15 @@ error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-operator-on-main.rs:9:5 | -LL | std::fs::File::open("foo")?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` +LL | / fn main() { +LL | | // error for a `Try` type on a non-`Try` fn +LL | | std::fs::File::open("foo")?; + | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` +LL | | +... | +LL | | try_trait_generic::<()>(); +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `()` = note: required by `std::ops::Try::from_error`