From faf5eac854f9099b54854145f2307cae3f3aa768 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 26 Apr 2019 17:22:36 +1000 Subject: [PATCH 01/11] Move metadata encoding earlier. This commit separates metadata encoding (`tcx.encode_metadata`) from the creation of the metadata module (which is now handled by `write_compressed_metadata`, formerly `write_metadata`). The metadata encoding now occurs slightly earlier in the pipeline, at the very start of code generation within `start_codegen`. Metadata *writing* still occurs near the end of compilation; that will be moved forward in subsequent commits. --- src/librustc_codegen_llvm/base.rs | 40 ++-------------- src/librustc_codegen_llvm/lib.rs | 14 ++++-- src/librustc_codegen_ssa/base.rs | 48 ++++++++----------- src/librustc_codegen_ssa/traits/backend.rs | 7 +-- src/librustc_codegen_utils/codegen_backend.rs | 4 +- src/librustc_interface/passes.rs | 44 +++++++++++++++-- .../hotplug_codegen_backend/the_backend.rs | 4 +- 7 files changed, 85 insertions(+), 76 deletions(-) diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 7ea5e91230905..9077e89a4020e 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -28,7 +28,7 @@ use rustc::mir::mono::{Linkage, Visibility, Stats}; use rustc::middle::cstore::{EncodedMetadata}; use rustc::ty::TyCtxt; use rustc::middle::exported_symbols; -use rustc::session::config::{self, DebugInfo}; +use rustc::session::config::DebugInfo; use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_data_structures::small_c_str::SmallCStr; @@ -42,47 +42,16 @@ use rustc::hir::CodegenFnAttrs; use crate::value::Value; - -pub fn write_metadata<'a, 'gcx>( +pub fn write_compressed_metadata<'a, 'gcx>( tcx: TyCtxt<'a, 'gcx, 'gcx>, + metadata: &EncodedMetadata, llvm_module: &mut ModuleLlvm -) -> EncodedMetadata { +) { use std::io::Write; use flate2::Compression; use flate2::write::DeflateEncoder; let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod()); - - #[derive(PartialEq, Eq, PartialOrd, Ord)] - enum MetadataKind { - None, - Uncompressed, - Compressed - } - - let kind = tcx.sess.crate_types.borrow().iter().map(|ty| { - match *ty { - config::CrateType::Executable | - config::CrateType::Staticlib | - config::CrateType::Cdylib => MetadataKind::None, - - config::CrateType::Rlib => MetadataKind::Uncompressed, - - config::CrateType::Dylib | - config::CrateType::ProcMacro => MetadataKind::Compressed, - } - }).max().unwrap_or(MetadataKind::None); - - if kind == MetadataKind::None { - return EncodedMetadata::new(); - } - - let metadata = tcx.encode_metadata(); - if kind == MetadataKind::Uncompressed { - return metadata; - } - - assert!(kind == MetadataKind::Compressed); let mut compressed = tcx.metadata_encoding_version(); DeflateEncoder::new(&mut compressed, Compression::fast()) .write_all(&metadata.raw_data).unwrap(); @@ -107,7 +76,6 @@ pub fn write_metadata<'a, 'gcx>( let directive = CString::new(directive).unwrap(); llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr()) } - return metadata; } pub struct ValueIter<'ll> { diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 08424e7c3229a..09b284052b3c4 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -110,12 +110,13 @@ impl ExtraBackendMethods for LlvmCodegenBackend { ModuleLlvm::new_metadata(tcx, mod_name) } - fn write_metadata<'b, 'gcx>( + fn write_compressed_metadata<'b, 'gcx>( &self, tcx: TyCtxt<'b, 'gcx, 'gcx>, - metadata: &mut ModuleLlvm - ) -> EncodedMetadata { - base::write_metadata(tcx, metadata) + metadata: &EncodedMetadata, + llvm_module: &mut ModuleLlvm + ) { + base::write_compressed_metadata(tcx, metadata, llvm_module) } fn codegen_allocator<'b, 'gcx>( &self, @@ -289,9 +290,12 @@ impl CodegenBackend for LlvmCodegenBackend { fn codegen_crate<'b, 'tcx>( &self, tcx: TyCtxt<'b, 'tcx, 'tcx>, + metadata: EncodedMetadata, + need_metadata_module: bool, rx: mpsc::Receiver> ) -> Box { - box rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx, rx) + box rustc_codegen_ssa::base::codegen_crate( + LlvmCodegenBackend(()), tcx, metadata, need_metadata_module, rx) } fn join_codegen_and_link( diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 3046c069981cb..3cd47dfbb29fb 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -17,6 +17,7 @@ use crate::{ModuleCodegen, ModuleKind, CachedModuleCodegen}; use rustc::dep_graph::cgu_reuse_tracker::CguReuse; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::middle::cstore::EncodedMetadata; use rustc::middle::lang_items::StartFnLangItem; use rustc::middle::weak_lang_items; use rustc::mir::mono::{Stats, CodegenUnitNameBuilder}; @@ -25,7 +26,7 @@ use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt}; use rustc::ty::query::Providers; use rustc::middle::cstore::{self, LinkagePreference}; use rustc::util::common::{time, print_time_passes_entry}; -use rustc::session::config::{self, CrateType, EntryFnType, Lto}; +use rustc::session::config::{self, EntryFnType, Lto}; use rustc::session::Session; use rustc_mir::monomorphize::item::DefPathBasedNames; use rustc_mir::monomorphize::Instance; @@ -530,26 +531,13 @@ pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX; pub fn codegen_crate( backend: B, tcx: TyCtxt<'a, 'tcx, 'tcx>, + metadata: EncodedMetadata, + need_metadata_module: bool, rx: mpsc::Receiver> ) -> OngoingCodegen { check_for_rustc_errors_attr(tcx); - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); - - // Codegen the metadata. - tcx.sess.profiler(|p| p.start_activity("codegen crate metadata")); - - let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE, - &["crate"], - Some("metadata")).as_str() - .to_string(); - let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name); - let metadata = time(tcx.sess, "write metadata", || { - backend.write_metadata(tcx, &mut metadata_llvm_module) - }); - tcx.sess.profiler(|p| p.end_activity("codegen crate metadata")); - // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.debugging_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { @@ -569,6 +557,8 @@ pub fn codegen_crate( return ongoing_codegen; } + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + // Run the monomorphization collector and partition the collected items into // codegen units. let codegen_units = tcx.collect_and_partition_mono_items(LOCAL_CRATE).1; @@ -632,17 +622,21 @@ pub fn codegen_crate( ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module); } - let needs_metadata_module = tcx.sess.crate_types.borrow().iter().any(|ct| { - match *ct { - CrateType::Dylib | - CrateType::ProcMacro => true, - CrateType::Executable | - CrateType::Rlib | - CrateType::Staticlib | - CrateType::Cdylib => false, - } - }); - if needs_metadata_module { + if need_metadata_module { + // Codegen the encoded metadata. + tcx.sess.profiler(|p| p.start_activity("codegen crate metadata")); + + let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE, + &["crate"], + Some("metadata")).as_str() + .to_string(); + let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name); + time(tcx.sess, "write compressed metadata", || { + backend.write_compressed_metadata(tcx, &ongoing_codegen.metadata, + &mut metadata_llvm_module); + }); + tcx.sess.profiler(|p| p.end_activity("codegen crate metadata")); + let metadata_module = ModuleCodegen { name: metadata_cgu_name, module_llvm: metadata_llvm_module, diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs index a9e0eadb198a8..530eba516a6c0 100644 --- a/src/librustc_codegen_ssa/traits/backend.rs +++ b/src/librustc_codegen_ssa/traits/backend.rs @@ -33,11 +33,12 @@ impl<'tcx, T> Backend<'tcx> for T where pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send { fn new_metadata(&self, sess: TyCtxt<'_, '_, '_>, mod_name: &str) -> Self::Module; - fn write_metadata<'b, 'gcx>( + fn write_compressed_metadata<'b, 'gcx>( &self, tcx: TyCtxt<'b, 'gcx, 'gcx>, - metadata: &mut Self::Module, - ) -> EncodedMetadata; + metadata: &EncodedMetadata, + llvm_module: &mut Self::Module, + ); fn codegen_allocator<'b, 'gcx>( &self, tcx: TyCtxt<'b, 'gcx, 'gcx>, diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs index 56eaffb1ca31d..191c6605b43ff 100644 --- a/src/librustc_codegen_utils/codegen_backend.rs +++ b/src/librustc_codegen_utils/codegen_backend.rs @@ -18,7 +18,7 @@ use rustc::util::common::ErrorReported; use rustc::session::config::{OutputFilenames, PrintRequest}; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; -use rustc::middle::cstore::MetadataLoader; +use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; use rustc::dep_graph::DepGraph; pub use rustc_data_structures::sync::MetadataRef; @@ -37,6 +37,8 @@ pub trait CodegenBackend { fn codegen_crate<'a, 'tcx>( &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + metadata: EncodedMetadata, + need_metadata_module: bool, rx: mpsc::Receiver> ) -> Box; diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index f8b1271b8b5c6..38d641d2f6076 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -16,7 +16,7 @@ use rustc::traits; use rustc::util::common::{time, ErrorReported}; use rustc::util::profiling::ProfileCategory; use rustc::session::{CompileResult, CrateDisambiguator, Session}; -use rustc::session::config::{self, Input, OutputFilenames, OutputType}; +use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc_allocator as allocator; use rustc_borrowck as borrowck; @@ -999,6 +999,38 @@ fn analysis<'tcx>( Ok(()) } +fn encode_metadata<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> (middle::cstore::EncodedMetadata, bool) { + #[derive(PartialEq, Eq, PartialOrd, Ord)] + enum MetadataKind { + None, + Uncompressed, + Compressed + } + + let metadata_kind = tcx.sess.crate_types.borrow().iter().map(|ty| { + match *ty { + CrateType::Executable | + CrateType::Staticlib | + CrateType::Cdylib => MetadataKind::None, + + CrateType::Rlib => MetadataKind::Uncompressed, + + CrateType::Dylib | + CrateType::ProcMacro => MetadataKind::Compressed, + } + }).max().unwrap_or(MetadataKind::None); + + let need_metadata_module = metadata_kind == MetadataKind::Compressed; + + let metadata = match metadata_kind { + MetadataKind::None => middle::cstore::EncodedMetadata::new(), + MetadataKind::Uncompressed | + MetadataKind::Compressed => tcx.encode_metadata(), + }; + + (metadata, need_metadata_module) +} + /// Runs the codegen backend, after which the AST and analysis can /// be discarded. pub fn start_codegen<'tcx>( @@ -1013,11 +1045,17 @@ pub fn start_codegen<'tcx>( } time(tcx.sess, "resolving dependency formats", || { - ::rustc::middle::dependency_format::calculate(tcx) + middle::dependency_format::calculate(tcx) + }); + + let (metadata, need_metadata_module) = time(tcx.sess, "metadata encoding", || { + encode_metadata(tcx) }); tcx.sess.profiler(|p| p.start_activity("codegen crate")); - let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx)); + let codegen = time(tcx.sess, "codegen", move || { + codegen_backend.codegen_crate(tcx, metadata, need_metadata_module, rx) + }); tcx.sess.profiler(|p| p.end_activity("codegen crate")); if log_enabled!(::log::Level::Info) { diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index 5330470da16b0..4e43aa96e1d85 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -15,7 +15,7 @@ use rustc::session::Session; use rustc::session::config::OutputFilenames; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; -use rustc::middle::cstore::MetadataLoader; +use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; use rustc::dep_graph::DepGraph; use rustc::util::common::ErrorReported; use rustc_codegen_utils::codegen_backend::CodegenBackend; @@ -61,6 +61,8 @@ impl CodegenBackend for TheBackend { fn codegen_crate<'a, 'tcx>( &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + _metadata: EncodedMetadata, + _need_metadata_module: bool, _rx: mpsc::Receiver> ) -> Box { use rustc::hir::def_id::LOCAL_CRATE; From 3da5d4a87e4fd3a96cf7e962211c875fe50650d4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Apr 2019 15:52:16 +1000 Subject: [PATCH 02/11] Inline and remove `link_binary_output`. This change simplifies things for the subsequent commit. --- src/librustc_codegen_ssa/back/link.rs | 135 ++++++++++++-------------- 1 file changed, 61 insertions(+), 74 deletions(-) diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 4cae20b698a1c..f80618441054a 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -63,12 +63,66 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, bug!("invalid output type `{:?}` for target os `{}`", crate_type, sess.opts.target_triple); } - link_binary_output::(sess, - codegen_results, - crate_type, - outputs, - crate_name, - target_cpu); + + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { + check_file_is_writeable(obj, sess); + } + + if outputs.outputs.contains_key(&OutputType::Metadata) { + let out_filename = filename_for_metadata(sess, crate_name, outputs); + // To avoid races with another rustc process scanning the output directory, + // we need to write the file somewhere else and atomically move it to its + // final destination, with a `fs::rename` call. In order for the rename to + // always succeed, the temporary file needs to be on the same filesystem, + // which is why we create it inside the output directory specifically. + let metadata_tmpdir = TempFileBuilder::new() + .prefix("rmeta") + .tempdir_in(out_filename.parent().unwrap()) + .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err))); + let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir); + match fs::rename(&metadata, &out_filename) { + Ok(_) => { + if sess.opts.debugging_opts.emit_directives { + sess.parse_sess.span_diagnostic.maybe_emit_json_directive( + format!("metadata file written: {}", out_filename.display())); + } + } + Err(e) => sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)), + } + } + + let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err| + sess.fatal(&format!("couldn't create a temp dir: {}", err))); + + if outputs.outputs.should_codegen() { + let out_filename = out_filename(sess, crate_type, outputs, crate_name); + match crate_type { + config::CrateType::Rlib => { + link_rlib::(sess, + codegen_results, + RlibFlavor::Normal, + &out_filename, + &tmpdir).build(); + } + config::CrateType::Staticlib => { + link_staticlib::(sess, codegen_results, &out_filename, &tmpdir); + } + _ => { + link_natively::( + sess, + crate_type, + &out_filename, + codegen_results, + tmpdir.path(), + target_cpu, + ); + } + } + } + + if sess.opts.cg.save_temps { + let _ = tmpdir.into_path(); + } } // Remove the temporary object file and metadata if we aren't saving temps @@ -85,7 +139,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, if let Some(ref obj) = metadata_module.object { remove(sess, obj); } - } + } if let Some(ref allocator_module) = codegen_results.allocator_module { if let Some(ref obj) = allocator_module.object { remove(sess, obj); @@ -97,73 +151,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, } } -fn link_binary_output<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, - codegen_results: &CodegenResults, - crate_type: config::CrateType, - outputs: &OutputFilenames, - crate_name: &str, - target_cpu: &str) { - for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { - check_file_is_writeable(obj, sess); - } - - if outputs.outputs.contains_key(&OutputType::Metadata) { - let out_filename = filename_for_metadata(sess, crate_name, outputs); - // To avoid races with another rustc process scanning the output directory, - // we need to write the file somewhere else and atomically move it to its - // final destination, with a `fs::rename` call. In order for the rename to - // always succeed, the temporary file needs to be on the same filesystem, - // which is why we create it inside the output directory specifically. - let metadata_tmpdir = TempFileBuilder::new() - .prefix("rmeta") - .tempdir_in(out_filename.parent().unwrap()) - .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err))); - let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir); - match fs::rename(&metadata, &out_filename) { - Ok(_) => { - if sess.opts.debugging_opts.emit_directives { - sess.parse_sess.span_diagnostic.maybe_emit_json_directive( - format!("metadata file written: {}", out_filename.display())); - } - } - Err(e) => sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)), - } - } - - let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err| - sess.fatal(&format!("couldn't create a temp dir: {}", err))); - - if outputs.outputs.should_codegen() { - let out_filename = out_filename(sess, crate_type, outputs, crate_name); - match crate_type { - config::CrateType::Rlib => { - link_rlib::(sess, - codegen_results, - RlibFlavor::Normal, - &out_filename, - &tmpdir).build(); - } - config::CrateType::Staticlib => { - link_staticlib::(sess, codegen_results, &out_filename, &tmpdir); - } - _ => { - link_natively::( - sess, - crate_type, - &out_filename, - codegen_results, - tmpdir.path(), - target_cpu, - ); - } - } - } - - if sess.opts.cg.save_temps { - let _ = tmpdir.into_path(); - } -} - // The third parameter is for env vars, used on windows to set up the // path for MSVC to find its DLLs, and gcc to find its bundled // toolchain From 38dffeba21842adc9deb647b30f3a4a00abca133 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Apr 2019 15:53:30 +1000 Subject: [PATCH 03/11] Move metadata writing earlier. The commit moves metadata writing from `link_binary` to `encode_metadata` (and renames the latter as `encode_and_write_metadata`). This is at the very start of code generation. --- Cargo.lock | 2 ++ src/librustc_codegen_ssa/back/link.rs | 35 ++++------------------ src/librustc_interface/Cargo.toml | 2 ++ src/librustc_interface/passes.rs | 43 +++++++++++++++++++++++---- 4 files changed, 48 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aeddf35eb0dd9..a7b8447ef356a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2802,6 +2802,7 @@ dependencies = [ "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_borrowck 0.0.0", + "rustc_codegen_ssa 0.0.0", "rustc_codegen_utils 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -2821,6 +2822,7 @@ dependencies = [ "syntax 0.0.0", "syntax_ext 0.0.0", "syntax_pos 0.0.0", + "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index f80618441054a..f25891d77ce53 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -7,7 +7,7 @@ use rustc::session::config::{ }; use rustc::session::search_paths::PathKind; use rustc::middle::dependency_format::Linkage; -use rustc::middle::cstore::{LibSource, NativeLibrary, NativeLibraryKind}; +use rustc::middle::cstore::{EncodedMetadata, LibSource, NativeLibrary, NativeLibraryKind}; use rustc::util::common::{time, time_ext}; use rustc::hir::def_id::CrateNum; use rustc_data_structures::fx::FxHashSet; @@ -50,9 +50,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, outputs: &OutputFilenames, crate_name: &str, target_cpu: &str) { + let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); for &crate_type in sess.crate_types.borrow().iter() { // Ignore executable crates if we have -Z no-codegen, as they will error. - let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) && !output_metadata && crate_type == config::CrateType::Executable { @@ -68,29 +68,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, check_file_is_writeable(obj, sess); } - if outputs.outputs.contains_key(&OutputType::Metadata) { - let out_filename = filename_for_metadata(sess, crate_name, outputs); - // To avoid races with another rustc process scanning the output directory, - // we need to write the file somewhere else and atomically move it to its - // final destination, with a `fs::rename` call. In order for the rename to - // always succeed, the temporary file needs to be on the same filesystem, - // which is why we create it inside the output directory specifically. - let metadata_tmpdir = TempFileBuilder::new() - .prefix("rmeta") - .tempdir_in(out_filename.parent().unwrap()) - .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err))); - let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir); - match fs::rename(&metadata, &out_filename) { - Ok(_) => { - if sess.opts.debugging_opts.emit_directives { - sess.parse_sess.span_diagnostic.maybe_emit_json_directive( - format!("metadata file written: {}", out_filename.display())); - } - } - Err(e) => sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)), - } - } - let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err))); @@ -248,13 +225,13 @@ pub fn each_linked_rlib(sess: &Session, /// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a /// directory being searched for `extern crate` (observing an incomplete file). /// The returned path is the temporary file containing the complete metadata. -fn emit_metadata<'a>( +pub fn emit_metadata<'a>( sess: &'a Session, - codegen_results: &CodegenResults, + metadata: &EncodedMetadata, tmpdir: &TempDir ) -> PathBuf { let out_filename = tmpdir.path().join(METADATA_FILENAME); - let result = fs::write(&out_filename, &codegen_results.metadata.raw_data); + let result = fs::write(&out_filename, &metadata.raw_data); if let Err(e) = result { sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); @@ -338,7 +315,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, RlibFlavor::Normal => { // Instead of putting the metadata in an object file section, rlibs // contain the metadata in a separate file. - ab.add_file(&emit_metadata(sess, codegen_results, tmpdir)); + ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir)); // For LTO purposes, the bytecode of this library is also inserted // into the archive. diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index fa2a5d2fc89bc..bcaa4216109aa 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -24,6 +24,7 @@ rustc_borrowck = { path = "../librustc_borrowck" } rustc_incremental = { path = "../librustc_incremental" } rustc_traits = { path = "../librustc_traits" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } @@ -34,3 +35,4 @@ rustc_errors = { path = "../librustc_errors" } rustc_plugin = { path = "../librustc_plugin" } rustc_privacy = { path = "../librustc_privacy" } rustc_resolve = { path = "../librustc_resolve" } +tempfile = "3.0.5" diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 38d641d2f6076..6d3115c621343 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -20,7 +20,9 @@ use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType use rustc::session::search_paths::PathKind; use rustc_allocator as allocator; use rustc_borrowck as borrowck; +use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_codegen_utils::link::filename_for_metadata; use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::StableHasher; @@ -50,6 +52,7 @@ use syntax_pos::{FileName, hygiene}; use syntax_ext; use serialize::json; +use tempfile::Builder as TempFileBuilder; use std::any::Any; use std::env; @@ -999,7 +1002,10 @@ fn analysis<'tcx>( Ok(()) } -fn encode_metadata<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> (middle::cstore::EncodedMetadata, bool) { +fn encode_and_write_metadata<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + outputs: &OutputFilenames, +) -> (middle::cstore::EncodedMetadata, bool) { #[derive(PartialEq, Eq, PartialOrd, Ord)] enum MetadataKind { None, @@ -1020,14 +1026,41 @@ fn encode_metadata<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> (middle::cstore::Encode } }).max().unwrap_or(MetadataKind::None); - let need_metadata_module = metadata_kind == MetadataKind::Compressed; - let metadata = match metadata_kind { MetadataKind::None => middle::cstore::EncodedMetadata::new(), MetadataKind::Uncompressed | MetadataKind::Compressed => tcx.encode_metadata(), }; + let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata); + if need_metadata_file { + let crate_name = &tcx.crate_name(LOCAL_CRATE).as_str(); + let out_filename = filename_for_metadata(tcx.sess, crate_name, outputs); + // To avoid races with another rustc process scanning the output directory, + // we need to write the file somewhere else and atomically move it to its + // final destination, with an `fs::rename` call. In order for the rename to + // always succeed, the temporary file needs to be on the same filesystem, + // which is why we create it inside the output directory specifically. + let metadata_tmpdir = TempFileBuilder::new() + .prefix("rmeta") + .tempdir_in(out_filename.parent().unwrap()) + .unwrap_or_else(|err| { + tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)) + }); + let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir); + match std::fs::rename(&metadata_filename, &out_filename) { + Ok(_) => { + if tcx.sess.opts.debugging_opts.emit_directives { + tcx.sess.parse_sess.span_diagnostic.maybe_emit_json_directive( + format!("metadata file written: {}", out_filename.display())); + } + } + Err(e) => tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)), + } + } + + let need_metadata_module = metadata_kind == MetadataKind::Compressed; + (metadata, need_metadata_module) } @@ -1048,8 +1081,8 @@ pub fn start_codegen<'tcx>( middle::dependency_format::calculate(tcx) }); - let (metadata, need_metadata_module) = time(tcx.sess, "metadata encoding", || { - encode_metadata(tcx) + let (metadata, need_metadata_module) = time(tcx.sess, "metadata encoding and writing", || { + encode_and_write_metadata(tcx, outputs) }); tcx.sess.profiler(|p| p.start_activity("codegen crate")); From 2be37ad42197f202dfb87c073cb0c6b5e9e5b2ec Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 20 Apr 2019 17:59:47 +0200 Subject: [PATCH 04/11] Added the E0704 error with a link to the Rust reference. --- src/libsyntax/error_codes.rs | 30 ++++++++++++++++++++++++++- src/test/ui/pub/pub-restricted.stderr | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/error_codes.rs b/src/libsyntax/error_codes.rs index ac24475cab89f..e2d212eb721ff 100644 --- a/src/libsyntax/error_codes.rs +++ b/src/libsyntax/error_codes.rs @@ -363,6 +363,35 @@ and likely to change in the future. "##, +E0704: r##" +This error indicates that a incorrect visibility restriction was specified. + +Example of erroneous code: + +```compile_fail,E0704 +mod foo { + pub(foo) struct Bar { + x: i32 + } +} +``` + +To make struct `Bar` only visible in module `foo` the `in` keyword should be +used: +``` +mod foo { + pub(in crate::foo) struct Bar { + x: i32 + } +} +# fn main() {} +``` + +For more information see the Rust Reference on [Visibility]. + +[Visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html +"##, + E0705: r##" A `#![feature]` attribute was declared for a feature that is stable in the current edition, but not in all editions. @@ -417,6 +446,5 @@ register_diagnostics! { E0693, // incorrect `repr(align)` attribute format E0694, // an unknown tool name found in scoped attributes E0703, // invalid ABI - E0704, // incorrect visibility restriction E0717, // rustc_promotable without stability attribute } diff --git a/src/test/ui/pub/pub-restricted.stderr b/src/test/ui/pub/pub-restricted.stderr index 044e5fc5188e6..7eeefa9550543 100644 --- a/src/test/ui/pub/pub-restricted.stderr +++ b/src/test/ui/pub/pub-restricted.stderr @@ -50,3 +50,4 @@ LL | pub (in x) non_parent_invalid: usize, error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0704`. From d3fff6cda7e56488566b6b82c494e6075d2d9988 Mon Sep 17 00:00:00 2001 From: Andrew Xu Date: Sun, 28 Apr 2019 13:28:07 +0800 Subject: [PATCH 05/11] move some functions from parser.rs to diagostics.rs parser.rs is too big. Some functions only for error reporting and error recovery are being moved to diagostics.rs. --- src/libsyntax/parse/diagnostics.rs | 226 +++++++++++++++++++++++++++++ src/libsyntax/parse/mod.rs | 1 + src/libsyntax/parse/parser.rs | 166 +-------------------- 3 files changed, 231 insertions(+), 162 deletions(-) create mode 100644 src/libsyntax/parse/diagnostics.rs diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs new file mode 100644 index 0000000000000..32e1ee94f0dfb --- /dev/null +++ b/src/libsyntax/parse/diagnostics.rs @@ -0,0 +1,226 @@ +use crate::ast; +use crate::ast::{Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind}; +use crate::parse::parser::PathStyle; +use crate::parse::token; +use crate::parse::PResult; +use crate::parse::Parser; +use crate::print::pprust; +use crate::ptr::P; +use crate::ThinVec; +use errors::Applicability; +use syntax_pos::Span; + +pub trait RecoverQPath: Sized + 'static { + const PATH_STYLE: PathStyle = PathStyle::Expr; + fn to_ty(&self) -> Option>; + fn recovered(qself: Option, path: ast::Path) -> Self; +} + +impl RecoverQPath for Ty { + const PATH_STYLE: PathStyle = PathStyle::Type; + fn to_ty(&self) -> Option> { + Some(P(self.clone())) + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + node: TyKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + } + } +} + +impl RecoverQPath for Pat { + fn to_ty(&self) -> Option> { + self.to_ty() + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + node: PatKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + } + } +} + +impl RecoverQPath for Expr { + fn to_ty(&self) -> Option> { + self.to_ty() + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + node: ExprKind::Path(qself, path), + attrs: ThinVec::new(), + id: ast::DUMMY_NODE_ID, + } + } +} + +impl<'a> Parser<'a> { + crate fn maybe_report_ambiguous_plus( + &mut self, + allow_plus: bool, + impl_dyn_multi: bool, + ty: &Ty, + ) { + if !allow_plus && impl_dyn_multi { + let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); + self.struct_span_err(ty.span, "ambiguous `+` in a type") + .span_suggestion( + ty.span, + "use parentheses to disambiguate", + sum_with_parens, + Applicability::MachineApplicable, + ) + .emit(); + } + } + + crate fn maybe_recover_from_bad_type_plus( + &mut self, + allow_plus: bool, + ty: &Ty, + ) -> PResult<'a, ()> { + // Do not add `+` to expected tokens. + if !allow_plus || !self.token.is_like_plus() { + return Ok(()); + } + + self.bump(); // `+` + let bounds = self.parse_generic_bounds(None)?; + let sum_span = ty.span.to(self.prev_span); + + let mut err = struct_span_err!( + self.sess.span_diagnostic, + sum_span, + E0178, + "expected a path on the left-hand side of `+`, not `{}`", + pprust::ty_to_string(ty) + ); + + match ty.node { + TyKind::Rptr(ref lifetime, ref mut_ty) => { + let sum_with_parens = pprust::to_string(|s| { + use crate::print::pprust::PrintState; + + s.s.word("&")?; + s.print_opt_lifetime(lifetime)?; + s.print_mutability(mut_ty.mutbl)?; + s.popen()?; + s.print_type(&mut_ty.ty)?; + s.print_type_bounds(" +", &bounds)?; + s.pclose() + }); + err.span_suggestion( + sum_span, + "try adding parentheses", + sum_with_parens, + Applicability::MachineApplicable, + ); + } + TyKind::Ptr(..) | TyKind::BareFn(..) => { + err.span_label(sum_span, "perhaps you forgot parentheses?"); + } + _ => { + err.span_label(sum_span, "expected a path"); + } + } + err.emit(); + Ok(()) + } + + /// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`. + /// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem` + /// tail, and combine them into a `::AssocItem` expression/pattern/type. + crate fn maybe_recover_from_bad_qpath( + &mut self, + base: P, + allow_recovery: bool, + ) -> PResult<'a, P> { + // Do not add `::` to expected tokens. + if allow_recovery && self.token == token::ModSep { + if let Some(ty) = base.to_ty() { + return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty); + } + } + Ok(base) + } + + /// Given an already parsed `Ty` parse the `::AssocItem` tail and + /// combine them into a `::AssocItem` expression/pattern/type. + crate fn maybe_recover_from_bad_qpath_stage_2( + &mut self, + ty_span: Span, + ty: P, + ) -> PResult<'a, P> { + self.expect(&token::ModSep)?; + + let mut path = ast::Path { + segments: Vec::new(), + span: syntax_pos::DUMMY_SP, + }; + self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; + path.span = ty_span.to(self.prev_span); + + let ty_str = self + .sess + .source_map() + .span_to_snippet(ty_span) + .unwrap_or_else(|_| pprust::ty_to_string(&ty)); + self.diagnostic() + .struct_span_err(path.span, "missing angle brackets in associated item path") + .span_suggestion( + // this is a best-effort recovery + path.span, + "try", + format!("<{}>::{}", ty_str, path), + Applicability::MaybeIncorrect, + ) + .emit(); + + let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0 + Ok(P(T::recovered( + Some(QSelf { + ty, + path_span, + position: 0, + }), + path, + ))) + } + + crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P]) -> bool { + if self.eat(&token::Semi) { + let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`"); + err.span_suggestion_short( + self.prev_span, + "remove this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + if !items.is_empty() { + let previous_item = &items[items.len() - 1]; + let previous_item_kind_name = match previous_item.node { + // say "braced struct" because tuple-structs and + // braceless-empty-struct declarations do take a semicolon + ItemKind::Struct(..) => Some("braced struct"), + ItemKind::Enum(..) => Some("enum"), + ItemKind::Trait(..) => Some("trait"), + ItemKind::Union(..) => Some("union"), + _ => None, + }; + if let Some(name) = previous_item_kind_name { + err.help(&format!( + "{} declarations are not followed by a semicolon", + name + )); + } + } + err.emit(); + true + } else { + false + } + } +} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 371e8fe5cf66f..608d00f5548f7 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -30,6 +30,7 @@ pub mod parser; pub mod lexer; pub mod token; pub mod attr; +pub mod diagnostics; pub mod classify; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8efe84cdf016f..6c64055ded1b1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -189,41 +189,6 @@ enum PrevTokenKind { Other, } -trait RecoverQPath: Sized + 'static { - const PATH_STYLE: PathStyle = PathStyle::Expr; - fn to_ty(&self) -> Option>; - fn recovered(qself: Option, path: ast::Path) -> Self; -} - -impl RecoverQPath for Ty { - const PATH_STYLE: PathStyle = PathStyle::Type; - fn to_ty(&self) -> Option> { - Some(P(self.clone())) - } - fn recovered(qself: Option, path: ast::Path) -> Self { - Self { span: path.span, node: TyKind::Path(qself, path), id: ast::DUMMY_NODE_ID } - } -} - -impl RecoverQPath for Pat { - fn to_ty(&self) -> Option> { - self.to_ty() - } - fn recovered(qself: Option, path: ast::Path) -> Self { - Self { span: path.span, node: PatKind::Path(qself, path), id: ast::DUMMY_NODE_ID } - } -} - -impl RecoverQPath for Expr { - fn to_ty(&self) -> Option> { - self.to_ty() - } - fn recovered(qself: Option, path: ast::Path) -> Self { - Self { span: path.span, node: ExprKind::Path(qself, path), - attrs: ThinVec::new(), id: ast::DUMMY_NODE_ID } - } -} - /* ident is handled by common.rs */ #[derive(Clone)] @@ -1479,7 +1444,7 @@ impl<'a> Parser<'a> { fn span_err>(&self, sp: S, m: &str) { self.sess.span_diagnostic.span_err(sp, m) } - fn struct_span_err>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + crate fn struct_span_err>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { self.sess.span_diagnostic.struct_span_err(sp, m) } fn struct_span_warn>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { @@ -1882,99 +1847,6 @@ impl<'a> Parser<'a> { Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } - fn maybe_report_ambiguous_plus(&mut self, allow_plus: bool, impl_dyn_multi: bool, ty: &Ty) { - if !allow_plus && impl_dyn_multi { - let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); - self.struct_span_err(ty.span, "ambiguous `+` in a type") - .span_suggestion( - ty.span, - "use parentheses to disambiguate", - sum_with_parens, - Applicability::MachineApplicable - ).emit(); - } - } - - fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { - // Do not add `+` to expected tokens. - if !allow_plus || !self.token.is_like_plus() { - return Ok(()) - } - - self.bump(); // `+` - let bounds = self.parse_generic_bounds(None)?; - let sum_span = ty.span.to(self.prev_span); - - let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178, - "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(ty)); - - match ty.node { - TyKind::Rptr(ref lifetime, ref mut_ty) => { - let sum_with_parens = pprust::to_string(|s| { - use crate::print::pprust::PrintState; - - s.s.word("&")?; - s.print_opt_lifetime(lifetime)?; - s.print_mutability(mut_ty.mutbl)?; - s.popen()?; - s.print_type(&mut_ty.ty)?; - s.print_type_bounds(" +", &bounds)?; - s.pclose() - }); - err.span_suggestion( - sum_span, - "try adding parentheses", - sum_with_parens, - Applicability::MachineApplicable - ); - } - TyKind::Ptr(..) | TyKind::BareFn(..) => { - err.span_label(sum_span, "perhaps you forgot parentheses?"); - } - _ => { - err.span_label(sum_span, "expected a path"); - }, - } - err.emit(); - Ok(()) - } - - /// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`. - /// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem` - /// tail, and combine them into a `::AssocItem` expression/pattern/type. - fn maybe_recover_from_bad_qpath(&mut self, base: P, allow_recovery: bool) - -> PResult<'a, P> { - // Do not add `::` to expected tokens. - if allow_recovery && self.token == token::ModSep { - if let Some(ty) = base.to_ty() { - return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty); - } - } - Ok(base) - } - - /// Given an already parsed `Ty` parse the `::AssocItem` tail and - /// combine them into a `::AssocItem` expression/pattern/type. - fn maybe_recover_from_bad_qpath_stage_2(&mut self, ty_span: Span, ty: P) - -> PResult<'a, P> { - self.expect(&token::ModSep)?; - - let mut path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP }; - self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; - path.span = ty_span.to(self.prev_span); - - let ty_str = self.sess.source_map().span_to_snippet(ty_span) - .unwrap_or_else(|_| pprust::ty_to_string(&ty)); - self.diagnostic() - .struct_span_err(path.span, "missing angle brackets in associated item path") - .span_suggestion( // this is a best-effort recovery - path.span, "try", format!("<{}>::{}", ty_str, path), Applicability::MaybeIncorrect - ).emit(); - - let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0 - Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path))) - } - fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; let mutbl = self.parse_mutability(); @@ -2410,7 +2282,7 @@ impl<'a> Parser<'a> { self.parse_path(style) } - fn parse_path_segments(&mut self, + crate fn parse_path_segments(&mut self, segments: &mut Vec, style: PathStyle) -> PResult<'a, ()> { @@ -5815,7 +5687,8 @@ impl<'a> Parser<'a> { return Ok(bounds); } - fn parse_generic_bounds(&mut self, colon_span: Option) -> PResult<'a, GenericBounds> { + crate fn parse_generic_bounds(&mut self, + colon_span: Option) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(true, colon_span) } @@ -7352,37 +7225,6 @@ impl<'a> Parser<'a> { } } - fn maybe_consume_incorrect_semicolon(&mut self, items: &[P]) -> bool { - if self.eat(&token::Semi) { - let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`"); - err.span_suggestion_short( - self.prev_span, - "remove this semicolon", - String::new(), - Applicability::MachineApplicable, - ); - if !items.is_empty() { - let previous_item = &items[items.len()-1]; - let previous_item_kind_name = match previous_item.node { - // say "braced struct" because tuple-structs and - // braceless-empty-struct declarations do take a semicolon - ItemKind::Struct(..) => Some("braced struct"), - ItemKind::Enum(..) => Some("enum"), - ItemKind::Trait(..) => Some("trait"), - ItemKind::Union(..) => Some("union"), - _ => None, - }; - if let Some(name) = previous_item_kind_name { - err.help(&format!("{} declarations are not followed by a semicolon", name)); - } - } - err.emit(); - true - } else { - false - } - } - /// Given a termination token, parses all of the items in a module. fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> { let mut items = vec![]; From eadf48e796cc6913d064b683a8d4708ce8d447cc Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Tue, 30 Apr 2019 18:30:08 -0400 Subject: [PATCH 06/11] Refactor `eval_body_using_ecx` so that it doesn't need to query for MIR --- src/librustc_mir/const_eval.rs | 41 +++++++++--------------- src/librustc_mir/transform/const_prop.rs | 3 +- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index b65f2ba2601e4..27b6c3a9d2118 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -59,7 +59,7 @@ pub(crate) fn eval_promoted<'a, 'mir, 'tcx>( ) -> EvalResult<'tcx, MPlaceTy<'tcx>> { let span = tcx.def_span(cid.instance.def_id()); let mut ecx = mk_eval_cx(tcx, span, param_env); - eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env) + eval_body_using_ecx(&mut ecx, cid, mir, param_env) } fn mplace_to_const<'tcx>( @@ -107,37 +107,15 @@ fn op_to_const<'tcx>( ty::Const { val, ty: op.layout.ty } } -fn eval_body_and_ecx<'a, 'mir, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cid: GlobalId<'tcx>, - mir: Option<&'mir mir::Mir<'tcx>>, - param_env: ty::ParamEnv<'tcx>, -) -> (EvalResult<'tcx, MPlaceTy<'tcx>>, CompileTimeEvalContext<'a, 'mir, 'tcx>) { - // we start out with the best span we have - // and try improving it down the road when more information is available - let span = tcx.def_span(cid.instance.def_id()); - let span = mir.map(|mir| mir.span).unwrap_or(span); - let mut ecx = InterpretCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new()); - let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env); - (r, ecx) -} - // Returns a pointer to where the result lives fn eval_body_using_ecx<'mir, 'tcx>( ecx: &mut CompileTimeEvalContext<'_, 'mir, 'tcx>, cid: GlobalId<'tcx>, - mir: Option<&'mir mir::Mir<'tcx>>, + mir: &'mir mir::Mir<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> EvalResult<'tcx, MPlaceTy<'tcx>> { debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env); let tcx = ecx.tcx.tcx; - let mut mir = match mir { - Some(mir) => mir, - None => ecx.load_mir(cid.instance.def)?, - }; - if let Some(index) = cid.promoted { - mir = &mir.promoted[index]; - } let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ret = ecx.allocate(layout, MemoryKind::Stack); @@ -618,8 +596,19 @@ pub fn const_eval_raw_provider<'a, 'tcx>( return Err(ErrorHandled::Reported); } - let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); - res.and_then(|place| { + let span = tcx.def_span(cid.instance.def_id()); + let mut ecx = InterpretCx::new(tcx.at(span), key.param_env, CompileTimeInterpreter::new()); + + let res = ecx.load_mir(cid.instance.def); + res.map(|mir| { + if let Some(index) = cid.promoted { + &mir.promoted[index] + } else { + mir + } + }).and_then( + |mir| eval_body_using_ecx(&mut ecx, cid, mir, key.param_env) + ).and_then(|place| { Ok(RawConst { alloc_id: place.to_ptr().expect("we allocated this ptr!").alloc_id, ty: place.layout.ty diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index b5bdc9e1c8c6e..eef3b6f7c54e6 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -301,7 +301,8 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { // cannot use `const_eval` here, because that would require having the MIR // for the current function available, but we're producing said MIR right now let res = self.use_ecx(source_info, |this| { - eval_promoted(this.tcx, cid, this.mir, this.param_env) + let mir = &this.mir.promoted[promoted]; + eval_promoted(this.tcx, cid, mir, this.param_env) })?; trace!("evaluated promoted {:?} to {:?}", promoted, res); Some((res.into(), source_info.span)) From b05d5db87bd9a3f31729a5c48dc5dd5bec6dbd2d Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 1 May 2019 13:35:34 +0100 Subject: [PATCH 07/11] Ensure that drop order of `async fn` matches `fn`. This commit modifies the lowering of `async fn` arguments so that the drop order matches the equivalent `fn`. Previously, async function arguments were lowered as shown below: async fn foo(: ) { async move { } } // <-- dropped as you "exit" the fn // ...becomes... fn foo(__arg0: ) { async move { let = __arg0; } // <-- dropped as you "exit" the async block } After this PR, async function arguments will be lowered as: async fn foo(: , : , : ) { async move { } } // <-- dropped as you "exit" the fn // ...becomes... fn foo(__arg0: , __arg1: , __arg2: ) { async move { let __arg2 = __arg2; let = __arg2; let __arg1 = __arg1; let = __arg1; let __arg0 = __arg0; let = __arg0; } // <-- dropped as you "exit" the async block } If `` is a simple ident, then it is lowered to a single `let = ;` statement as an optimization. --- src/librustc/hir/lowering.rs | 39 ++- src/librustc/hir/map/def_collector.rs | 13 +- src/librustc/lint/context.rs | 15 +- src/librustc_resolve/lib.rs | 15 +- src/libsyntax/ast.rs | 12 +- src/libsyntax/ext/placeholders.rs | 5 +- src/libsyntax/mut_visit.rs | 14 +- src/libsyntax/parse/parser.rs | 62 ++++- ...wait-drop-order-for-async-fn-parameters.rs | 263 ++++++++++++++++++ src/test/run-pass/issue-54716.rs | 184 ------------ 10 files changed, 401 insertions(+), 221 deletions(-) create mode 100644 src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs delete mode 100644 src/test/run-pass/issue-54716.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index df455a725c5ba..e7fe9bf40ba79 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2996,8 +2996,33 @@ impl<'a> LoweringContext<'a> { if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness { let mut body = body.clone(); + // Async function arguments are lowered into the closure body so that they are + // captured and so that the drop order matches the equivalent non-async functions. + // + // async fn foo(: , : , : ) { + // async move { + // } + // } + // + // // ...becomes... + // fn foo(__arg0: , __arg1: , __arg2: ) { + // async move { + // let __arg2 = __arg2; + // let = __arg2; + // let __arg1 = __arg1; + // let = __arg1; + // let __arg0 = __arg0; + // let = __arg0; + // } + // } + // + // If `` is a simple ident, then it is lowered to a single + // `let = ;` statement as an optimization. for a in arguments.iter().rev() { - body.stmts.insert(0, a.stmt.clone()); + if let Some(pat_stmt) = a.pat_stmt.clone() { + body.stmts.insert(0, pat_stmt); + } + body.stmts.insert(0, a.move_stmt.clone()); } let async_expr = this.make_async_expr( @@ -3093,7 +3118,11 @@ impl<'a> LoweringContext<'a> { let mut decl = decl.clone(); // Replace the arguments of this async function with the generated // arguments that will be moved into the closure. - decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect(); + for (i, a) in arguments.clone().drain(..).enumerate() { + if let Some(arg) = a.arg { + decl.inputs[i] = arg; + } + } lower_fn(&decl) } else { lower_fn(decl) @@ -3590,7 +3619,11 @@ impl<'a> LoweringContext<'a> { let mut sig = sig.clone(); // Replace the arguments of this async function with the generated // arguments that will be moved into the closure. - sig.decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect(); + for (i, a) in arguments.clone().drain(..).enumerate() { + if let Some(arg) = a.arg { + sig.decl.inputs[i] = arg; + } + } lower_method(&sig) } else { lower_method(sig) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 0fa9738532215..78de85398594e 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -94,7 +94,9 @@ impl<'a> DefCollector<'a> { // Walk the generated arguments for the `async fn`. for a in arguments { use visit::Visitor; - this.visit_ty(&a.arg.ty); + if let Some(arg) = &a.arg { + this.visit_ty(&arg.ty); + } } // We do not invoke `walk_fn_decl` as this will walk the arguments that are being @@ -105,10 +107,13 @@ impl<'a> DefCollector<'a> { *closure_id, DefPathData::ClosureExpr, REGULAR_SPACE, span, ); this.with_parent(closure_def, |this| { + use visit::Visitor; + // Walk each of the generated statements before the regular block body. for a in arguments { - use visit::Visitor; - // Walk each of the generated statements before the regular block body. - this.visit_stmt(&a.stmt); + this.visit_stmt(&a.move_stmt); + if let Some(pat_stmt) = &a.pat_stmt { + this.visit_stmt(&pat_stmt); + } } visit::walk_block(this, &body); diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index f5cb4cfa29f5c..8d5c1798e0fa4 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1334,14 +1334,19 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node { for a in arguments { // Visit the argument.. - self.visit_pat(&a.arg.pat); - if let ast::ArgSource::AsyncFn(pat) = &a.arg.source { - self.visit_pat(pat); + if let Some(arg) = &a.arg { + self.visit_pat(&arg.pat); + if let ast::ArgSource::AsyncFn(pat) = &arg.source { + self.visit_pat(pat); + } + self.visit_ty(&arg.ty); } - self.visit_ty(&a.arg.ty); // ..and the statement. - self.visit_stmt(&a.stmt); + self.visit_stmt(&a.move_stmt); + if let Some(pat_stmt) = &a.pat_stmt { + self.visit_stmt(&pat_stmt); + } } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index be68f30353715..281be201a66ce 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -862,7 +862,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { // Walk the generated async arguments if this is an `async fn`, otherwise walk the // normal arguments. if let IsAsync::Async { ref arguments, .. } = asyncness { - for a in arguments { add_argument(&a.arg); } + for (i, a) in arguments.iter().enumerate() { + if let Some(arg) = &a.arg { + add_argument(&arg); + } else { + add_argument(&declaration.inputs[i]); + } + } } else { for a in &declaration.inputs { add_argument(a); } } @@ -882,8 +888,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { let mut body = body.clone(); // Insert the generated statements into the body before attempting to // resolve names. - for a in arguments { - body.stmts.insert(0, a.stmt.clone()); + for a in arguments.iter().rev() { + if let Some(pat_stmt) = a.pat_stmt.clone() { + body.stmts.insert(0, pat_stmt); + } + body.stmts.insert(0, a.move_stmt.clone()); } self.visit_block(&body); } else { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a20bf91a6ad43..33b8c76bb531a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1865,10 +1865,14 @@ pub enum Unsafety { pub struct AsyncArgument { /// `__arg0` pub ident: Ident, - /// `__arg0: ` argument to replace existing function argument `: `. - pub arg: Arg, - /// `let : = __arg0;` statement to be inserted at the start of the block. - pub stmt: Stmt, + /// `__arg0: ` argument to replace existing function argument `: `. Only if + /// argument is not a simple binding. + pub arg: Option, + /// `let __arg0 = __arg0;` statement to be inserted at the start of the block. + pub move_stmt: Stmt, + /// `let = __arg0;` statement to be inserted at the start of the block, after matching + /// move statement. Only if argument is not a simple binding. + pub pat_stmt: Option, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 68cd3c28676f9..f5e18e98436e6 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -199,7 +199,10 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { if let ast::IsAsync::Async { ref mut arguments, .. } = a { for argument in arguments.iter_mut() { - self.next_id(&mut argument.stmt.id); + self.next_id(&mut argument.move_stmt.id); + if let Some(ref mut pat_stmt) = &mut argument.pat_stmt { + self.next_id(&mut pat_stmt.id); + } } } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index d3441a2039b17..2e09235ca77b0 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -694,13 +694,21 @@ pub fn noop_visit_asyncness(asyncness: &mut IsAsync, vis: &mut T) IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => { vis.visit_id(closure_id); vis.visit_id(return_impl_trait_id); - for AsyncArgument { ident, arg, stmt } in arguments.iter_mut() { + for AsyncArgument { ident, arg, pat_stmt, move_stmt } in arguments.iter_mut() { vis.visit_ident(ident); - vis.visit_arg(arg); - visit_clobber(stmt, |stmt| { + if let Some(arg) = arg { + vis.visit_arg(arg); + } + visit_clobber(move_stmt, |stmt| { vis.flat_map_stmt(stmt) .expect_one("expected visitor to produce exactly one item") }); + visit_opt(pat_stmt, |stmt| { + visit_clobber(stmt, |stmt| { + vis.flat_map_stmt(stmt) + .expect_one("expected visitor to produce exactly one item") + }) + }); } } IsAsync::NotAsync => {} diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8efe84cdf016f..a10ee17b7e79e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -8880,11 +8880,37 @@ impl<'a> Parser<'a> { let name = format!("__arg{}", index); let ident = Ident::from_str(&name); + // Check if this is a ident pattern, if so, we can optimize and avoid adding a + // `let = __argN;` statement, instead just adding a `let = ;` + // statement. + let (ident, is_simple_pattern) = match input.pat.node { + PatKind::Ident(_, ident, _) => (ident, true), + _ => (ident, false), + }; + // Construct an argument representing `__argN: ` to replace the argument of the - // async function. - let arg = Arg { - ty: input.ty.clone(), - id, + // async function if it isn't a simple pattern. + let arg = if is_simple_pattern { + None + } else { + Some(Arg { + ty: input.ty.clone(), + id, + pat: P(Pat { + id, + node: PatKind::Ident( + BindingMode::ByValue(Mutability::Immutable), ident, None, + ), + span, + }), + source: ArgSource::AsyncFn(input.pat.clone()), + }) + }; + + // Construct a `let __argN = __argN;` statement to insert at the top of the + // async closure. This makes sure that the argument is captured by the closure and + // that the drop order is correct. + let move_local = Local { pat: P(Pat { id, node: PatKind::Ident( @@ -8892,13 +8918,6 @@ impl<'a> Parser<'a> { ), span, }), - source: ArgSource::AsyncFn(input.pat.clone()), - }; - - // Construct a `let = __argN;` statement to insert at the top of the - // async closure. - let local = P(Local { - pat: input.pat.clone(), // We explicitly do not specify the type for this statement. When the user's // argument type is `impl Trait` then this would require the // `impl_trait_in_bindings` feature to also be present for that same type to @@ -8918,10 +8937,25 @@ impl<'a> Parser<'a> { span, attrs: ThinVec::new(), source: LocalSource::AsyncFn, - }); - let stmt = Stmt { id, node: StmtKind::Local(local), span, }; + }; + + // Construct a `let = __argN;` statement to insert at the top of the + // async closure if this isn't a simple pattern. + let pat_stmt = if is_simple_pattern { + None + } else { + Some(Stmt { + id, + node: StmtKind::Local(P(Local { + pat: input.pat.clone(), + ..move_local.clone() + })), + span, + }) + }; - arguments.push(AsyncArgument { ident, arg, stmt }); + let move_stmt = Stmt { id, node: StmtKind::Local(P(move_local)), span }; + arguments.push(AsyncArgument { ident, arg, pat_stmt, move_stmt }); } } } diff --git a/src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs b/src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs new file mode 100644 index 0000000000000..708c570498460 --- /dev/null +++ b/src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs @@ -0,0 +1,263 @@ +// aux-build:arc_wake.rs +// edition:2018 +// run-pass + +#![allow(unused_variables)] +#![feature(async_await, await_macro)] + +// Test that the drop order for parameters in a fn and async fn matches up. Also test that +// parameters (used or unused) are not dropped until the async fn completes execution. +// See also #54716. + +extern crate arc_wake; + +use arc_wake::ArcWake; +use std::cell::RefCell; +use std::future::Future; +use std::marker::PhantomData; +use std::sync::Arc; +use std::rc::Rc; +use std::task::Context; + +struct EmptyWaker; + +impl ArcWake for EmptyWaker { + fn wake(self: Arc) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc>>; + +struct D(&'static str, DropOrderListPtr); + +impl Drop for D { + fn drop(&mut self) { + self.1.borrow_mut().push(DropOrder::Val(self.0)); + } +} + +/// Check that unused bindings are dropped after the function is polled. +async fn foo_async(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foo_sync(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns are dropped after the function is polled. +async fn bar_async(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn bar_sync(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns within more complex patterns are dropped after the function +/// is polled. +async fn baz_async((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn baz_sync((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore and unused bindings within and outwith more complex patterns are dropped +/// after the function is polled. +async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +struct Foo; + +impl Foo { + /// Check that unused bindings are dropped after the method is polled. + async fn foo_async(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method is polled. + async fn bar_async(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// is polled. + async fn baz_async((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method is polled. + async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +struct Bar<'a>(PhantomData<&'a ()>); + +impl<'a> Bar<'a> { + /// Check that unused bindings are dropped after the method with self is polled. + async fn foo_async(&'a self, x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(&'a self, x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method with self is polled. + async fn bar_async(&'a self, x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(&'a self, x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// with self is polled. + async fn baz_async(&'a self, (x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync(&'a self, (x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method with self is polled. + async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +fn assert_drop_order_after_poll>( + f: impl FnOnce(DropOrderListPtr) -> Fut, + g: impl FnOnce(DropOrderListPtr), +) { + let empty = Arc::new(EmptyWaker); + let waker = ArcWake::into_waker(empty); + let mut cx = Context::from_waker(&waker); + + let actual_order = Rc::new(RefCell::new(Vec::new())); + let mut fut = Box::pin(f(actual_order.clone())); + let _ = fut.as_mut().poll(&mut cx); + + let expected_order = Rc::new(RefCell::new(Vec::new())); + g(expected_order.clone()); + + assert_eq!(*actual_order.borrow(), *expected_order.borrow()); +} + +fn main() { + // Free functions (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())), + |l| bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods w/out self (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())), + |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + Foo::foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + Foo::foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods (see doc comment on function for what it tests). + let b = Bar(Default::default()); + assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())), + |l| b.bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| b.baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + b.foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + b.foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); +} diff --git a/src/test/run-pass/issue-54716.rs b/src/test/run-pass/issue-54716.rs deleted file mode 100644 index 961c412f5ecb2..0000000000000 --- a/src/test/run-pass/issue-54716.rs +++ /dev/null @@ -1,184 +0,0 @@ -// aux-build:arc_wake.rs -// edition:2018 -// run-pass - -#![allow(unused_variables)] -#![feature(async_await, await_macro)] - -extern crate arc_wake; - -use arc_wake::ArcWake; -use std::cell::RefCell; -use std::future::Future; -use std::marker::PhantomData; -use std::sync::Arc; -use std::rc::Rc; -use std::task::Context; - -struct EmptyWaker; - -impl ArcWake for EmptyWaker { - fn wake(self: Arc) {} -} - -#[derive(Debug, Eq, PartialEq)] -enum DropOrder { - Function, - Val(&'static str), -} - -type DropOrderListPtr = Rc>>; - -struct D(&'static str, DropOrderListPtr); - -impl Drop for D { - fn drop(&mut self) { - self.1.borrow_mut().push(DropOrder::Val(self.0)); - } -} - -/// Check that unused bindings are dropped after the function is polled. -async fn foo(x: D, _y: D) { - x.1.borrow_mut().push(DropOrder::Function); -} - -/// Check that underscore patterns are dropped after the function is polled. -async fn bar(x: D, _: D) { - x.1.borrow_mut().push(DropOrder::Function); -} - -/// Check that underscore patterns within more complex patterns are dropped after the function -/// is polled. -async fn baz((x, _): (D, D)) { - x.1.borrow_mut().push(DropOrder::Function); -} - -/// Check that underscore and unused bindings within and outwith more complex patterns are dropped -/// after the function is polled. -async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { - x.1.borrow_mut().push(DropOrder::Function); -} - -struct Foo; - -impl Foo { - /// Check that unused bindings are dropped after the method is polled. - async fn foo(x: D, _y: D) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore patterns are dropped after the method is polled. - async fn bar(x: D, _: D) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore patterns within more complex patterns are dropped after the method - /// is polled. - async fn baz((x, _): (D, D)) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore and unused bindings within and outwith more complex patterns are - /// dropped after the method is polled. - async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { - x.1.borrow_mut().push(DropOrder::Function); - } -} - -struct Bar<'a>(PhantomData<&'a ()>); - -impl<'a> Bar<'a> { - /// Check that unused bindings are dropped after the method with self is polled. - async fn foo(&'a self, x: D, _y: D) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore patterns are dropped after the method with self is polled. - async fn bar(&'a self, x: D, _: D) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore patterns within more complex patterns are dropped after the method - /// with self is polled. - async fn baz(&'a self, (x, _): (D, D)) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore and unused bindings within and outwith more complex patterns are - /// dropped after the method with self is polled. - async fn foobar(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { - x.1.borrow_mut().push(DropOrder::Function); - } -} - -fn assert_drop_order_after_poll>( - f: impl FnOnce(DropOrderListPtr) -> Fut, - expected_order: &[DropOrder], -) { - let empty = Arc::new(EmptyWaker); - let waker = ArcWake::into_waker(empty); - let mut cx = Context::from_waker(&waker); - - let actual_order = Rc::new(RefCell::new(Vec::new())); - let mut fut = Box::pin(f(actual_order.clone())); - let _ = fut.as_mut().poll(&mut cx); - - assert_eq!(*actual_order.borrow(), expected_order); -} - -fn main() { - use DropOrder::*; - - // At time of writing (23/04/19), the `bar` and `foobar` tests do not output the same order as - // the equivalent non-async functions. This is because the drop order of captured variables - // doesn't match the drop order of arguments in a function. - - // Free functions (see doc comment on function for what it tests). - assert_drop_order_after_poll(|l| foo(D("x", l.clone()), D("_y", l.clone())), - &[Function, Val("_y"), Val("x")]); - assert_drop_order_after_poll(|l| bar(D("x", l.clone()), D("_", l.clone())), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| baz((D("x", l.clone()), D("_", l.clone()))), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| { - foobar( - D("x", l.clone()), - (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), - D("_", l.clone()), - D("_y", l.clone()), - ) - }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]); - - // Methods w/out self (see doc comment on function for what it tests). - assert_drop_order_after_poll(|l| Foo::foo(D("x", l.clone()), D("_y", l.clone())), - &[Function, Val("_y"), Val("x")]); - assert_drop_order_after_poll(|l| Foo::bar(D("x", l.clone()), D("_", l.clone())), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| Foo::baz((D("x", l.clone()), D("_", l.clone()))), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| { - Foo::foobar( - D("x", l.clone()), - (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), - D("_", l.clone()), - D("_y", l.clone()), - ) - }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]); - - // Methods (see doc comment on function for what it tests). - let b = Bar(Default::default()); - assert_drop_order_after_poll(|l| b.foo(D("x", l.clone()), D("_y", l.clone())), - &[Function, Val("_y"), Val("x")]); - assert_drop_order_after_poll(|l| b.bar(D("x", l.clone()), D("_", l.clone())), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| b.baz((D("x", l.clone()), D("_", l.clone()))), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| { - b.foobar( - D("x", l.clone()), - (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), - D("_", l.clone()), - D("_y", l.clone()), - ) - }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]); -} From f47735c3dc596c0b55c2221a18915a7b25ed1492 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 1 May 2019 14:31:27 +0100 Subject: [PATCH 08/11] Ensure that users cannot use generated arguments. This commit gensyms the generated ident for replacement arguments so that users cannot refer to them. It also ensures that levenshtein distance suggestions do not suggest gensymed identifiers. --- src/librustc_resolve/lib.rs | 23 ++++--- src/libsyntax/parse/parser.rs | 2 +- ...sync-await-drop-order-locals-are-hidden.rs | 11 ++++ ...-await-drop-order-locals-are-hidden.stderr | 15 +++++ src/test/ui/auxiliary/arc_wake.rs | 64 +++++++++++++++++++ 5 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/async-await-drop-order-locals-are-hidden.rs create mode 100644 src/test/ui/async-await-drop-order-locals-are-hidden.stderr create mode 100644 src/test/ui/auxiliary/arc_wake.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 281be201a66ce..dcfe00069c5bd 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -4183,7 +4183,7 @@ impl<'a> Resolver<'a> { let add_module_candidates = |module: Module<'_>, names: &mut Vec| { for (&(ident, _), resolution) in module.resolutions.borrow().iter() { if let Some(binding) = resolution.borrow().binding { - if filter_fn(binding.def()) { + if !ident.name.is_gensymed() && filter_fn(binding.def()) { names.push(TypoSuggestion { candidate: ident.name, article: binding.def().article(), @@ -4201,7 +4201,7 @@ impl<'a> Resolver<'a> { for rib in self.ribs[ns].iter().rev() { // Locals and type parameters for (ident, def) in &rib.bindings { - if filter_fn(*def) { + if !ident.name.is_gensymed() && filter_fn(*def) { names.push(TypoSuggestion { candidate: ident.name, article: def.article(), @@ -4228,7 +4228,7 @@ impl<'a> Resolver<'a> { index: CRATE_DEF_INDEX, }); - if filter_fn(crate_mod) { + if !ident.name.is_gensymed() && filter_fn(crate_mod) { Some(TypoSuggestion { candidate: ident.name, article: "a", @@ -4251,13 +4251,16 @@ impl<'a> Resolver<'a> { // Add primitive types to the mix if filter_fn(Def::PrimTy(Bool)) { names.extend( - self.primitive_type_table.primitive_types.iter().map(|(name, _)| { - TypoSuggestion { - candidate: *name, - article: "a", - kind: "primitive type", - } - }) + self.primitive_type_table.primitive_types + .iter() + .filter(|(name, _)| !name.is_gensymed()) + .map(|(name, _)| { + TypoSuggestion { + candidate: *name, + article: "a", + kind: "primitive type", + } + }) ) } } else { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a10ee17b7e79e..8d95b3900014d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -8878,7 +8878,7 @@ impl<'a> Parser<'a> { // Construct a name for our temporary argument. let name = format!("__arg{}", index); - let ident = Ident::from_str(&name); + let ident = Ident::from_str(&name).gensym(); // Check if this is a ident pattern, if so, we can optimize and avoid adding a // `let = __argN;` statement, instead just adding a `let = ;` diff --git a/src/test/ui/async-await-drop-order-locals-are-hidden.rs b/src/test/ui/async-await-drop-order-locals-are-hidden.rs new file mode 100644 index 0000000000000..10dc5e27f6f9f --- /dev/null +++ b/src/test/ui/async-await-drop-order-locals-are-hidden.rs @@ -0,0 +1,11 @@ +// edition:2018 + +#![allow(unused_variables)] +#![feature(async_await)] + +async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) { + assert_eq!(__arg1, (1, 2, 3)); //~ ERROR cannot find value `__arg1` in this scope [E0425] + assert_eq!(__arg2, 4); //~ ERROR cannot find value `__arg2` in this scope [E0425] +} + +fn main() {} diff --git a/src/test/ui/async-await-drop-order-locals-are-hidden.stderr b/src/test/ui/async-await-drop-order-locals-are-hidden.stderr new file mode 100644 index 0000000000000..b988b85d63d1b --- /dev/null +++ b/src/test/ui/async-await-drop-order-locals-are-hidden.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find value `__arg1` in this scope + --> $DIR/async-await-drop-order-locals-are-hidden.rs:7:16 + | +LL | assert_eq!(__arg1, (1, 2, 3)); + | ^^^^^^ not found in this scope + +error[E0425]: cannot find value `__arg2` in this scope + --> $DIR/async-await-drop-order-locals-are-hidden.rs:8:16 + | +LL | assert_eq!(__arg2, 4); + | ^^^^^^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/auxiliary/arc_wake.rs b/src/test/ui/auxiliary/arc_wake.rs new file mode 100644 index 0000000000000..c21886f26f467 --- /dev/null +++ b/src/test/ui/auxiliary/arc_wake.rs @@ -0,0 +1,64 @@ +// edition:2018 + +use std::sync::Arc; +use std::task::{ + Waker, RawWaker, RawWakerVTable, +}; + +macro_rules! waker_vtable { + ($ty:ident) => { + &RawWakerVTable::new( + clone_arc_raw::<$ty>, + wake_arc_raw::<$ty>, + wake_by_ref_arc_raw::<$ty>, + drop_arc_raw::<$ty>, + ) + }; +} + +pub trait ArcWake { + fn wake(self: Arc); + + fn wake_by_ref(arc_self: &Arc) { + arc_self.clone().wake() + } + + fn into_waker(wake: Arc) -> Waker where Self: Sized + { + let ptr = Arc::into_raw(wake) as *const (); + + unsafe { + Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self))) + } + } +} + +unsafe fn increase_refcount(data: *const ()) { + // Retain Arc by creating a copy + let arc: Arc = Arc::from_raw(data as *const T); + let arc_clone = arc.clone(); + // Forget the Arcs again, so that the refcount isn't decrased + let _ = Arc::into_raw(arc); + let _ = Arc::into_raw(arc_clone); +} + +unsafe fn clone_arc_raw(data: *const ()) -> RawWaker { + increase_refcount::(data); + RawWaker::new(data, waker_vtable!(T)) +} + +unsafe fn drop_arc_raw(data: *const ()) { + // Drop Arc + let _: Arc = Arc::from_raw(data as *const T); +} + +unsafe fn wake_arc_raw(data: *const ()) { + let arc: Arc = Arc::from_raw(data as *const T); + ArcWake::wake(arc); +} + +unsafe fn wake_by_ref_arc_raw(data: *const ()) { + let arc: Arc = Arc::from_raw(data as *const T); + ArcWake::wake_by_ref(&arc); + let _ = Arc::into_raw(arc); +} From 1fedb0a20bfe03e1bf7d5c2576806c761b4e3963 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 1 May 2019 15:03:42 +0100 Subject: [PATCH 09/11] Unify tests under async-await directory. --- src/test/ui/{ => async-await}/auxiliary/arc_wake.rs | 0 .../async-await/drop-order-for-async-fn-parameters.rs} | 0 .../drop-order-locals-are-hidden.rs} | 0 .../drop-order-locals-are-hidden.stderr} | 4 ++-- 4 files changed, 2 insertions(+), 2 deletions(-) rename src/test/ui/{ => async-await}/auxiliary/arc_wake.rs (100%) rename src/test/{run-pass/async-await-drop-order-for-async-fn-parameters.rs => ui/async-await/drop-order-for-async-fn-parameters.rs} (100%) rename src/test/ui/{async-await-drop-order-locals-are-hidden.rs => async-await/drop-order-locals-are-hidden.rs} (100%) rename src/test/ui/{async-await-drop-order-locals-are-hidden.stderr => async-await/drop-order-locals-are-hidden.stderr} (77%) diff --git a/src/test/ui/auxiliary/arc_wake.rs b/src/test/ui/async-await/auxiliary/arc_wake.rs similarity index 100% rename from src/test/ui/auxiliary/arc_wake.rs rename to src/test/ui/async-await/auxiliary/arc_wake.rs diff --git a/src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs b/src/test/ui/async-await/drop-order-for-async-fn-parameters.rs similarity index 100% rename from src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs rename to src/test/ui/async-await/drop-order-for-async-fn-parameters.rs diff --git a/src/test/ui/async-await-drop-order-locals-are-hidden.rs b/src/test/ui/async-await/drop-order-locals-are-hidden.rs similarity index 100% rename from src/test/ui/async-await-drop-order-locals-are-hidden.rs rename to src/test/ui/async-await/drop-order-locals-are-hidden.rs diff --git a/src/test/ui/async-await-drop-order-locals-are-hidden.stderr b/src/test/ui/async-await/drop-order-locals-are-hidden.stderr similarity index 77% rename from src/test/ui/async-await-drop-order-locals-are-hidden.stderr rename to src/test/ui/async-await/drop-order-locals-are-hidden.stderr index b988b85d63d1b..ca0da6b7c962a 100644 --- a/src/test/ui/async-await-drop-order-locals-are-hidden.stderr +++ b/src/test/ui/async-await/drop-order-locals-are-hidden.stderr @@ -1,11 +1,11 @@ error[E0425]: cannot find value `__arg1` in this scope - --> $DIR/async-await-drop-order-locals-are-hidden.rs:7:16 + --> $DIR/drop-order-locals-are-hidden.rs:7:16 | LL | assert_eq!(__arg1, (1, 2, 3)); | ^^^^^^ not found in this scope error[E0425]: cannot find value `__arg2` in this scope - --> $DIR/async-await-drop-order-locals-are-hidden.rs:8:16 + --> $DIR/drop-order-locals-are-hidden.rs:8:16 | LL | assert_eq!(__arg2, 4); | ^^^^^^ not found in this scope From 26199a27ffe777db9bfbff32e7ff8f5e4c7dde4c Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Wed, 1 May 2019 15:57:02 +0200 Subject: [PATCH 10/11] doc: Warn about possible zombie apocalypse Extend the std::process::Child docs with warning about possible zombies. The previous version mentioned that when dropping the Child, the process is not killed. However, the wording gave the impression that such behaviour is fine to do (leaving the reader believe low-level details like reaping zombies of the dead processes is taken over by std somehow; or simply leaving the reader unaware about the problem). --- src/libstd/process.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index c1addb46a0a23..6e4c6e4c366e4 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -134,6 +134,18 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// the parent process wait until the child has actually exited before /// continuing. /// +/// # Warning +/// +/// On some system, calling [`wait`] or similar is necessary for the OS to +/// release resources. A process that terminated but has not been waited on is +/// still around as a "zombie". Leaving too many zombies around may exhaust +/// global resources (for example process IDs). +/// +/// The standard library does *not* automatically wait on child processes (not +/// even if the `Child` is dropped), it is up to the application developer to do +/// so. As a consequence, dropping `Child` handles without waiting on them first +/// is not recommended in long-running applications. +/// /// # Examples /// /// ```should_panic From 99ebb7a51716a98b7d9b261a6d6b37695c6b2359 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 2 May 2019 06:03:17 +0900 Subject: [PATCH 11/11] Remove Context and ContextKind --- .../borrow_check/error_reporting.rs | 76 +++---- src/librustc_mir/borrow_check/mod.rs | 203 +++++++----------- .../borrow_check/nll/explain_borrow/mod.rs | 18 +- .../borrow_check/nll/invalidation.rs | 82 ++++--- src/librustc_mir/borrow_check/path_utils.rs | 3 +- 5 files changed, 171 insertions(+), 211 deletions(-) diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index a8ebe85e2510c..ed42326d7d520 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -22,7 +22,7 @@ use syntax_pos::Span; use syntax::source_map::CompilerDesugaringKind; use super::borrow_set::BorrowData; -use super::{Context, MirBorrowckCtxt}; +use super::{MirBorrowckCtxt}; use super::{InitializationRequiringAction, PrefixSet}; use crate::dataflow::drop_flag_effects; use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex}; @@ -42,22 +42,22 @@ struct MoveSite { impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { pub(super) fn report_use_of_moved_or_uninitialized( &mut self, - context: Context, + location: Location, desired_action: InitializationRequiringAction, (moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span), mpi: MovePathIndex, ) { debug!( - "report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} \ + "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \ moved_place={:?} used_place={:?} span={:?} mpi={:?}", - context, desired_action, moved_place, used_place, span, mpi + location, desired_action, moved_place, used_place, span, mpi ); - let use_spans = self.move_spans(moved_place, context.loc) - .or_else(|| self.borrow_spans(span, context.loc)); + let use_spans = self.move_spans(moved_place, location) + .or_else(|| self.borrow_spans(span, location)); let span = use_spans.args_or_use(); - let move_site_vec = self.get_moved_indexes(context, mpi); + let move_site_vec = self.get_moved_indexes(location, mpi); debug!( "report_use_of_moved_or_uninitialized: move_site_vec={:?}", move_site_vec @@ -125,7 +125,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); self.add_moved_or_invoked_closure_note( - context.loc, + location, used_place, &mut err, ); @@ -261,13 +261,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { pub(super) fn report_move_out_while_borrowed( &mut self, - context: Context, + location: Location, (place, span): (&Place<'tcx>, Span), borrow: &BorrowData<'tcx>, ) { debug!( - "report_move_out_while_borrowed: context={:?} place={:?} span={:?} borrow={:?}", - context, place, span, borrow + "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}", + location, place, span, borrow ); let tcx = self.infcx.tcx; let value_msg = match self.describe_place(place) { @@ -282,7 +282,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.args_or_use(); - let move_spans = self.move_spans(place, context.loc); + let move_spans = self.move_spans(place, location); let span = move_spans.args_or_use(); let mut err = tcx.cannot_move_when_borrowed( @@ -304,7 +304,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); self.explain_why_borrow_contains_point( - context, + location, borrow, None, ).add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", Some(borrow_span)); @@ -313,7 +313,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { pub(super) fn report_use_while_mutably_borrowed( &mut self, - context: Context, + location: Location, (place, _span): (&Place<'tcx>, Span), borrow: &BorrowData<'tcx>, ) -> DiagnosticBuilder<'cx> { @@ -324,7 +324,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Conflicting borrows are reported separately, so only check for move // captures. - let use_spans = self.move_spans(place, context.loc); + let use_spans = self.move_spans(place, location); let span = use_spans.var_or_use(); let mut err = tcx.cannot_use_when_mutably_borrowed( @@ -343,14 +343,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe()) }); - self.explain_why_borrow_contains_point(context, borrow, None) + self.explain_why_borrow_contains_point(location, borrow, None) .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None); err } pub(super) fn report_conflicting_borrow( &mut self, - context: Context, + location: Location, (place, span): (&Place<'tcx>, Span), gen_borrow_kind: BorrowKind, issued_borrow: &BorrowData<'tcx>, @@ -358,7 +358,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let issued_spans = self.retrieve_borrow_spans(issued_borrow); let issued_span = issued_spans.args_or_use(); - let borrow_spans = self.borrow_spans(span, context.loc); + let borrow_spans = self.borrow_spans(span, location); let span = borrow_spans.args_or_use(); let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() { @@ -370,7 +370,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let (desc_place, msg_place, msg_borrow, union_type_name) = self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place); - let explanation = self.explain_why_borrow_contains_point(context, issued_borrow, None); + let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None); let second_borrow_desc = if explanation.is_explained() { "second " } else { @@ -671,7 +671,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// `Drop::drop` with an aliasing borrow.) pub(super) fn report_borrowed_value_does_not_live_long_enough( &mut self, - context: Context, + location: Location, borrow: &BorrowData<'tcx>, place_span: (&Place<'tcx>, Span), kind: Option, @@ -680,7 +680,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { "report_borrowed_value_does_not_live_long_enough(\ {:?}, {:?}, {:?}, {:?}\ )", - context, borrow, place_span, kind + location, borrow, place_span, kind ); let drop_span = place_span.1; @@ -719,7 +719,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // destructor conflict. if !borrow.borrowed_place.is_prefix_of(place_span.0) { self.report_borrow_conflicts_with_destructor( - context, borrow, place_span, kind, dropped_ty, + location, borrow, place_span, kind, dropped_ty, ); return; } @@ -728,7 +728,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let place_desc = self.describe_place(&borrow.borrowed_place); let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0)); - let explanation = self.explain_why_borrow_contains_point(context, &borrow, kind_place); + let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place); let err = match (place_desc, explanation) { (Some(_), _) if self.is_place_thread_local(root_place) => { @@ -784,7 +784,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { }, ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span), (Some(name), explanation) => self.report_local_value_does_not_live_long_enough( - context, + location, &name, &scope_tree, &borrow, @@ -793,7 +793,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { explanation, ), (None, explanation) => self.report_temporary_value_does_not_live_long_enough( - context, + location, &scope_tree, &borrow, drop_span, @@ -808,7 +808,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn report_local_value_does_not_live_long_enough( &mut self, - context: Context, + location: Location, name: &str, scope_tree: &'tcx ScopeTree, borrow: &BorrowData<'tcx>, @@ -820,7 +820,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { "report_local_value_does_not_live_long_enough(\ {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\ )", - context, name, scope_tree, borrow, drop_span, borrow_spans + location, name, scope_tree, borrow, drop_span, borrow_spans ); let borrow_span = borrow_spans.var_or_use(); @@ -914,7 +914,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn report_borrow_conflicts_with_destructor( &mut self, - context: Context, + location: Location, borrow: &BorrowData<'tcx>, (place, drop_span): (&Place<'tcx>, Span), kind: Option, @@ -924,7 +924,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { "report_borrow_conflicts_with_destructor(\ {:?}, {:?}, ({:?}, {:?}), {:?}\ )", - context, borrow, place, drop_span, kind, + location, borrow, place, drop_span, kind, ); let borrow_spans = self.retrieve_borrow_spans(borrow); @@ -957,7 +957,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Only give this note and suggestion if they could be relevant. let explanation = - self.explain_why_borrow_contains_point(context, borrow, kind.map(|k| (k, place))); + self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place))); match explanation { BorrowExplanation::UsedLater { .. } | BorrowExplanation::UsedLaterWhenDropped { .. } => { @@ -998,7 +998,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn report_temporary_value_does_not_live_long_enough( &mut self, - context: Context, + location: Location, scope_tree: &'tcx ScopeTree, borrow: &BorrowData<'tcx>, drop_span: Span, @@ -1010,7 +1010,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { "report_temporary_value_does_not_live_long_enough(\ {:?}, {:?}, {:?}, {:?}, {:?}\ )", - context, scope_tree, borrow, drop_span, proper_span + location, scope_tree, borrow, drop_span, proper_span ); if let BorrowExplanation::MustBeValidFor { @@ -1246,12 +1246,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { err } - fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec { + fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec { let mir = self.mir; let mut stack = Vec::new(); - stack.extend(mir.predecessor_locations(context.loc).map(|predecessor| { - let is_back_edge = context.loc.dominates(predecessor, &self.dominators); + stack.extend(mir.predecessor_locations(location).map(|predecessor| { + let is_back_edge = location.dominates(predecessor, &self.dominators); (predecessor, is_back_edge) })); @@ -1348,7 +1348,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { pub(super) fn report_illegal_mutation_of_borrowed( &mut self, - context: Context, + location: Location, (place, span): (&Place<'tcx>, Span), loan: &BorrowData<'tcx>, ) { @@ -1386,7 +1386,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { format!("borrow occurs due to use{}", loan_spans.describe()), ); - self.explain_why_borrow_contains_point(context, loan, None) + self.explain_why_borrow_contains_point(location, loan, None) .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None); err.buffer(&mut self.errors_buffer); @@ -1400,7 +1400,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// assignment to `x.f`). pub(super) fn report_illegal_reassignment( &mut self, - _context: Context, + _location: Location, (place, span): (&Place<'tcx>, Span), assigned_span: Span, err_place: &Place<'tcx>, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 169d56523591d..1d65a018dd62d 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -302,11 +302,12 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( // Convert any reservation warnings into lints. let reservation_warnings = mem::replace(&mut mbcx.reservation_warnings, Default::default()); - for (_, (place, span, context, bk, borrow)) in reservation_warnings { - let mut initial_diag = mbcx.report_conflicting_borrow(context, (&place, span), bk, &borrow); + for (_, (place, span, location, bk, borrow)) in reservation_warnings { + let mut initial_diag = + mbcx.report_conflicting_borrow(location, (&place, span), bk, &borrow); let lint_root = if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data { - let scope = mbcx.mir.source_info(context.loc).scope; + let scope = mbcx.mir.source_info(location).scope; vsi[scope].lint_root } else { id @@ -483,7 +484,7 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// for the activation of the borrow. reservation_warnings: FxHashMap< BorrowIndex, - (Place<'tcx>, Span, Context, BorrowKind, BorrowData<'tcx>) + (Place<'tcx>, Span, Location, BorrowKind, BorrowData<'tcx>) >, /// This field keeps track of move errors that are to be reported for given move indicies. /// @@ -559,14 +560,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx match stmt.kind { StatementKind::Assign(ref lhs, ref rhs) => { self.consume_rvalue( - ContextKind::AssignRhs.new(location), - (rhs, span), location, + (rhs, span), flow_state, ); self.mutate_place( - ContextKind::AssignLhs.new(location), + location, (lhs, span), Shallow(None), JustWrite, @@ -585,7 +585,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx // match x {}; // from compiling. self.check_if_path_or_subpath_is_moved( - ContextKind::FakeRead.new(location), + location, InitializationRequiringAction::Use, (place, span), flow_state, @@ -596,7 +596,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx variant_index: _, } => { self.mutate_place( - ContextKind::SetDiscrim.new(location), + location, (place, span), Shallow(None), JustWrite, @@ -604,27 +604,26 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx ); } StatementKind::InlineAsm(ref asm) => { - let context = ContextKind::InlineAsm.new(location); for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) { if o.is_indirect { // FIXME(eddyb) indirect inline asm outputs should // be encoded through MIR place derefs instead. self.access_place( - context, + location, (output, o.span), (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, flow_state, ); self.check_if_path_or_subpath_is_moved( - context, + location, InitializationRequiringAction::Use, (output, o.span), flow_state, ); } else { self.mutate_place( - context, + location, (output, o.span), if o.is_rw { Deep } else { Shallow(None) }, if o.is_rw { WriteAndRead } else { JustWrite }, @@ -633,7 +632,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx } } for (_, input) in asm.inputs.iter() { - self.consume_operand(context, (input, span), flow_state); + self.consume_operand(location, (input, span), flow_state); } } StatementKind::Nop @@ -645,7 +644,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx } StatementKind::StorageDead(local) => { self.access_place( - ContextKind::StorageDead.new(location), + location, (&Place::Base(PlaceBase::Local(local)), span), (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, @@ -677,7 +676,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx values: _, targets: _, } => { - self.consume_operand(ContextKind::SwitchInt.new(loc), (discr, span), flow_state); + self.consume_operand(loc, (discr, span), flow_state); } TerminatorKind::Drop { location: ref drop_place, @@ -702,7 +701,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx loc, term, drop_place, drop_place_ty, span); self.access_place( - ContextKind::Drop.new(loc), + loc, (drop_place, span), (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, @@ -716,14 +715,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx unwind: _, } => { self.mutate_place( - ContextKind::DropAndReplace.new(loc), + loc, (drop_place, span), Deep, JustWrite, flow_state, ); self.consume_operand( - ContextKind::DropAndReplace.new(loc), + loc, (new_value, span), flow_state, ); @@ -735,17 +734,17 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx cleanup: _, from_hir_call: _, } => { - self.consume_operand(ContextKind::CallOperator.new(loc), (func, span), flow_state); + self.consume_operand(loc, (func, span), flow_state); for arg in args { self.consume_operand( - ContextKind::CallOperand.new(loc), + loc, (arg, span), flow_state, ); } if let Some((ref dest, _ /*bb*/)) = *destination { self.mutate_place( - ContextKind::CallDest.new(loc), + loc, (dest, span), Deep, JustWrite, @@ -760,11 +759,11 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx target: _, cleanup: _, } => { - self.consume_operand(ContextKind::Assert.new(loc), (cond, span), flow_state); + self.consume_operand(loc, (cond, span), flow_state); use rustc::mir::interpret::InterpError::BoundsCheck; if let BoundsCheck { ref len, ref index } = *msg { - self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state); - self.consume_operand(ContextKind::Assert.new(loc), (index, span), flow_state); + self.consume_operand(loc, (len, span), flow_state); + self.consume_operand(loc, (index, span), flow_state); } } @@ -773,7 +772,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx resume: _, drop: _, } => { - self.consume_operand(ContextKind::Yield.new(loc), (value, span), flow_state); + self.consume_operand(loc, (value, span), flow_state); if self.movable_generator { // Look for any active borrows to locals @@ -796,8 +795,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx flow_state.with_outgoing_borrows(|borrows| { for i in borrows { let borrow = &borrow_set[i]; - let context = ContextKind::StorageDead.new(loc); - self.check_for_invalidation_at_exit(context, borrow, span); + self.check_for_invalidation_at_exit(loc, borrow, span); } }); } @@ -955,7 +953,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// Returns `true` if an error is reported. fn access_place( &mut self, - context: Context, + location: Location, place_span: (&Place<'tcx>, Span), kind: (AccessDepth, ReadOrWrite), is_local_mutation_allowed: LocalMutationIsAllowed, @@ -994,10 +992,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { rw, is_local_mutation_allowed, flow_state, - context.loc, + location, ); let conflict_error = - self.check_access_for_conflict(context, place_span, sd, rw, flow_state); + self.check_access_for_conflict(location, place_span, sd, rw, flow_state); if let (Activation(_, borrow_idx), true) = (kind.1, conflict_error) { // Suppress this warning when there's an error being emited for the @@ -1018,30 +1016,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn check_access_for_conflict( &mut self, - context: Context, + location: Location, place_span: (&Place<'tcx>, Span), sd: AccessDepth, rw: ReadOrWrite, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) -> bool { debug!( - "check_access_for_conflict(context={:?}, place_span={:?}, sd={:?}, rw={:?})", - context, place_span, sd, rw, + "check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})", + location, place_span, sd, rw, ); let mut error_reported = false; let tcx = self.infcx.tcx; let mir = self.mir; - let location = self.location_table.start_index(context.loc); + let location_table = self.location_table.start_index(location); let borrow_set = self.borrow_set.clone(); each_borrow_involving_path( self, tcx, mir, - context, + location, (sd, place_span.0), &borrow_set, - flow_state.borrows_in_scope(location), + flow_state.borrows_in_scope(location_table), |this, borrow_index, borrow| match (rw, borrow.kind) { // Obviously an activation is compatible with its own // reservation (or even prior activating uses of same @@ -1075,7 +1073,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. - if !is_active(&this.dominators, borrow, context.loc) { + if !is_active(&this.dominators, borrow, location) { assert!(allow_two_phase_borrow(borrow.kind)); return Control::Continue; } @@ -1083,11 +1081,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { error_reported = true; match kind { ReadKind::Copy => { - this.report_use_while_mutably_borrowed(context, place_span, borrow) + this.report_use_while_mutably_borrowed(location, place_span, borrow) .buffer(&mut this.errors_buffer); } ReadKind::Borrow(bk) => { - this.report_conflicting_borrow(context, place_span, bk, borrow) + this.report_conflicting_borrow(location, place_span, bk, borrow) .buffer(&mut this.errors_buffer); } } @@ -1098,7 +1096,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | (Reservation(WriteKind::MutableBorrow(bk)), BorrowKind::Shared) if { tcx.migrate_borrowck() } => { - let bi = this.borrow_set.location_map[&context.loc]; + let bi = this.borrow_set.location_map[&location]; debug!( "recording invalid reservation of place: {:?} with \ borrow index {:?} as warning", @@ -1111,7 +1109,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // checking was otherwise successful. this.reservation_warnings.insert( bi, - (place_span.0.clone(), place_span.1, context, bk, borrow.clone()), + (place_span.0.clone(), place_span.1, location, bk, borrow.clone()), ); // Don't suppress actual errors. @@ -1143,21 +1141,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { error_reported = true; match kind { WriteKind::MutableBorrow(bk) => { - this.report_conflicting_borrow(context, place_span, bk, borrow) + this.report_conflicting_borrow(location, place_span, bk, borrow) .buffer(&mut this.errors_buffer); } WriteKind::StorageDeadOrDrop => { this.report_borrowed_value_does_not_live_long_enough( - context, + location, borrow, place_span, Some(kind)) } WriteKind::Mutate => { - this.report_illegal_mutation_of_borrowed(context, place_span, borrow) + this.report_illegal_mutation_of_borrowed(location, place_span, borrow) } WriteKind::Move => { - this.report_move_out_while_borrowed(context, place_span, borrow) + this.report_move_out_while_borrowed(location, place_span, borrow) } } Control::Break @@ -1170,7 +1168,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn mutate_place( &mut self, - context: Context, + location: Location, place_span: (&Place<'tcx>, Span), kind: AccessDepth, mode: MutateMode, @@ -1180,14 +1178,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { match mode { MutateMode::WriteAndRead => { self.check_if_path_or_subpath_is_moved( - context, + location, InitializationRequiringAction::Update, place_span, flow_state, ); } MutateMode::JustWrite => { - self.check_if_assigned_path_is_moved(context, place_span, flow_state); + self.check_if_assigned_path_is_moved(location, place_span, flow_state); } } @@ -1198,7 +1196,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if let Mutability::Not = self.mir.local_decls[local].mutability { // check for reassignments to immutable local variables self.check_if_reassignment_to_immutable_state( - context, + location, local, place_span, flow_state, @@ -1209,7 +1207,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Otherwise, use the normal access permission rules. self.access_place( - context, + location, place_span, (kind, Write(WriteKind::Mutate)), LocalMutationIsAllowed::No, @@ -1219,9 +1217,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn consume_rvalue( &mut self, - context: Context, + location: Location, (rvalue, span): (&Rvalue<'tcx>, Span), - _location: Location, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { match *rvalue { @@ -1242,7 +1239,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { }; self.access_place( - context, + location, (place, span), access_kind, LocalMutationIsAllowed::No, @@ -1256,7 +1253,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { }; self.check_if_path_or_subpath_is_moved( - context, + location, action, (place, span), flow_state, @@ -1267,7 +1264,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | Rvalue::Repeat(ref operand, _) | Rvalue::UnaryOp(_ /*un_op*/, ref operand) | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => { - self.consume_operand(context, (operand, span), flow_state) + self.consume_operand(location, (operand, span), flow_state) } Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => { @@ -1277,14 +1274,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { _ => unreachable!(), }; self.access_place( - context, + location, (place, span), (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, flow_state, ); self.check_if_path_or_subpath_is_moved( - context, + location, InitializationRequiringAction::Use, (place, span), flow_state, @@ -1293,8 +1290,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2) | Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => { - self.consume_operand(context, (operand1, span), flow_state); - self.consume_operand(context, (operand2, span), flow_state); + self.consume_operand(location, (operand1, span), flow_state); + self.consume_operand(location, (operand2, span), flow_state); } Rvalue::NullaryOp(_op, _ty) => { @@ -1326,7 +1323,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } for operand in operands { - self.consume_operand(context, (operand, span), flow_state); + self.consume_operand(location, (operand, span), flow_state); } } } @@ -1407,7 +1404,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn consume_operand( &mut self, - context: Context, + location: Location, (operand, span): (&Operand<'tcx>, Span), flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { @@ -1416,7 +1413,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // copy of place: check if this is "copy of frozen path" // (FIXME: see check_loans.rs) self.access_place( - context, + location, (place, span), (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, @@ -1425,7 +1422,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Finally, check if path was already moved. self.check_if_path_or_subpath_is_moved( - context, + location, InitializationRequiringAction::Use, (place, span), flow_state, @@ -1434,7 +1431,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Operand::Move(ref place) => { // move of place: check if this is move of already borrowed path self.access_place( - context, + location, (place, span), (Deep, Write(WriteKind::Move)), LocalMutationIsAllowed::Yes, @@ -1443,7 +1440,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Finally, check if path was already moved. self.check_if_path_or_subpath_is_moved( - context, + location, InitializationRequiringAction::Use, (place, span), flow_state, @@ -1457,7 +1454,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// exits fn check_for_invalidation_at_exit( &mut self, - context: Context, + location: Location, borrow: &BorrowData<'tcx>, span: Span, ) { @@ -1513,7 +1510,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // of just a span here. let span = self.infcx.tcx.sess.source_map().end_point(span); self.report_borrowed_value_does_not_live_long_enough( - context, + location, borrow, (place, span), None, @@ -1558,7 +1555,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { }); self.access_place( - ContextKind::Activation.new(location), + location, (&borrow.borrowed_place, span), ( Deep, @@ -1577,7 +1574,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn check_if_reassignment_to_immutable_state( &mut self, - context: Context, + location: Location, local: Local, place_span: (&Place<'tcx>, Span), flow_state: &Flows<'cx, 'gcx, 'tcx>, @@ -1590,14 +1587,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let init = &self.move_data.inits[init_index]; let span = init.span(&self.mir); self.report_illegal_reassignment( - context, place_span, span, place_span.0 + location, place_span, span, place_span.0 ); } } fn check_if_full_path_is_moved( &mut self, - context: Context, + location: Location, desired_action: InitializationRequiringAction, place_span: (&Place<'tcx>, Span), flow_state: &Flows<'cx, 'gcx, 'tcx>, @@ -1644,7 +1641,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Ok((prefix, mpi)) => { if maybe_uninits.contains(mpi) { self.report_use_of_moved_or_uninitialized( - context, + location, desired_action, (prefix, place_span.0, place_span.1), mpi, @@ -1665,7 +1662,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn check_if_path_or_subpath_is_moved( &mut self, - context: Context, + location: Location, desired_action: InitializationRequiringAction, place_span: (&Place<'tcx>, Span), flow_state: &Flows<'cx, 'gcx, 'tcx>, @@ -1687,7 +1684,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // must have been initialized for the use to be sound. // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` - self.check_if_full_path_is_moved(context, desired_action, place_span, flow_state); + self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state); // A move of any shallow suffix of `place` also interferes // with an attempt to use `place`. This is scenario 3 above. @@ -1702,7 +1699,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if let Some(mpi) = self.move_path_for_place(place_span.0) { if let Some(child_mpi) = maybe_uninits.has_any_child_of(mpi) { self.report_use_of_moved_or_uninitialized( - context, + location, desired_action, (place_span.0, place_span.0, place_span.1), child_mpi, @@ -1753,7 +1750,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn check_if_assigned_path_is_moved( &mut self, - context: Context, + location: Location, (place, span): (&Place<'tcx>, Span), flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { @@ -1781,7 +1778,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // assigning to (*P) requires P to be initialized ProjectionElem::Deref => { self.check_if_full_path_is_moved( - context, InitializationRequiringAction::Use, + location, InitializationRequiringAction::Use, (base, span), flow_state); // (base initialized; no need to // recur further) @@ -1789,8 +1786,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } ProjectionElem::Subslice { .. } => { - panic!("we don't allow assignments to subslices, context: {:?}", - context); + panic!("we don't allow assignments to subslices, location: {:?}", + location); } ProjectionElem::Field(..) => { @@ -1801,7 +1798,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { match base.ty(self.mir, tcx).ty.sty { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( - context, InitializationRequiringAction::Assignment, + location, InitializationRequiringAction::Assignment, (base, span), flow_state); // (base initialized; no need to @@ -1813,7 +1810,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Once `let s; s.x = V; read(s.x);`, // is allowed, remove this match arm. ty::Adt(..) | ty::Tuple(..) => { - check_parent_of_field(self, context, base, span, flow_state); + check_parent_of_field(self, location, base, span, flow_state); if let Some(local) = place.base_local() { // rust-lang/rust#21232, @@ -1841,7 +1838,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn check_parent_of_field<'cx, 'gcx, 'tcx>( this: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, - context: Context, + location: Location, base: &Place<'tcx>, span: Span, flow_state: &Flows<'cx, 'gcx, 'tcx>, @@ -1907,7 +1904,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { this.move_data.moves[*moi].source.is_predecessor_of( - context.loc, this.mir, + location, this.mir, ) }) { return; @@ -1916,7 +1913,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } this.report_use_of_moved_or_uninitialized( - context, + location, InitializationRequiringAction::PartialAssignment, (prefix, base, span), mpi, @@ -2234,7 +2231,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Subtle: this is an upvar // reference, so it looks like // `self.foo` -- we want to double - // check that the context `*self` + // check that the location `*self` // is mutable (i.e., this is not a // `Fn` closure). But if that // check succeeds, we want to @@ -2331,37 +2328,3 @@ enum Overlap { /// will also be disjoint. Disjoint, } - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -struct Context { - kind: ContextKind, - loc: Location, -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum ContextKind { - Activation, - AssignLhs, - AssignRhs, - SetDiscrim, - InlineAsm, - SwitchInt, - Drop, - DropAndReplace, - CallOperator, - CallOperand, - CallDest, - Assert, - Yield, - FakeRead, - StorageDead, -} - -impl ContextKind { - fn new(self, loc: Location) -> Context { - Context { - kind: self, - loc, - } - } -} 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 89f85a941d386..c64d4b4a531e0 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -4,7 +4,7 @@ use crate::borrow_check::borrow_set::BorrowData; use crate::borrow_check::error_reporting::UseSpans; use crate::borrow_check::nll::region_infer::{Cause, RegionName}; use crate::borrow_check::nll::ConstraintDescription; -use crate::borrow_check::{Context, MirBorrowckCtxt, WriteKind}; +use crate::borrow_check::{MirBorrowckCtxt, WriteKind}; use rustc::mir::{ CastKind, ConstraintCategory, FakeReadCause, Local, Location, Mir, Operand, Place, PlaceBase, Projection, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, @@ -209,13 +209,13 @@ impl BorrowExplanation { impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// Returns structured explanation for *why* the borrow contains the - /// point from `context`. This is key for the "3-point errors" + /// point from `location`. This is key for the "3-point errors" /// [described in the NLL RFC][d]. /// /// # Parameters /// /// - `borrow`: the borrow in question - /// - `context`: where the borrow occurs + /// - `location`: where the borrow occurs /// - `kind_place`: if Some, this describes the statement that triggered the error. /// - first half is the kind of write, if any, being performed /// - second half is the place being accessed @@ -223,13 +223,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points pub(in crate::borrow_check) fn explain_why_borrow_contains_point( &self, - context: Context, + location: Location, borrow: &BorrowData<'tcx>, kind_place: Option<(WriteKind, &Place<'tcx>)>, ) -> BorrowExplanation { debug!( - "explain_why_borrow_contains_point(context={:?}, borrow={:?}, kind_place={:?})", - context, borrow, kind_place + "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})", + location, borrow, kind_place ); let regioncx = &self.nonlexical_regioncx; @@ -242,20 +242,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { borrow_region_vid ); - let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, context.loc); + let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, location); debug!( "explain_why_borrow_contains_point: region_sub={:?}", region_sub ); - match find_use::find(mir, regioncx, tcx, region_sub, context.loc) { + match find_use::find(mir, regioncx, tcx, region_sub, location) { Some(Cause::LiveVar(local, location)) => { let span = mir.source_info(location).span; let spans = self .move_spans(&Place::Base(PlaceBase::Local(local)), location) .or_else(|| self.borrow_spans(span, location)); - let borrow_location = context.loc; + let borrow_location = location; if self.is_use_in_later_iteration_of_loop(borrow_location, location) { let later_use = self.later_use_kind(borrow, spans, location); BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1) diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index fd17d4a812566..e3ab48ccff15b 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -3,7 +3,6 @@ use crate::borrow_check::location::LocationTable; use crate::borrow_check::{JustWrite, WriteAndRead}; use crate::borrow_check::{AccessDepth, Deep, Shallow}; use crate::borrow_check::{ReadOrWrite, Activation, Read, Reservation, Write}; -use crate::borrow_check::{Context, ContextKind}; use crate::borrow_check::{LocalMutationIsAllowed, MutateMode}; use crate::borrow_check::ArtificialField; use crate::borrow_check::{ReadKind, WriteKind}; @@ -66,12 +65,12 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { match statement.kind { StatementKind::Assign(ref lhs, ref rhs) => { self.consume_rvalue( - ContextKind::AssignRhs.new(location), + location, rhs, ); self.mutate_place( - ContextKind::AssignLhs.new(location), + location, lhs, Shallow(None), JustWrite @@ -85,27 +84,26 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { variant_index: _, } => { self.mutate_place( - ContextKind::SetDiscrim.new(location), + location, place, Shallow(None), JustWrite, ); } StatementKind::InlineAsm(ref asm) => { - let context = ContextKind::InlineAsm.new(location); for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) { if o.is_indirect { // FIXME(eddyb) indirect inline asm outputs should // be encoded through MIR place derefs instead. self.access_place( - context, + location, output, (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, ); } else { self.mutate_place( - context, + location, output, if o.is_rw { Deep } else { Shallow(None) }, if o.is_rw { WriteAndRead } else { JustWrite }, @@ -113,7 +111,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { } } for (_, input) in asm.inputs.iter() { - self.consume_operand(context, input); + self.consume_operand(location, input); } } StatementKind::Nop | @@ -125,7 +123,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { } StatementKind::StorageDead(local) => { self.access_place( - ContextKind::StorageDead.new(location), + location, &Place::Base(PlaceBase::Local(local)), (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, @@ -150,7 +148,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { values: _, targets: _, } => { - self.consume_operand(ContextKind::SwitchInt.new(location), discr); + self.consume_operand(location, discr); } TerminatorKind::Drop { location: ref drop_place, @@ -158,7 +156,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { unwind: _, } => { self.access_place( - ContextKind::Drop.new(location), + location, drop_place, (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, @@ -171,13 +169,13 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { unwind: _, } => { self.mutate_place( - ContextKind::DropAndReplace.new(location), + location, drop_place, Deep, JustWrite, ); self.consume_operand( - ContextKind::DropAndReplace.new(location), + location, new_value, ); } @@ -188,13 +186,13 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { cleanup: _, from_hir_call: _, } => { - self.consume_operand(ContextKind::CallOperator.new(location), func); + self.consume_operand(location, func); for arg in args { - self.consume_operand(ContextKind::CallOperand.new(location), arg); + self.consume_operand(location, arg); } if let Some((ref dest, _ /*bb*/)) = *destination { self.mutate_place( - ContextKind::CallDest.new(location), + location, dest, Deep, JustWrite, @@ -208,11 +206,11 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { target: _, cleanup: _, } => { - self.consume_operand(ContextKind::Assert.new(location), cond); + self.consume_operand(location, cond); use rustc::mir::interpret::InterpError::BoundsCheck; if let BoundsCheck { ref len, ref index } = *msg { - self.consume_operand(ContextKind::Assert.new(location), len); - self.consume_operand(ContextKind::Assert.new(location), index); + self.consume_operand(location, len); + self.consume_operand(location, index); } } TerminatorKind::Yield { @@ -220,7 +218,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { resume, drop: _, } => { - self.consume_operand(ContextKind::Yield.new(location), value); + self.consume_operand(location, value); // Invalidate all borrows of local places let borrow_set = self.borrow_set.clone(); @@ -264,13 +262,13 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { /// Simulates mutation of a place. fn mutate_place( &mut self, - context: Context, + location: Location, place: &Place<'tcx>, kind: AccessDepth, _mode: MutateMode, ) { self.access_place( - context, + location, place, (kind, Write(WriteKind::Mutate)), LocalMutationIsAllowed::ExceptUpvars, @@ -280,13 +278,13 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { /// Simulates consumption of an operand. fn consume_operand( &mut self, - context: Context, + location: Location, operand: &Operand<'tcx>, ) { match *operand { Operand::Copy(ref place) => { self.access_place( - context, + location, place, (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, @@ -294,7 +292,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { } Operand::Move(ref place) => { self.access_place( - context, + location, place, (Deep, Write(WriteKind::Move)), LocalMutationIsAllowed::Yes, @@ -307,7 +305,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { // Simulates consumption of an rvalue fn consume_rvalue( &mut self, - context: Context, + location: Location, rvalue: &Rvalue<'tcx>, ) { match *rvalue { @@ -328,7 +326,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { }; self.access_place( - context, + location, place, access_kind, LocalMutationIsAllowed::No, @@ -339,7 +337,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { | Rvalue::Repeat(ref operand, _) | Rvalue::UnaryOp(_ /*un_op*/, ref operand) | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => { - self.consume_operand(context, operand) + self.consume_operand(location, operand) } Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => { @@ -349,7 +347,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { _ => unreachable!(), }; self.access_place( - context, + location, place, (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, @@ -358,8 +356,8 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2) | Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => { - self.consume_operand(context, operand1); - self.consume_operand(context, operand2); + self.consume_operand(location, operand1); + self.consume_operand(location, operand2); } Rvalue::NullaryOp(_op, _ty) => { @@ -367,7 +365,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { Rvalue::Aggregate(_, ref operands) => { for operand in operands { - self.consume_operand(context, operand); + self.consume_operand(location, operand); } } } @@ -376,27 +374,27 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { /// Simulates an access to a place. fn access_place( &mut self, - context: Context, + location: Location, place: &Place<'tcx>, kind: (AccessDepth, ReadOrWrite), _is_local_mutation_allowed: LocalMutationIsAllowed, ) { let (sd, rw) = kind; // note: not doing check_access_permissions checks because they don't generate invalidates - self.check_access_for_conflict(context, place, sd, rw); + self.check_access_for_conflict(location, place, sd, rw); } fn check_access_for_conflict( &mut self, - context: Context, + location: Location, place: &Place<'tcx>, sd: AccessDepth, rw: ReadOrWrite, ) { debug!( - "invalidation::check_access_for_conflict(context={:?}, place={:?}, sd={:?}, \ + "invalidation::check_access_for_conflict(location={:?}, place={:?}, sd={:?}, \ rw={:?})", - context, + location, place, sd, rw, @@ -409,7 +407,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { self, tcx, mir, - context, + location, (sd, place), &borrow_set.clone(), indices, @@ -435,7 +433,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { (Read(_), BorrowKind::Unique) | (Read(_), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. - if !is_active(&this.dominators, borrow, context.loc) { + if !is_active(&this.dominators, borrow, location) { // If the borrow isn't active yet, reads don't invalidate it assert!(allow_two_phase_borrow(borrow.kind)); return Control::Continue; @@ -443,7 +441,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { // Unique and mutable borrows are invalidated by reads from any // involved path - this.generate_invalidates(borrow_index, context.loc); + this.generate_invalidates(borrow_index, location); } (Reservation(_), _) @@ -453,7 +451,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { // Reservations count as writes since we need to check // that activating the borrow will be OK // FIXME(bob_twinkles) is this actually the right thing to do? - this.generate_invalidates(borrow_index, context.loc); + this.generate_invalidates(borrow_index, location); } } Control::Continue @@ -485,7 +483,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { }); self.access_place( - ContextKind::Activation.new(location), + location, &borrow.borrowed_place, ( Deep, diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 86af2490408aa..0c2a4ef45f104 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -1,6 +1,5 @@ use crate::borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation}; use crate::borrow_check::places_conflict; -use crate::borrow_check::Context; use crate::borrow_check::AccessDepth; use crate::dataflow::indexes::BorrowIndex; use rustc::mir::{BasicBlock, Location, Mir, Place, PlaceBase}; @@ -27,7 +26,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( s: &mut S, tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, - _context: Context, + _location: Location, access_place: (AccessDepth, &Place<'tcx>), borrow_set: &BorrowSet<'tcx>, candidates: I,