diff --git a/Cargo.lock b/Cargo.lock index f6713496f5b..fd6a7a5604e 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/hir/lowering.rs b/src/librustc/hir/lowering.rs index f4209a39c83..6d57882976e 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 0fa97385322..78de8539859 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 f5cb4cfa29f..8d5c1798e0f 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_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 7ea5e912309..9077e89a402 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 08424e7c322..09b284052b3 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/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 4cae20b698a..f25891d77ce 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 { @@ -63,12 +63,43 @@ 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); + } + + 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 +116,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 +128,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 @@ -261,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)); @@ -351,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_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 3046c069981..3cd47dfbb29 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 a9e0eadb198..530eba516a6 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 56eaffb1ca3..191c6605b43 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/Cargo.toml b/src/librustc_interface/Cargo.toml index fa2a5d2fc89..bcaa4216109 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 f8b1271b8b5..6d3115c6213 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -16,11 +16,13 @@ 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; +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,6 +1002,68 @@ fn analysis<'tcx>( Ok(()) } +fn encode_and_write_metadata<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + outputs: &OutputFilenames, +) -> (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 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) +} + /// Runs the codegen backend, after which the AST and analysis can /// be discarded. pub fn start_codegen<'tcx>( @@ -1013,11 +1078,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 and writing", || { + encode_and_write_metadata(tcx, outputs) }); 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/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index a8ebe85e251..ed42326d7d5 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 169d5652359..1d65a018dd6 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 89f85a941d3..c64d4b4a531 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 fd17d4a8125..e3ab48ccff1 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 86af2490408..0c2a4ef45f1 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, diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 4b8b3232bfa..681a204d76e 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 5ae052e46c5..2465adf46cd 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)) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index be68f303537..dcfe00069c5 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 { @@ -4174,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(), @@ -4192,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(), @@ -4219,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", @@ -4242,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/libstd/process.rs b/src/libstd/process.rs index c1addb46a0a..6e4c6e4c366 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 diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a20bf91a6ad..33b8c76bb53 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/error_codes.rs b/src/libsyntax/error_codes.rs index ac24475cab8..e2d212eb721 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/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 68cd3c28676..f5e18e98436 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 d3441a2039b..2e09235ca77 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/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs new file mode 100644 index 00000000000..32e1ee94f0d --- /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 1abc7832ffa..85a74df2357 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 8efe84cdf01..f70acb3e7da 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![]; @@ -8878,13 +8720,39 @@ 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 = ;` + // 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 +8760,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 +8779,25 @@ impl<'a> Parser<'a> { span, attrs: ThinVec::new(), source: LocalSource::AsyncFn, - }); - let stmt = Stmt { id, node: StmtKind::Local(local), span, }; + }; - arguments.push(AsyncArgument { ident, arg, stmt }); + // 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, + }) + }; + + 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-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index 5330470da16..4e43aa96e1d 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; diff --git a/src/test/run-pass/issue-54716.rs b/src/test/run-pass/issue-54716.rs deleted file mode 100644 index 961c412f5ec..00000000000 --- 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("_")]); -} diff --git a/src/test/ui/async-await/auxiliary/arc_wake.rs b/src/test/ui/async-await/auxiliary/arc_wake.rs new file mode 100644 index 00000000000..c21886f26f4 --- /dev/null +++ b/src/test/ui/async-await/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); +} diff --git a/src/test/ui/async-await/drop-order-for-async-fn-parameters.rs b/src/test/ui/async-await/drop-order-for-async-fn-parameters.rs new file mode 100644 index 00000000000..708c5704984 --- /dev/null +++ b/src/test/ui/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/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 00000000000..10dc5e27f6f --- /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 00000000000..ca0da6b7c96 --- /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/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/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/pub/pub-restricted.stderr b/src/test/ui/pub/pub-restricted.stderr index 044e5fc5188..7eeefa95505 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`.