From 4c8bf5028f31c0d82bbf46a50b2375131a488623 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 1 Apr 2020 13:26:01 +1100 Subject: [PATCH 01/22] Remove some dead code. The condition checks if `sess.opts.output_types` doesn't contain `OutputType::Assembly` within a match arm that is only reached if `sess.opts.output_types` contains `OutputType::Assembly`. --- src/librustc_codegen_ssa/back/write.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 35c5812e1f3bf..b23a8d7976fe1 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -414,13 +414,6 @@ pub fn start_async_codegen( } OutputType::Assembly => { modules_config.emit_asm = true; - // If we're not using the LLVM assembler, this function - // could be invoked specially with output_type_assembly, so - // in this case we still want the metadata object file. - if !sess.opts.output_types.contains_key(&OutputType::Assembly) { - metadata_config.emit_obj = emit_obj; - allocator_config.emit_obj = emit_obj; - } } OutputType::Object => { modules_config.emit_obj = emit_obj; From 72a28e85d77bab7f1073ad2224d536ae232cfc50 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 1 Apr 2020 12:13:57 +1100 Subject: [PATCH 02/22] Improve `ModuleConfig` initialization. There are three `ModuleConfigs`, one for each `ModuleKind`. The code to initialized them is spaghetti imperative code that sets each field to a default value and then modifies many fields in complicated ways. This makes it very hard to tell what value ends up in each field in each config. For example, the `modules_config.emit_pre_lto_bc` field is set twice, which means it can be set to true and then incorrectly set back to false. (This probably hasn't been noticed because it happens in a very obscure case.) This commit changes the code to a declarative style in which `ModuleConfig::new` initializes all fields and then they are never changed again. This is slightly more concise and much easier to read. (And it fixes the abovementioned `emit_pre_lto_bc` error as well.) --- src/librustc_codegen_ssa/back/write.rs | 289 ++++++++++++------------- 1 file changed, 137 insertions(+), 152 deletions(-) diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index b23a8d7976fe1..b06ad5b2f1c14 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -104,6 +104,7 @@ pub struct ModuleConfig { pub emit_ir: bool, pub emit_asm: bool, pub emit_obj: EmitObj, + // Miscellaneous flags. These are mostly copied from command-line // options. pub verify_llvm_ir: bool, @@ -118,77 +119,144 @@ pub struct ModuleConfig { } impl ModuleConfig { - fn new(passes: Vec) -> ModuleConfig { - ModuleConfig { - passes, - opt_level: None, - opt_size: None, - - pgo_gen: SwitchWithOptPath::Disabled, - pgo_use: None, - - sanitizer: None, - sanitizer_recover: Default::default(), - sanitizer_memory_track_origins: 0, - - emit_no_opt_bc: false, - emit_pre_lto_bc: false, - emit_bc: false, - emit_bc_compressed: false, - emit_ir: false, - emit_asm: false, - emit_obj: EmitObj::None, - - verify_llvm_ir: false, - no_prepopulate_passes: false, - no_builtins: false, - time_module: true, - vectorize_loop: false, - vectorize_slp: false, - merge_functions: false, - inline_threshold: None, - new_llvm_pass_manager: None, + fn new(kind: ModuleKind, sess: &Session, no_builtins: bool) -> ModuleConfig { + // If it's a regular module, use `$regular`, otherwise use `$other`. + // `$regular` and `$other` are evaluated lazily. + macro_rules! if_regular { + ($regular: expr, $other: expr) => { + if let ModuleKind::Regular = kind { $regular } else { $other } + }; } - } - fn set_flags(&mut self, sess: &Session, no_builtins: bool) { - self.verify_llvm_ir = sess.verify_llvm_ir(); - self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes; - self.no_builtins = no_builtins || sess.target.target.options.no_builtins; - self.inline_threshold = sess.opts.cg.inline_threshold; - self.new_llvm_pass_manager = sess.opts.debugging_opts.new_llvm_pass_manager; - - // Copy what clang does by turning on loop vectorization at O2 and - // slp vectorization at O3. Otherwise configure other optimization aspects - // of this pass manager builder. - self.vectorize_loop = !sess.opts.cg.no_vectorize_loops - && (sess.opts.optimize == config::OptLevel::Default - || sess.opts.optimize == config::OptLevel::Aggressive); - - self.vectorize_slp = - !sess.opts.cg.no_vectorize_slp && sess.opts.optimize == config::OptLevel::Aggressive; - - // Some targets (namely, NVPTX) interact badly with the MergeFunctions - // pass. This is because MergeFunctions can generate new function calls - // which may interfere with the target calling convention; e.g. for the - // NVPTX target, PTX kernels should not call other PTX kernels. - // MergeFunctions can also be configured to generate aliases instead, - // but aliases are not supported by some backends (again, NVPTX). - // Therefore, allow targets to opt out of the MergeFunctions pass, - // but otherwise keep the pass enabled (at O2 and O3) since it can be - // useful for reducing code size. - self.merge_functions = match sess - .opts - .debugging_opts - .merge_functions - .unwrap_or(sess.target.target.options.merge_functions) + let opt_level_and_size = if_regular!(Some(sess.opts.optimize), None); + + let save_temps = sess.opts.cg.save_temps; + + let should_emit_obj = sess.opts.output_types.contains_key(&OutputType::Exe) + || match kind { + ModuleKind::Regular => sess.opts.output_types.contains_key(&OutputType::Object), + ModuleKind::Allocator => false, + ModuleKind::Metadata => sess.opts.output_types.contains_key(&OutputType::Metadata), + }; + + let emit_obj = if !should_emit_obj { + EmitObj::None + } else if sess.target.target.options.obj_is_bitcode + || sess.opts.cg.linker_plugin_lto.enabled() { - MergeFunctions::Disabled => false, - MergeFunctions::Trampolines | MergeFunctions::Aliases => { - sess.opts.optimize == config::OptLevel::Default - || sess.opts.optimize == config::OptLevel::Aggressive + EmitObj::Bitcode + } else if sess.opts.debugging_opts.embed_bitcode { + match sess.opts.optimize { + config::OptLevel::No | config::OptLevel::Less => { + EmitObj::ObjectCode(BitcodeSection::Marker) + } + _ => EmitObj::ObjectCode(BitcodeSection::Full), } + } else { + EmitObj::ObjectCode(BitcodeSection::None) }; + + ModuleConfig { + passes: if_regular!( + { + let mut passes = sess.opts.cg.passes.clone(); + if sess.opts.debugging_opts.profile { + passes.push("insert-gcov-profiling".to_owned()); + } + passes + }, + vec![] + ), + + opt_level: opt_level_and_size, + opt_size: opt_level_and_size, + + pgo_gen: if_regular!( + sess.opts.cg.profile_generate.clone(), + SwitchWithOptPath::Disabled + ), + pgo_use: if_regular!(sess.opts.cg.profile_use.clone(), None), + + sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer.clone(), None), + sanitizer_recover: if_regular!( + sess.opts.debugging_opts.sanitizer_recover.clone(), + vec![] + ), + sanitizer_memory_track_origins: if_regular!( + sess.opts.debugging_opts.sanitizer_memory_track_origins, + 0 + ), + + emit_pre_lto_bc: if_regular!( + save_temps || need_pre_lto_bitcode_for_incr_comp(sess), + false + ), + emit_no_opt_bc: if_regular!(save_temps, false), + emit_bc: if_regular!( + save_temps || sess.opts.output_types.contains_key(&OutputType::Bitcode), + save_temps + ), + emit_bc_compressed: match kind { + ModuleKind::Regular | ModuleKind::Allocator => { + // Emit compressed bitcode files for the crate if we're + // emitting an rlib. Whenever an rlib is created, the + // bitcode is inserted into the archive in order to allow + // LTO against it. + need_crate_bitcode_for_rlib(sess) + } + ModuleKind::Metadata => false, + }, + emit_ir: if_regular!( + sess.opts.output_types.contains_key(&OutputType::LlvmAssembly), + false + ), + emit_asm: if_regular!( + sess.opts.output_types.contains_key(&OutputType::Assembly), + false + ), + emit_obj, + + verify_llvm_ir: sess.verify_llvm_ir(), + no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes, + no_builtins: no_builtins || sess.target.target.options.no_builtins, + + // Exclude metadata and allocator modules from time_passes output, + // since they throw off the "LLVM passes" measurement. + time_module: if_regular!(true, false), + + // Copy what clang does by turning on loop vectorization at O2 and + // slp vectorization at O3. + vectorize_loop: !sess.opts.cg.no_vectorize_loops + && (sess.opts.optimize == config::OptLevel::Default + || sess.opts.optimize == config::OptLevel::Aggressive), + vectorize_slp: !sess.opts.cg.no_vectorize_slp + && sess.opts.optimize == config::OptLevel::Aggressive, + + // Some targets (namely, NVPTX) interact badly with the + // MergeFunctions pass. This is because MergeFunctions can generate + // new function calls which may interfere with the target calling + // convention; e.g. for the NVPTX target, PTX kernels should not + // call other PTX kernels. MergeFunctions can also be configured to + // generate aliases instead, but aliases are not supported by some + // backends (again, NVPTX). Therefore, allow targets to opt out of + // the MergeFunctions pass, but otherwise keep the pass enabled (at + // O2 and O3) since it can be useful for reducing code size. + merge_functions: match sess + .opts + .debugging_opts + .merge_functions + .unwrap_or(sess.target.target.options.merge_functions) + { + MergeFunctions::Disabled => false, + MergeFunctions::Trampolines | MergeFunctions::Aliases => { + sess.opts.optimize == config::OptLevel::Default + || sess.opts.optimize == config::OptLevel::Aggressive + } + }, + + inline_threshold: sess.opts.cg.inline_threshold, + new_llvm_pass_manager: sess.opts.debugging_opts.new_llvm_pass_manager, + } } pub fn bitcode_needed(&self) -> bool { @@ -353,92 +421,9 @@ pub fn start_async_codegen( let linker_info = LinkerInfo::new(tcx); let crate_info = CrateInfo::new(tcx); - // Figure out what we actually need to build. - let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone()); - let mut metadata_config = ModuleConfig::new(vec![]); - let mut allocator_config = ModuleConfig::new(vec![]); - - if sess.opts.debugging_opts.profile { - modules_config.passes.push("insert-gcov-profiling".to_owned()) - } - - modules_config.pgo_gen = sess.opts.cg.profile_generate.clone(); - modules_config.pgo_use = sess.opts.cg.profile_use.clone(); - modules_config.sanitizer = sess.opts.debugging_opts.sanitizer.clone(); - modules_config.sanitizer_recover = sess.opts.debugging_opts.sanitizer_recover.clone(); - modules_config.sanitizer_memory_track_origins = - sess.opts.debugging_opts.sanitizer_memory_track_origins; - modules_config.opt_level = Some(sess.opts.optimize); - modules_config.opt_size = Some(sess.opts.optimize); - - // Save all versions of the bytecode if we're saving our temporaries. - if sess.opts.cg.save_temps { - modules_config.emit_no_opt_bc = true; - modules_config.emit_pre_lto_bc = true; - modules_config.emit_bc = true; - metadata_config.emit_bc = true; - allocator_config.emit_bc = true; - } - - // Emit compressed bitcode files for the crate if we're emitting an rlib. - // Whenever an rlib is created, the bitcode is inserted into the archive in - // order to allow LTO against it. - if need_crate_bitcode_for_rlib(sess) { - modules_config.emit_bc_compressed = true; - allocator_config.emit_bc_compressed = true; - } - - let emit_obj = - if sess.target.target.options.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled() { - EmitObj::Bitcode - } else if sess.opts.debugging_opts.embed_bitcode { - match sess.opts.optimize { - config::OptLevel::No | config::OptLevel::Less => { - EmitObj::ObjectCode(BitcodeSection::Marker) - } - _ => EmitObj::ObjectCode(BitcodeSection::Full), - } - } else { - EmitObj::ObjectCode(BitcodeSection::None) - }; - - modules_config.emit_pre_lto_bc = need_pre_lto_bitcode_for_incr_comp(sess); - - for output_type in sess.opts.output_types.keys() { - match *output_type { - OutputType::Bitcode => { - modules_config.emit_bc = true; - } - OutputType::LlvmAssembly => { - modules_config.emit_ir = true; - } - OutputType::Assembly => { - modules_config.emit_asm = true; - } - OutputType::Object => { - modules_config.emit_obj = emit_obj; - } - OutputType::Metadata => { - metadata_config.emit_obj = emit_obj; - } - OutputType::Exe => { - modules_config.emit_obj = emit_obj; - metadata_config.emit_obj = emit_obj; - allocator_config.emit_obj = emit_obj; - } - OutputType::Mir => {} - OutputType::DepInfo => {} - } - } - - modules_config.set_flags(sess, no_builtins); - metadata_config.set_flags(sess, no_builtins); - allocator_config.set_flags(sess, no_builtins); - - // Exclude metadata and allocator modules from time_passes output, since - // they throw off the "LLVM passes" measurement. - metadata_config.time_module = false; - allocator_config.time_module = false; + let modules_config = ModuleConfig::new(ModuleKind::Regular, sess, no_builtins); + let metadata_config = ModuleConfig::new(ModuleKind::Metadata, sess, no_builtins); + let allocator_config = ModuleConfig::new(ModuleKind::Allocator, sess, no_builtins); let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); let (codegen_worker_send, codegen_worker_receive) = channel(); From 5131c69dd67d9fc61d593803b252cf93ec369c18 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 1 Apr 2020 15:26:54 +1100 Subject: [PATCH 03/22] Rename `modules_config` as `regular_config`. That way it matches `ModuleKind::Regular`. --- src/librustc_codegen_ssa/back/write.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index b06ad5b2f1c14..91ba7ed5df3ca 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -421,7 +421,7 @@ pub fn start_async_codegen( let linker_info = LinkerInfo::new(tcx); let crate_info = CrateInfo::new(tcx); - let modules_config = ModuleConfig::new(ModuleKind::Regular, sess, no_builtins); + let regular_config = ModuleConfig::new(ModuleKind::Regular, sess, no_builtins); let metadata_config = ModuleConfig::new(ModuleKind::Metadata, sess, no_builtins); let allocator_config = ModuleConfig::new(ModuleKind::Allocator, sess, no_builtins); @@ -437,7 +437,7 @@ pub fn start_async_codegen( coordinator_receive, total_cgus, sess.jobserver.clone(), - Arc::new(modules_config), + Arc::new(regular_config), Arc::new(metadata_config), Arc::new(allocator_config), coordinator_send.clone(), @@ -937,7 +937,7 @@ fn start_executing_work( coordinator_receive: Receiver>, total_cgus: usize, jobserver: Client, - modules_config: Arc, + regular_config: Arc, metadata_config: Arc, allocator_config: Arc, tx_to_llvm_workers: Sender>, @@ -1020,7 +1020,7 @@ fn start_executing_work( coordinator_send, diag_emitter: shared_emitter.clone(), output_filenames: tcx.output_filenames(LOCAL_CRATE), - regular_module_config: modules_config, + regular_module_config: regular_config, metadata_module_config: metadata_config, allocator_module_config: allocator_config, tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol, false)), From b0ec96cc93d20a65e33927cd4627c284bc20aba7 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 24 Mar 2020 17:06:40 -0700 Subject: [PATCH 04/22] Use inner/outer generator naming instead of first/last I personally find this clearer. --- .../traits/error_reporting/suggestions.rs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 6a352602e266a..ae7d4aeeac366 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -126,8 +126,8 @@ crate trait InferCtxtExt<'tcx> { scope_span: &Option, expr: Option, snippet: String, - first_generator: DefId, - last_generator: Option, + inner_generator: DefId, + outer_generator: Option, trait_ref: ty::TraitRef<'_>, target_ty: Ty<'tcx>, tables: &ty::TypeckTables<'_>, @@ -1003,8 +1003,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // - `BindingObligation` with `impl_send (Send requirement) // // The first obligation in the chain is the most useful and has the generator that captured - // the type. The last generator has information about where the bound was introduced. At - // least one generator should be present for this diagnostic to be modified. + // the type. The last generator (`outer_generator` below) has information about where the + // bound was introduced. At least one generator should be present for this diagnostic to be + // modified. let (mut trait_ref, mut target_ty) = match obligation.predicate { ty::Predicate::Trait(p, _) => { (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty())) @@ -1012,7 +1013,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => (None, None), }; let mut generator = None; - let mut last_generator = None; + let mut outer_generator = None; let mut next_code = Some(&obligation.cause.code); while let Some(code) = next_code { debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code); @@ -1029,7 +1030,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { match ty.kind { ty::Generator(did, ..) => { generator = generator.or(Some(did)); - last_generator = Some(did); + outer_generator = Some(did); } ty::GeneratorWitness(..) => {} _ if generator.is_none() => { @@ -1133,7 +1134,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { *expr, snippet, generator_did, - last_generator, + outer_generator, trait_ref, target_ty, tables, @@ -1155,8 +1156,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { scope_span: &Option, expr: Option, snippet: String, - first_generator: DefId, - last_generator: Option, + inner_generator: DefId, + outer_generator: Option, trait_ref: ty::TraitRef<'_>, target_ty: Ty<'tcx>, tables: &ty::TypeckTables<'_>, @@ -1167,14 +1168,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let is_async_fn = self .tcx - .parent(first_generator) + .parent(inner_generator) .map(|parent_did| self.tcx.asyncness(parent_did)) .map(|parent_asyncness| parent_asyncness == hir::IsAsync::Async) .unwrap_or(false); let is_async_move = self .tcx .hir() - .as_local_hir_id(first_generator) + .as_local_hir_id(inner_generator) .and_then(|hir_id| self.tcx.hir().maybe_body_owned_by(hir_id)) .map(|body_id| self.tcx.hir().body(body_id)) .and_then(|body| body.generator_kind()) @@ -1203,7 +1204,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let original_span = err.span.primary_span().unwrap(); let mut span = MultiSpan::from_span(original_span); - let message = if let Some(name) = last_generator + let message = if let Some(name) = outer_generator .and_then(|generator_did| self.tcx.parent(generator_did)) .and_then(|parent_did| hir.as_local_hir_id(parent_did)) .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) From 0c97636326b0aec32b93206f9b6cee7777b02370 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 24 Mar 2020 17:23:50 -0700 Subject: [PATCH 05/22] Add test for #68112 (existing output) --- src/test/ui/async-await/issue-68112.rs | 53 ++++++++++++++++++++ src/test/ui/async-await/issue-68112.stderr | 45 +++++++++++++++++ src/test/ui/generator/issue-68112.rs | 56 ++++++++++++++++++++++ src/test/ui/generator/issue-68112.stderr | 40 ++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 src/test/ui/async-await/issue-68112.rs create mode 100644 src/test/ui/async-await/issue-68112.stderr create mode 100644 src/test/ui/generator/issue-68112.rs create mode 100644 src/test/ui/generator/issue-68112.stderr diff --git a/src/test/ui/async-await/issue-68112.rs b/src/test/ui/async-await/issue-68112.rs new file mode 100644 index 0000000000000..0d269b1801bac --- /dev/null +++ b/src/test/ui/async-await/issue-68112.rs @@ -0,0 +1,53 @@ +// edition:2018 + +use std::{ + future::Future, + cell::RefCell, + sync::Arc, + pin::Pin, + task::{Context, Poll}, +}; + +fn require_send(_: impl Send) {} + +struct Ready(Option); +impl Future for Ready { + type Output = T; + fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + Poll::Ready(self.0.take().unwrap()) + } +} +fn ready(t: T) -> Ready { + Ready(Some(t)) +} + +fn make_non_send_future1() -> impl Future>> { + ready(Arc::new(RefCell::new(0))) +} + +fn test1() { + let send_fut = async { + let non_send_fut = make_non_send_future1(); + let _ = non_send_fut.await; + ready(0).await; + }; + require_send(send_fut); + //~^ ERROR future cannot be sent between threads +} + +async fn ready2(t: T) -> T { t } +fn make_non_send_future2() -> impl Future>> { + ready2(Arc::new(RefCell::new(0))) +} + +fn test2() { + let send_fut = async { + let non_send_fut = make_non_send_future2(); + let _ = non_send_fut.await; + ready(0).await; + }; + require_send(send_fut); + //~^ ERROR `std::cell::RefCell` cannot be shared between threads safely +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr new file mode 100644 index 0000000000000..461967b7d8b2f --- /dev/null +++ b/src/test/ui/async-await/issue-68112.stderr @@ -0,0 +1,45 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-68112.rs:34:5 + | +LL | fn require_send(_: impl Send) {} + | ------------ ---- required by this bound in `require_send` +... +LL | require_send(send_fut); + | ^^^^^^^^^^^^ future returned by `test1` is not `Send` + | + = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` +note: future is not `Send` as this value is used across an await + --> $DIR/issue-68112.rs:32:9 + | +LL | let non_send_fut = make_non_send_future1(); + | ------------ has type `impl std::future::Future` +LL | let _ = non_send_fut.await; +LL | ready(0).await; + | ^^^^^^^^ await occurs here, with `non_send_fut` maybe used later +LL | }; + | - `non_send_fut` is later dropped here + +error[E0277]: `std::cell::RefCell` cannot be shared between threads safely + --> $DIR/issue-68112.rs:49:5 + | +LL | fn require_send(_: impl Send) {} + | ------------ ---- required by this bound in `require_send` +... +LL | require_send(send_fut); + | ^^^^^^^^^^^^ `std::cell::RefCell` cannot be shared between threads safely + | + = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` + = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc>` + = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:38:31: 38:36 t:std::sync::Arc> {}]` + = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:38:31: 38:36 t:std::sync::Arc> {}]>` + = note: required because it appears within the type `impl std::future::Future` + = note: required because it appears within the type `impl std::future::Future` + = note: required because it appears within the type `impl std::future::Future` + = note: required because it appears within the type `{std::future::ResumeTy, impl std::future::Future, (), i32, Ready}` + = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:44:26: 48:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]` + = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:44:26: 48:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]>` + = note: required because it appears within the type `impl std::future::Future` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generator/issue-68112.rs b/src/test/ui/generator/issue-68112.rs new file mode 100644 index 0000000000000..ee62cbff08f32 --- /dev/null +++ b/src/test/ui/generator/issue-68112.rs @@ -0,0 +1,56 @@ +#![feature(generators, generator_trait)] + +use std::{ + cell::RefCell, + sync::Arc, + pin::Pin, + ops::{Generator, GeneratorState}, +}; + +pub struct Ready(Option); +impl Generator<()> for Ready { + type Return = T; + type Yield = (); + fn resume(mut self: Pin<&mut Self>, _args: ()) -> GeneratorState<(), T> { + GeneratorState::Complete(self.0.take().unwrap()) + } +} +pub fn make_gen1(t: T) -> Ready { + Ready(Some(t)) +} + +fn require_send(_: impl Send) {} + +fn make_non_send_generator() -> impl Generator>> { + make_gen1(Arc::new(RefCell::new(0))) +} + +fn test1() { + let send_gen = || { + let _non_send_gen = make_non_send_generator(); + yield; + }; + require_send(send_gen); + //~^ ERROR future cannot be sent between threads +} + +pub fn make_gen2(t: T) -> impl Generator { + || { + yield; + t + } +} +fn make_non_send_generator2() -> impl Generator>> { + make_gen2(Arc::new(RefCell::new(0))) +} + +fn test2() { + let send_gen = || { + let _non_send_gen = make_non_send_generator2(); + yield; + }; + require_send(send_gen); + //~^ ERROR `std::cell::RefCell` cannot be shared between threads safely +} + +fn main() {} diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr new file mode 100644 index 0000000000000..b98afd47b566f --- /dev/null +++ b/src/test/ui/generator/issue-68112.stderr @@ -0,0 +1,40 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-68112.rs:33:5 + | +LL | fn require_send(_: impl Send) {} + | ------------ ---- required by this bound in `require_send` +... +LL | require_send(send_gen); + | ^^^^^^^^^^^^ future returned by `test1` is not `Send` + | + = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` +note: future is not `Send` as this value is used across an yield + --> $DIR/issue-68112.rs:31:9 + | +LL | let _non_send_gen = make_non_send_generator(); + | ------------- has type `impl std::ops::Generator` +LL | yield; + | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later +LL | }; + | - `_non_send_gen` is later dropped here + +error[E0277]: `std::cell::RefCell` cannot be shared between threads safely + --> $DIR/issue-68112.rs:52:5 + | +LL | fn require_send(_: impl Send) {} + | ------------ ---- required by this bound in `require_send` +... +LL | require_send(send_gen); + | ^^^^^^^^^^^^ `std::cell::RefCell` cannot be shared between threads safely + | + = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` + = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc>` + = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6 t:std::sync::Arc> {()}]` + = note: required because it appears within the type `impl std::ops::Generator` + = note: required because it appears within the type `impl std::ops::Generator` + = note: required because it appears within the type `{impl std::ops::Generator, ()}` + = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6 {impl std::ops::Generator, ()}]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From ce8331fd123f923730a2853c16fead308b17900d Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 24 Mar 2020 18:51:16 -0700 Subject: [PATCH 06/22] Improve span label --- .../traits/error_reporting/suggestions.rs | 28 ++++++++++++------- .../issue-64130-4-async-move.stderr | 2 +- .../issue-67252-unnamed-future.stderr | 2 +- src/test/ui/async-await/issue-68112.stderr | 2 +- .../issue-65436-raw-ptr-not-send.stderr | 2 +- src/test/ui/generator/issue-68112.stderr | 2 +- src/test/ui/generator/not-send-sync.stderr | 2 +- 7 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index ae7d4aeeac366..eb7c8f479aab1 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -10,7 +10,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::Node; +use rustc_hir::{GeneratorKind, AsyncGeneratorKind, Node}; use rustc_middle::ty::TypeckTables; use rustc_middle::ty::{ self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, @@ -1204,15 +1204,23 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let original_span = err.span.primary_span().unwrap(); let mut span = MultiSpan::from_span(original_span); - let message = if let Some(name) = outer_generator - .and_then(|generator_did| self.tcx.parent(generator_did)) - .and_then(|parent_did| hir.as_local_hir_id(parent_did)) - .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) - { - format!("future returned by `{}` is not {}", name, trait_name) - } else { - format!("future is not {}", trait_name) - }; + let message = outer_generator + .and_then(|generator_did| Some( + match self.tcx.generator_kind(generator_did).unwrap() { + GeneratorKind::Gen => format!("generator is not {}", trait_name), + GeneratorKind::Async(AsyncGeneratorKind::Fn) => + self.tcx.parent(generator_did) + .and_then(|parent_did| hir.as_local_hir_id(parent_did)) + .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) + .map(|name| format!("future returned by `{}` is not {}", + name, trait_name))?, + GeneratorKind::Async(AsyncGeneratorKind::Block) => + format!("future created by async block is not {}", trait_name), + GeneratorKind::Async(AsyncGeneratorKind::Closure) => + format!("future created by async closure is not {}", trait_name), + } + )) + .unwrap_or_else(|| format!("future is not {}", trait_name)); span.push_span_label(original_span, message); err.set_span(span); diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr index 1e52d74f1559c..edde947764afe 100644 --- a/src/test/ui/async-await/issue-64130-4-async-move.stderr +++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr @@ -2,7 +2,7 @@ error: future cannot be sent between threads safely --> $DIR/issue-64130-4-async-move.rs:15:17 | LL | pub fn foo() -> impl Future + Send { - | ^^^^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` + | ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` ... LL | / async move { LL | | match client.status() { diff --git a/src/test/ui/async-await/issue-67252-unnamed-future.stderr b/src/test/ui/async-await/issue-67252-unnamed-future.stderr index 24aedeb96597a..048f53467d528 100644 --- a/src/test/ui/async-await/issue-67252-unnamed-future.stderr +++ b/src/test/ui/async-await/issue-67252-unnamed-future.stderr @@ -5,7 +5,7 @@ LL | fn spawn(_: T) {} | ----- ---- required by this bound in `spawn` ... LL | spawn(async { - | ^^^^^ future is not `Send` + | ^^^^^ future created by async block is not `Send` | = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `*mut ()` note: future is not `Send` as this value is used across an await diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index 461967b7d8b2f..9f901901e207e 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -5,7 +5,7 @@ LL | fn require_send(_: impl Send) {} | ------------ ---- required by this bound in `require_send` ... LL | require_send(send_fut); - | ^^^^^^^^^^^^ future returned by `test1` is not `Send` + | ^^^^^^^^^^^^ future created by async block is not `Send` | = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` note: future is not `Send` as this value is used across an await diff --git a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr index 7638ba1fe7de8..d9b3c96c0b27b 100644 --- a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr +++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr @@ -5,7 +5,7 @@ LL | fn assert_send(_: T) {} | ----------- ---- required by this bound in `assert_send` ... LL | assert_send(async { - | ^^^^^^^^^^^ future returned by `main` is not `Send` + | ^^^^^^^^^^^ future created by async block is not `Send` | = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `*const u8` note: future is not `Send` as this value is used across an await diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr index b98afd47b566f..8950ff707d4aa 100644 --- a/src/test/ui/generator/issue-68112.stderr +++ b/src/test/ui/generator/issue-68112.stderr @@ -5,7 +5,7 @@ LL | fn require_send(_: impl Send) {} | ------------ ---- required by this bound in `require_send` ... LL | require_send(send_gen); - | ^^^^^^^^^^^^ future returned by `test1` is not `Send` + | ^^^^^^^^^^^^ generator is not `Send` | = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` note: future is not `Send` as this value is used across an yield diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index 0ac1d189b79b0..d340dc95519ca 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -18,7 +18,7 @@ LL | fn assert_sync(_: T) {} | ----------- ---- required by this bound in `main::assert_sync` ... LL | assert_sync(|| { - | ^^^^^^^^^^^ future returned by `main` is not `Sync` + | ^^^^^^^^^^^ generator is not `Sync` | = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` note: future is not `Sync` as this value is used across an yield From b73147861f0963aca93a75f4e8adfa20e91d60a7 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 24 Mar 2020 19:25:40 -0700 Subject: [PATCH 07/22] Don't annotate type when type is opaque --- .../traits/error_reporting/suggestions.rs | 7 ++++++- src/test/ui/async-await/async-fn-nonsend.stderr | 4 ++-- src/test/ui/async-await/issue-68112.stderr | 2 +- src/test/ui/generator/issue-68112.stderr | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index eb7c8f479aab1..09e7cd71fe783 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1238,7 +1238,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), ); - span.push_span_label(target_span, format!("has type `{}`", target_ty)); + if target_ty.is_impl_trait() { + // It's not very useful to tell the user the type if it's opaque. + span.push_span_label(target_span, "created here".to_string()); + } else { + span.push_span_label(target_span, format!("has type `{}`", target_ty)); + } // If available, use the scope span to annotate the drop location. if let Some(scope_span) = scope_span { diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr index 3a2c42b383700..ff28227d43352 100644 --- a/src/test/ui/async-await/async-fn-nonsend.stderr +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -12,7 +12,7 @@ note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:24:5 | LL | let x = non_send(); - | - has type `impl std::fmt::Debug` + | - created here LL | drop(x); LL | fut().await; | ^^^^^^^^^^^ await occurs here, with `x` maybe used later @@ -33,7 +33,7 @@ note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:33:20 | LL | match Some(non_send()) { - | ---------- has type `impl std::fmt::Debug` + | ---------- created here LL | Some(_) => fut().await, | ^^^^^^^^^^^ await occurs here, with `non_send()` maybe used later ... diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index 9f901901e207e..eec2171024ac4 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -12,7 +12,7 @@ note: future is not `Send` as this value is used across an await --> $DIR/issue-68112.rs:32:9 | LL | let non_send_fut = make_non_send_future1(); - | ------------ has type `impl std::future::Future` + | ------------ created here LL | let _ = non_send_fut.await; LL | ready(0).await; | ^^^^^^^^ await occurs here, with `non_send_fut` maybe used later diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr index 8950ff707d4aa..273fec082cf8d 100644 --- a/src/test/ui/generator/issue-68112.stderr +++ b/src/test/ui/generator/issue-68112.stderr @@ -12,7 +12,7 @@ note: future is not `Send` as this value is used across an yield --> $DIR/issue-68112.rs:31:9 | LL | let _non_send_gen = make_non_send_generator(); - | ------------- has type `impl std::ops::Generator` + | ------------- created here LL | yield; | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later LL | }; From 455537e028e8b1b30d3c06ea498c9622702a96ea Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 24 Mar 2020 21:13:05 -0700 Subject: [PATCH 08/22] Use "generator" instead of "future" when appropriate --- .../traits/error_reporting/suggestions.rs | 29 +++++++++---------- src/test/ui/generator/issue-68112.rs | 2 +- src/test/ui/generator/issue-68112.stderr | 4 +-- src/test/ui/generator/not-send-sync.rs | 2 +- src/test/ui/generator/not-send-sync.stderr | 4 +-- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 09e7cd71fe783..d42236afd2213 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1166,13 +1166,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) { let source_map = self.tcx.sess.source_map(); - let is_async_fn = self - .tcx - .parent(inner_generator) - .map(|parent_did| self.tcx.asyncness(parent_did)) - .map(|parent_asyncness| parent_asyncness == hir::IsAsync::Async) - .unwrap_or(false); - let is_async_move = self + let is_async = self .tcx .hir() .as_local_hir_id(inner_generator) @@ -1184,7 +1178,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => false, }) .unwrap_or(false); - let await_or_yield = if is_async_fn || is_async_move { "await" } else { "yield" }; + let await_or_yield = if is_async { "await" } else { "yield" }; + let future_or_generator = if is_async { "future" } else { "generator" }; // Special case the primary error message when send or sync is the trait that was // not implemented. @@ -1197,7 +1192,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.clear_code(); err.set_primary_message(format!( - "future cannot be {} between threads safely", + "{} cannot be {} between threads safely", + future_or_generator, trait_verb )); @@ -1220,14 +1216,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { format!("future created by async closure is not {}", trait_name), } )) - .unwrap_or_else(|| format!("future is not {}", trait_name)); + .unwrap_or_else(|| format!("{} is not {}", future_or_generator, trait_name)); span.push_span_label(original_span, message); err.set_span(span); - format!("is not {}", trait_name) + format!("{} is not {}", future_or_generator, trait_name) } else { - format!("does not implement `{}`", trait_ref.print_only_trait_path()) + format!( + "{} does not implement `{}`", + future_or_generator, + trait_ref.print_only_trait_path() + ) }; // Look at the last interior type to get a span for the `.await`. @@ -1255,10 +1255,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_note( span, - &format!( - "future {} as this value is used across an {}", - trait_explanation, await_or_yield, - ), + &format!("{} as this value is used across an {}", trait_explanation, await_or_yield), ); if let Some(expr_id) = expr { diff --git a/src/test/ui/generator/issue-68112.rs b/src/test/ui/generator/issue-68112.rs index ee62cbff08f32..9ab2abf740572 100644 --- a/src/test/ui/generator/issue-68112.rs +++ b/src/test/ui/generator/issue-68112.rs @@ -31,7 +31,7 @@ fn test1() { yield; }; require_send(send_gen); - //~^ ERROR future cannot be sent between threads + //~^ ERROR generator cannot be sent between threads } pub fn make_gen2(t: T) -> impl Generator { diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr index 273fec082cf8d..f40771d2826d6 100644 --- a/src/test/ui/generator/issue-68112.stderr +++ b/src/test/ui/generator/issue-68112.stderr @@ -1,4 +1,4 @@ -error: future cannot be sent between threads safely +error: generator cannot be sent between threads safely --> $DIR/issue-68112.rs:33:5 | LL | fn require_send(_: impl Send) {} @@ -8,7 +8,7 @@ LL | require_send(send_gen); | ^^^^^^^^^^^^ generator is not `Send` | = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` -note: future is not `Send` as this value is used across an yield +note: generator is not `Send` as this value is used across an yield --> $DIR/issue-68112.rs:31:9 | LL | let _non_send_gen = make_non_send_generator(); diff --git a/src/test/ui/generator/not-send-sync.rs b/src/test/ui/generator/not-send-sync.rs index 0db01c6f756ac..8ca5565fb2ab5 100644 --- a/src/test/ui/generator/not-send-sync.rs +++ b/src/test/ui/generator/not-send-sync.rs @@ -7,7 +7,7 @@ fn main() { fn assert_send(_: T) {} assert_sync(|| { - //~^ ERROR: future cannot be shared between threads safely + //~^ ERROR: generator cannot be shared between threads safely let a = Cell::new(2); yield; }); diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index d340dc95519ca..fe8b3b27fab1b 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -11,7 +11,7 @@ LL | assert_send(|| { = note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::Cell` = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 a:&std::cell::Cell _]` -error: future cannot be shared between threads safely +error: generator cannot be shared between threads safely --> $DIR/not-send-sync.rs:9:5 | LL | fn assert_sync(_: T) {} @@ -21,7 +21,7 @@ LL | assert_sync(|| { | ^^^^^^^^^^^ generator is not `Sync` | = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` -note: future is not `Sync` as this value is used across an yield +note: generator is not `Sync` as this value is used across an yield --> $DIR/not-send-sync.rs:12:9 | LL | let a = Cell::new(2); From 9862bbea8ae96d0e127be23fe8d4fdd9bad50649 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 1 Apr 2020 18:53:00 -0700 Subject: [PATCH 09/22] Use clearer message when obligation is caused by await expr --- src/librustc_ast_lowering/expr.rs | 4 +- src/librustc_hir/hir.rs | 15 +- .../traits/error_reporting/suggestions.rs | 142 +++++++++++++----- src/librustc_typeck/check/expr.rs | 2 +- src/test/ui/async-await/issue-68112.stderr | 9 +- 5 files changed, 126 insertions(+), 46 deletions(-) diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index 9984eb4e2825f..2fc58efbf0e7f 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -590,6 +590,7 @@ impl<'hir> LoweringContext<'_, 'hir> { await_span, self.allow_gen_future.clone(), ); + let expr = self.lower_expr(expr); let pinned_ident = Ident::with_dummy_span(sym::pinned); let (pinned_pat, pinned_pat_hid) = @@ -671,7 +672,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unit = self.expr_unit(span); let yield_expr = self.expr( span, - hir::ExprKind::Yield(unit, hir::YieldSource::Await), + hir::ExprKind::Yield(unit, hir::YieldSource::Await { expr: Some(expr.hir_id) }), ThinVec::new(), ); let yield_expr = self.arena.alloc(yield_expr); @@ -704,7 +705,6 @@ impl<'hir> LoweringContext<'_, 'hir> { // match { // mut pinned => loop { .. } // } - let expr = self.lower_expr(expr); hir::ExprKind::Match(expr, arena_vec![self; pinned_arm], hir::MatchSource::AwaitDesugar) } diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index b719d576d6f67..440fdc662862e 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -1736,15 +1736,24 @@ pub struct Destination { #[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)] pub enum YieldSource { /// An `.await`. - Await, + Await { expr: Option }, /// A plain `yield`. Yield, } +impl YieldSource { + pub fn is_await(&self) -> bool { + match self { + YieldSource::Await { .. } => true, + YieldSource::Yield => false, + } + } +} + impl fmt::Display for YieldSource { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { - YieldSource::Await => "`await`", + YieldSource::Await { .. } => "`await`", YieldSource::Yield => "`yield`", }) } @@ -1755,7 +1764,7 @@ impl From for YieldSource { match kind { // Guess based on the kind of the current generator. GeneratorKind::Gen => Self::Yield, - GeneratorKind::Async(_) => Self::Await, + GeneratorKind::Async(_) => Self::Await { expr: None }, } } } diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index d42236afd2213..7b25b47161e15 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -126,13 +126,14 @@ crate trait InferCtxtExt<'tcx> { scope_span: &Option, expr: Option, snippet: String, - inner_generator: DefId, + inner_generator_body: Option<&hir::Body<'_>>, outer_generator: Option, trait_ref: ty::TraitRef<'_>, target_ty: Ty<'tcx>, tables: &ty::TypeckTables<'_>, obligation: &PredicateObligation<'tcx>, next_code: Option<&ObligationCauseCode<'tcx>>, + from_awaited_ty: Option, ); fn note_obligation_cause_code( @@ -1088,6 +1089,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } }; + let generator_body = self.tcx + .hir() + .as_local_hir_id(generator_did) + .and_then(|hir_id| self.tcx.hir().maybe_body_owned_by(hir_id)) + .map(|body_id| self.tcx.hir().body(body_id)); + let mut visitor = AwaitsVisitor::default(); + if let Some(body) = generator_body { + visitor.visit_body(body); + } + debug!("maybe_note_obligation_cause_for_async_await: awaits = {:?}", visitor.awaits); + // Look for a type inside the generator interior that matches the target type to get // a span. let target_ty_erased = self.tcx.erase_regions(&target_ty); @@ -1117,8 +1129,26 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); eq }) - .map(|ty::GeneratorInteriorTypeCause { span, scope_span, expr, .. }| { - (span, source_map.span_to_snippet(*span), scope_span, expr) + .map(|cause| { + // Check to see if any awaited expressions have the target type. + let from_awaited_ty = visitor.awaits.into_iter() + .map(|id| self.tcx.hir().expect_expr(id)) + .find(|expr| { + let ty = tables.expr_ty_adjusted(&expr); + // Compare types using the same logic as above. + let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(ty)); + let ty_erased = self.tcx.erase_regions(&ty_erased); + let eq = ty::TyS::same_type(ty_erased, target_ty_erased); + debug!( + "maybe_note_obligation_cause_for_async_await: await_expr={:?} \ + await_ty_erased={:?} target_ty_erased={:?} eq={:?}", + expr, ty_erased, target_ty_erased, eq + ); + eq + }) + .map(|expr| expr.span); + let ty::GeneratorInteriorTypeCause { span, scope_span, expr, .. } = cause; + (span, source_map.span_to_snippet(*span), scope_span, expr, from_awaited_ty) }); debug!( @@ -1126,20 +1156,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { generator_interior_types={:?} target_span={:?}", target_ty, tables.generator_interior_types, target_span ); - if let Some((target_span, Ok(snippet), scope_span, expr)) = target_span { + if let Some((target_span, Ok(snippet), scope_span, expr, from_awaited_ty)) = target_span { self.note_obligation_cause_for_async_await( err, *target_span, scope_span, *expr, snippet, - generator_did, + generator_body, outer_generator, trait_ref, target_ty, tables, obligation, next_code, + from_awaited_ty, ); true } else { @@ -1156,22 +1187,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { scope_span: &Option, expr: Option, snippet: String, - inner_generator: DefId, + inner_generator_body: Option<&hir::Body<'_>>, outer_generator: Option, trait_ref: ty::TraitRef<'_>, target_ty: Ty<'tcx>, tables: &ty::TypeckTables<'_>, obligation: &PredicateObligation<'tcx>, next_code: Option<&ObligationCauseCode<'tcx>>, + from_awaited_ty: Option, ) { let source_map = self.tcx.sess.source_map(); - let is_async = self - .tcx - .hir() - .as_local_hir_id(inner_generator) - .and_then(|hir_id| self.tcx.hir().maybe_body_owned_by(hir_id)) - .map(|body_id| self.tcx.hir().body(body_id)) + let is_async = inner_generator_body .and_then(|body| body.generator_kind()) .map(|generator_kind| match generator_kind { hir::GeneratorKind::Async(..) => true, @@ -1230,33 +1257,57 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) }; - // Look at the last interior type to get a span for the `.await`. - let await_span = tables.generator_interior_types.iter().map(|t| t.span).last().unwrap(); - let mut span = MultiSpan::from_span(await_span); - span.push_span_label( - await_span, - format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), - ); + let push_target_span = |span: &mut MultiSpan| { + if target_ty.is_impl_trait() { + // It's not very useful to tell the user the type if it's opaque. + span.push_span_label(target_span, "created here".to_string()); + } else { + span.push_span_label(target_span, format!("has type `{}`", target_ty)); + } + }; - if target_ty.is_impl_trait() { - // It's not very useful to tell the user the type if it's opaque. - span.push_span_label(target_span, "created here".to_string()); - } else { - span.push_span_label(target_span, format!("has type `{}`", target_ty)); - } + if let Some(await_span) = from_awaited_ty { + // The type causing this obligation is one being awaited at await_span. + let mut span = MultiSpan::from_span(await_span); + span.push_span_label( + await_span, + "await occurs here".to_string(), + ); + + push_target_span(&mut span); - // If available, use the scope span to annotate the drop location. - if let Some(scope_span) = scope_span { + err.span_note( + span, + &format!("{} as this value is used in an await", trait_explanation), + ); + } else { + // Look at the last interior type to get a span for the `.await`. + debug!( + "note_obligation_cause_for_async_await generator_interior_types: {:#?}", + tables.generator_interior_types + ); + let await_span = tables.generator_interior_types.iter().map(|t| t.span).last().unwrap(); + let mut span = MultiSpan::from_span(await_span); span.push_span_label( - source_map.end_point(*scope_span), - format!("`{}` is later dropped here", snippet), + await_span, + format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), ); - } - err.span_note( - span, - &format!("{} as this value is used across an {}", trait_explanation, await_or_yield), - ); + push_target_span(&mut span); + + // If available, use the scope span to annotate the drop location. + if let Some(scope_span) = scope_span { + span.push_span_label( + source_map.end_point(*scope_span), + format!("`{}` is later dropped here", snippet), + ); + } + + err.span_note( + span, + &format!("{} as this value is used across an {}", trait_explanation, await_or_yield), + ); + } if let Some(expr_id) = expr { let expr = hir.expect_expr(expr_id); @@ -1593,3 +1644,26 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> { hir::intravisit::walk_body(self, body); } } + +/// Collect all the awaited expressions within the input expression. +#[derive(Default)] +struct AwaitsVisitor { + awaits: Vec, +} + +impl<'v> Visitor<'v> for AwaitsVisitor { + type Map = hir::intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { + hir::intravisit::NestedVisitorMap::None + } + + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + match ex.kind { + hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) => + self.awaits.push(id), + _ => (), + } + hir::intravisit::walk_expr(self, ex) + } +} diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index bfcb6fe35fe75..9ab4b0dbbfafb 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1797,7 +1797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we know that the yield type must be `()`; however, the context won't contain this // information. Hence, we check the source of the yield expression here and check its // value's type against `()` (this check should always hold). - None if src == &hir::YieldSource::Await => { + None if src.is_await() => { self.check_expr_coercable_to_type(&value, self.tcx.mk_unit()); self.tcx.mk_unit() } diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index eec2171024ac4..f79908110c4d4 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -8,16 +8,13 @@ LL | require_send(send_fut); | ^^^^^^^^^^^^ future created by async block is not `Send` | = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` -note: future is not `Send` as this value is used across an await - --> $DIR/issue-68112.rs:32:9 +note: future is not `Send` as this value is used in an await + --> $DIR/issue-68112.rs:31:17 | LL | let non_send_fut = make_non_send_future1(); | ------------ created here LL | let _ = non_send_fut.await; -LL | ready(0).await; - | ^^^^^^^^ await occurs here, with `non_send_fut` maybe used later -LL | }; - | - `non_send_fut` is later dropped here + | ^^^^^^^^^^^^ await occurs here error[E0277]: `std::cell::RefCell` cannot be shared between threads safely --> $DIR/issue-68112.rs:49:5 From cd501a619481add8979ade40f7ef86ffd66031ed Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 1 Apr 2020 19:04:55 -0700 Subject: [PATCH 10/22] Don't double-annotate the same Span --- .../traits/error_reporting/suggestions.rs | 4 ++- src/test/ui/async-await/issue-68112.rs | 9 ++++++ src/test/ui/async-await/issue-68112.stderr | 28 +++++++++++++++---- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 7b25b47161e15..b378120a833d4 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1274,7 +1274,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { "await occurs here".to_string(), ); - push_target_span(&mut span); + if target_span != await_span { + push_target_span(&mut span); + } err.span_note( span, diff --git a/src/test/ui/async-await/issue-68112.rs b/src/test/ui/async-await/issue-68112.rs index 0d269b1801bac..604cc51921e0e 100644 --- a/src/test/ui/async-await/issue-68112.rs +++ b/src/test/ui/async-await/issue-68112.rs @@ -35,6 +35,15 @@ fn test1() { //~^ ERROR future cannot be sent between threads } +fn test1_no_let() { + let send_fut = async { + let _ = make_non_send_future1().await; + ready(0).await; + }; + require_send(send_fut); + //~^ ERROR future cannot be sent between threads +} + async fn ready2(t: T) -> T { t } fn make_non_send_future2() -> impl Future>> { ready2(Arc::new(RefCell::new(0))) diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index f79908110c4d4..c0659bf944b81 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -16,8 +16,24 @@ LL | let non_send_fut = make_non_send_future1(); LL | let _ = non_send_fut.await; | ^^^^^^^^^^^^ await occurs here +error: future cannot be sent between threads safely + --> $DIR/issue-68112.rs:43:5 + | +LL | fn require_send(_: impl Send) {} + | ------------ ---- required by this bound in `require_send` +... +LL | require_send(send_fut); + | ^^^^^^^^^^^^ future created by async block is not `Send` + | + = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` +note: future is not `Send` as this value is used in an await + --> $DIR/issue-68112.rs:40:17 + | +LL | let _ = make_non_send_future1().await; + | ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here + error[E0277]: `std::cell::RefCell` cannot be shared between threads safely - --> $DIR/issue-68112.rs:49:5 + --> $DIR/issue-68112.rs:58:5 | LL | fn require_send(_: impl Send) {} | ------------ ---- required by this bound in `require_send` @@ -27,16 +43,16 @@ LL | require_send(send_fut); | = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc>` - = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:38:31: 38:36 t:std::sync::Arc> {}]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:38:31: 38:36 t:std::sync::Arc> {}]>` + = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36 t:std::sync::Arc> {}]` + = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36 t:std::sync::Arc> {}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `{std::future::ResumeTy, impl std::future::Future, (), i32, Ready}` - = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:44:26: 48:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:44:26: 48:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]>` + = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:53:26: 57:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]` + = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:53:26: 57:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]>` = note: required because it appears within the type `impl std::future::Future` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. From 4687b8d2d4504c8a2ae783c20b4e4dceed7aeadf Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 1 Apr 2020 19:14:51 -0700 Subject: [PATCH 11/22] rustfmt --- .../traits/error_reporting/suggestions.rs | 59 +++++++++++-------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index b378120a833d4..ae7cb94d8e1a4 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -10,7 +10,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{GeneratorKind, AsyncGeneratorKind, Node}; +use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; use rustc_middle::ty::TypeckTables; use rustc_middle::ty::{ self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, @@ -1089,7 +1089,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } }; - let generator_body = self.tcx + let generator_body = self + .tcx .hir() .as_local_hir_id(generator_did) .and_then(|hir_id| self.tcx.hir().maybe_body_owned_by(hir_id)) @@ -1131,7 +1132,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }) .map(|cause| { // Check to see if any awaited expressions have the target type. - let from_awaited_ty = visitor.awaits.into_iter() + let from_awaited_ty = visitor + .awaits + .into_iter() .map(|id| self.tcx.hir().expect_expr(id)) .find(|expr| { let ty = tables.expr_ty_adjusted(&expr); @@ -1220,29 +1223,32 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.clear_code(); err.set_primary_message(format!( "{} cannot be {} between threads safely", - future_or_generator, - trait_verb + future_or_generator, trait_verb )); let original_span = err.span.primary_span().unwrap(); let mut span = MultiSpan::from_span(original_span); let message = outer_generator - .and_then(|generator_did| Some( - match self.tcx.generator_kind(generator_did).unwrap() { + .and_then(|generator_did| { + Some(match self.tcx.generator_kind(generator_did).unwrap() { GeneratorKind::Gen => format!("generator is not {}", trait_name), - GeneratorKind::Async(AsyncGeneratorKind::Fn) => - self.tcx.parent(generator_did) - .and_then(|parent_did| hir.as_local_hir_id(parent_did)) - .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) - .map(|name| format!("future returned by `{}` is not {}", - name, trait_name))?, - GeneratorKind::Async(AsyncGeneratorKind::Block) => - format!("future created by async block is not {}", trait_name), - GeneratorKind::Async(AsyncGeneratorKind::Closure) => - format!("future created by async closure is not {}", trait_name), - } - )) + GeneratorKind::Async(AsyncGeneratorKind::Fn) => self + .tcx + .parent(generator_did) + .and_then(|parent_did| hir.as_local_hir_id(parent_did)) + .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) + .map(|name| { + format!("future returned by `{}` is not {}", name, trait_name) + })?, + GeneratorKind::Async(AsyncGeneratorKind::Block) => { + format!("future created by async block is not {}", trait_name) + } + GeneratorKind::Async(AsyncGeneratorKind::Closure) => { + format!("future created by async closure is not {}", trait_name) + } + }) + }) .unwrap_or_else(|| format!("{} is not {}", future_or_generator, trait_name)); span.push_span_label(original_span, message); @@ -1269,10 +1275,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(await_span) = from_awaited_ty { // The type causing this obligation is one being awaited at await_span. let mut span = MultiSpan::from_span(await_span); - span.push_span_label( - await_span, - "await occurs here".to_string(), - ); + span.push_span_label(await_span, "await occurs here".to_string()); if target_span != await_span { push_target_span(&mut span); @@ -1307,7 +1310,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_note( span, - &format!("{} as this value is used across an {}", trait_explanation, await_or_yield), + &format!( + "{} as this value is used across an {}", + trait_explanation, await_or_yield + ), ); } @@ -1662,8 +1668,9 @@ impl<'v> Visitor<'v> for AwaitsVisitor { fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { match ex.kind { - hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) => - self.awaits.push(id), + hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) => { + self.awaits.push(id) + } _ => (), } hir::intravisit::walk_expr(self, ex) From 9aeaaa2c8a3660fa489f3c013aab66745eb1a9cb Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 1 Apr 2020 19:54:11 -0700 Subject: [PATCH 12/22] Include type info when available for awaited expr --- .../traits/error_reporting/suggestions.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index ae7cb94d8e1a4..42c0cd8abb9b3 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1263,10 +1263,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) }; - let push_target_span = |span: &mut MultiSpan| { + let push_target_span_with_fallback = |span: &mut MultiSpan, fallback: &str| { if target_ty.is_impl_trait() { // It's not very useful to tell the user the type if it's opaque. - span.push_span_label(target_span, "created here".to_string()); + span.push_span_label(target_span, fallback.to_string()); } else { span.push_span_label(target_span, format!("has type `{}`", target_ty)); } @@ -1275,10 +1275,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(await_span) = from_awaited_ty { // The type causing this obligation is one being awaited at await_span. let mut span = MultiSpan::from_span(await_span); - span.push_span_label(await_span, "await occurs here".to_string()); - if target_span != await_span { - push_target_span(&mut span); + if target_span == await_span { + push_target_span_with_fallback(&mut span, "await occurs here"); + } else { + span.push_span_label(await_span, "await occurs here".to_string()); + push_target_span_with_fallback(&mut span, "created here"); } err.span_note( @@ -1298,7 +1300,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), ); - push_target_span(&mut span); + push_target_span_with_fallback(&mut span, "created here"); // If available, use the scope span to annotate the drop location. if let Some(scope_span) = scope_span { From 9dba024f6fa5f0428e3f9d469bdc2f31d8d2b037 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 7 Apr 2020 18:50:27 -0700 Subject: [PATCH 13/22] Fix style nits --- .../traits/error_reporting/suggestions.rs | 82 +++++++++---------- 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 42c0cd8abb9b3..ea0abedf6b298 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -980,6 +980,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation.predicate, obligation.cause.span ); let source_map = self.tcx.sess.source_map(); + let hir = self.tcx.hir(); // Attempt to detect an async-await error by looking at the obligation causes, looking // for a generator to be present. @@ -1063,7 +1064,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let span = self.tcx.def_span(generator_did); // Do not ICE on closure typeck (#66868). - if self.tcx.hir().as_local_hir_id(generator_did).is_none() { + if hir.as_local_hir_id(generator_did).is_none() { return false; } @@ -1089,12 +1090,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } }; - let generator_body = self - .tcx - .hir() + let generator_body = hir .as_local_hir_id(generator_did) - .and_then(|hir_id| self.tcx.hir().maybe_body_owned_by(hir_id)) - .map(|body_id| self.tcx.hir().body(body_id)); + .and_then(|hir_id| hir.maybe_body_owned_by(hir_id)) + .map(|body_id| hir.body(body_id)); let mut visitor = AwaitsVisitor::default(); if let Some(body) = generator_body { visitor.visit_body(body); @@ -1104,50 +1103,46 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Look for a type inside the generator interior that matches the target type to get // a span. let target_ty_erased = self.tcx.erase_regions(&target_ty); + let ty_matches = |ty| -> bool { + // Careful: the regions for types that appear in the + // generator interior are not generally known, so we + // want to erase them when comparing (and anyway, + // `Send` and other bounds are generally unaffected by + // the choice of region). When erasing regions, we + // also have to erase late-bound regions. This is + // because the types that appear in the generator + // interior generally contain "bound regions" to + // represent regions that are part of the suspended + // generator frame. Bound regions are preserved by + // `erase_regions` and so we must also call + // `erase_late_bound_regions`. + let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(ty)); + let ty_erased = self.tcx.erase_regions(&ty_erased); + let eq = ty::TyS::same_type(ty_erased, target_ty_erased); + debug!( + "maybe_note_obligation_cause_for_async_await: ty_erased={:?} \ + target_ty_erased={:?} eq={:?}", + ty_erased, target_ty_erased, eq + ); + eq + }; let target_span = tables .generator_interior_types .iter() - .find(|ty::GeneratorInteriorTypeCause { ty, .. }| { - // Careful: the regions for types that appear in the - // generator interior are not generally known, so we - // want to erase them when comparing (and anyway, - // `Send` and other bounds are generally unaffected by - // the choice of region). When erasing regions, we - // also have to erase late-bound regions. This is - // because the types that appear in the generator - // interior generally contain "bound regions" to - // represent regions that are part of the suspended - // generator frame. Bound regions are preserved by - // `erase_regions` and so we must also call - // `erase_late_bound_regions`. - let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(*ty)); - let ty_erased = self.tcx.erase_regions(&ty_erased); - let eq = ty::TyS::same_type(ty_erased, target_ty_erased); - debug!( - "maybe_note_obligation_cause_for_async_await: ty_erased={:?} \ - target_ty_erased={:?} eq={:?}", - ty_erased, target_ty_erased, eq - ); - eq - }) + .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty_matches(ty)) .map(|cause| { // Check to see if any awaited expressions have the target type. let from_awaited_ty = visitor .awaits .into_iter() - .map(|id| self.tcx.hir().expect_expr(id)) - .find(|expr| { - let ty = tables.expr_ty_adjusted(&expr); - // Compare types using the same logic as above. - let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(ty)); - let ty_erased = self.tcx.erase_regions(&ty_erased); - let eq = ty::TyS::same_type(ty_erased, target_ty_erased); + .map(|id| hir.expect_expr(id)) + .find(|await_expr| { + let ty = tables.expr_ty_adjusted(&await_expr); debug!( - "maybe_note_obligation_cause_for_async_await: await_expr={:?} \ - await_ty_erased={:?} target_ty_erased={:?} eq={:?}", - expr, ty_erased, target_ty_erased, eq + "maybe_note_obligation_cause_for_async_await: await_expr={:?}", + await_expr ); - eq + ty_matches(ty) }) .map(|expr| expr.span); let ty::GeneratorInteriorTypeCause { span, scope_span, expr, .. } = cause; @@ -1669,11 +1664,8 @@ impl<'v> Visitor<'v> for AwaitsVisitor { } fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - match ex.kind { - hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) => { - self.awaits.push(id) - } - _ => (), + if let hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) = ex.kind { + self.awaits.push(id) } hir::intravisit::walk_expr(self, ex) } From 889cfe1a33a3eb6c554f8ba71eb3c6d4fef62edb Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 8 Apr 2020 11:54:31 -0700 Subject: [PATCH 14/22] Incorporate feedback into diagnostics --- .../traits/error_reporting/suggestions.rs | 44 ++++++++----------- .../ui/async-await/async-fn-nonsend.stderr | 6 +-- .../ui/async-await/issue-64130-1-sync.stderr | 2 +- .../ui/async-await/issue-64130-2-send.stderr | 2 +- .../ui/async-await/issue-64130-3-other.stderr | 2 +- .../issue-64130-4-async-move.stderr | 2 +- .../issue-64130-non-send-future-diags.stderr | 2 +- .../issue-67252-unnamed-future.stderr | 2 +- src/test/ui/async-await/issue-68112.rs | 2 + src/test/ui/async-await/issue-68112.stderr | 16 +++---- .../issue-65436-raw-ptr-not-send.stderr | 2 +- src/test/ui/generator/issue-68112.stderr | 4 +- src/test/ui/generator/not-send-sync.stderr | 4 +- 13 files changed, 41 insertions(+), 49 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index ea0abedf6b298..8e9a39203be9e 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1203,7 +1203,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => false, }) .unwrap_or(false); - let await_or_yield = if is_async { "await" } else { "yield" }; + let (await_or_yield, an_await_or_yield) = + if is_async { ("await", "an await") } else { ("yield", "a yield") }; let future_or_generator = if is_async { "future" } else { "generator" }; // Special case the primary error message when send or sync is the trait that was @@ -1249,38 +1250,26 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span.push_span_label(original_span, message); err.set_span(span); - format!("{} is not {}", future_or_generator, trait_name) + format!("is not {}", trait_name) } else { - format!( - "{} does not implement `{}`", - future_or_generator, - trait_ref.print_only_trait_path() - ) - }; - - let push_target_span_with_fallback = |span: &mut MultiSpan, fallback: &str| { - if target_ty.is_impl_trait() { - // It's not very useful to tell the user the type if it's opaque. - span.push_span_label(target_span, fallback.to_string()); - } else { - span.push_span_label(target_span, format!("has type `{}`", target_ty)); - } + format!("does not implement `{}`", trait_ref.print_only_trait_path()) }; if let Some(await_span) = from_awaited_ty { // The type causing this obligation is one being awaited at await_span. let mut span = MultiSpan::from_span(await_span); - if target_span == await_span { - push_target_span_with_fallback(&mut span, "await occurs here"); - } else { - span.push_span_label(await_span, "await occurs here".to_string()); - push_target_span_with_fallback(&mut span, "created here"); - } + span.push_span_label( + await_span, + format!("await occurs here on type `{}`, which {}", target_ty, trait_explanation), + ); err.span_note( span, - &format!("{} as this value is used in an await", trait_explanation), + &format!( + "future {not_trait} as it awaits another future which {not_trait}", + not_trait = trait_explanation + ), ); } else { // Look at the last interior type to get a span for the `.await`. @@ -1295,7 +1284,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), ); - push_target_span_with_fallback(&mut span, "created here"); + span.push_span_label( + target_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); // If available, use the scope span to annotate the drop location. if let Some(scope_span) = scope_span { @@ -1308,8 +1300,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_note( span, &format!( - "{} as this value is used across an {}", - trait_explanation, await_or_yield + "{} {} as this value is used across {}", + future_or_generator, trait_explanation, an_await_or_yield ), ); } diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr index ff28227d43352..0c775e13827c3 100644 --- a/src/test/ui/async-await/async-fn-nonsend.stderr +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -12,7 +12,7 @@ note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:24:5 | LL | let x = non_send(); - | - created here + | - has type `impl std::fmt::Debug` which is not `Send` LL | drop(x); LL | fut().await; | ^^^^^^^^^^^ await occurs here, with `x` maybe used later @@ -33,7 +33,7 @@ note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:33:20 | LL | match Some(non_send()) { - | ---------- created here + | ---------- has type `impl std::fmt::Debug` which is not `Send` LL | Some(_) => fut().await, | ^^^^^^^^^^^ await occurs here, with `non_send()` maybe used later ... @@ -54,7 +54,7 @@ note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:42:9 | LL | let f: &mut std::fmt::Formatter = panic!(); - | - has type `&mut std::fmt::Formatter<'_>` + | - has type `&mut std::fmt::Formatter<'_>` which is not `Send` LL | if non_sync().fmt(f).unwrap() == () { LL | fut().await; | ^^^^^^^^^^^ await occurs here, with `f` maybe used later diff --git a/src/test/ui/async-await/issue-64130-1-sync.stderr b/src/test/ui/async-await/issue-64130-1-sync.stderr index 8beb31f152a9d..a854b0929d2d8 100644 --- a/src/test/ui/async-await/issue-64130-1-sync.stderr +++ b/src/test/ui/async-await/issue-64130-1-sync.stderr @@ -12,7 +12,7 @@ note: future is not `Sync` as this value is used across an await --> $DIR/issue-64130-1-sync.rs:15:5 | LL | let x = Foo; - | - has type `Foo` + | - has type `Foo` which is not `Sync` LL | baz().await; | ^^^^^^^^^^^ await occurs here, with `x` maybe used later LL | } diff --git a/src/test/ui/async-await/issue-64130-2-send.stderr b/src/test/ui/async-await/issue-64130-2-send.stderr index 823b88e18c5b6..b10b80683f56f 100644 --- a/src/test/ui/async-await/issue-64130-2-send.stderr +++ b/src/test/ui/async-await/issue-64130-2-send.stderr @@ -12,7 +12,7 @@ note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-2-send.rs:15:5 | LL | let x = Foo; - | - has type `Foo` + | - has type `Foo` which is not `Send` LL | baz().await; | ^^^^^^^^^^^ await occurs here, with `x` maybe used later LL | } diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr index 6456e7abd745d..61ffd77b69e26 100644 --- a/src/test/ui/async-await/issue-64130-3-other.stderr +++ b/src/test/ui/async-await/issue-64130-3-other.stderr @@ -16,7 +16,7 @@ note: future does not implement `Qux` as this value is used across an await --> $DIR/issue-64130-3-other.rs:18:5 | LL | let x = Foo; - | - has type `Foo` + | - has type `Foo` which does not implement `Qux` LL | baz().await; | ^^^^^^^^^^^ await occurs here, with `x` maybe used later LL | } diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr index edde947764afe..fc231d394c11f 100644 --- a/src/test/ui/async-await/issue-64130-4-async-move.stderr +++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr @@ -18,7 +18,7 @@ note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-4-async-move.rs:21:26 | LL | match client.status() { - | ------ has type `&Client` + | ------ has type `&Client` which is not `Send` LL | 200 => { LL | let _x = get().await; | ^^^^^^^^^^^ await occurs here, with `client` maybe used later diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr index 662407f7017f5..be2c4be67cbcc 100644 --- a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr @@ -12,7 +12,7 @@ note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-non-send-future-diags.rs:15:5 | LL | let g = x.lock().unwrap(); - | - has type `std::sync::MutexGuard<'_, u32>` + | - has type `std::sync::MutexGuard<'_, u32>` which is not `Send` LL | baz().await; | ^^^^^^^^^^^ await occurs here, with `g` maybe used later LL | } diff --git a/src/test/ui/async-await/issue-67252-unnamed-future.stderr b/src/test/ui/async-await/issue-67252-unnamed-future.stderr index 048f53467d528..989e1c6ee4f3d 100644 --- a/src/test/ui/async-await/issue-67252-unnamed-future.stderr +++ b/src/test/ui/async-await/issue-67252-unnamed-future.stderr @@ -12,7 +12,7 @@ note: future is not `Send` as this value is used across an await --> $DIR/issue-67252-unnamed-future.rs:20:9 | LL | let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send` - | -- has type `*mut ()` + | -- has type `*mut ()` which is not `Send` LL | AFuture.await; | ^^^^^^^^^^^^^ await occurs here, with `_a` maybe used later LL | }); diff --git a/src/test/ui/async-await/issue-68112.rs b/src/test/ui/async-await/issue-68112.rs index 604cc51921e0e..11b1783680807 100644 --- a/src/test/ui/async-await/issue-68112.rs +++ b/src/test/ui/async-await/issue-68112.rs @@ -49,6 +49,8 @@ fn make_non_send_future2() -> impl Future>> { ready2(Arc::new(RefCell::new(0))) } +// Ideally this test would have diagnostics similar to the test above, but right +// now it doesn't. fn test2() { let send_fut = async { let non_send_fut = make_non_send_future2(); diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index c0659bf944b81..78462868ede53 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -8,13 +8,11 @@ LL | require_send(send_fut); | ^^^^^^^^^^^^ future created by async block is not `Send` | = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` -note: future is not `Send` as this value is used in an await +note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:31:17 | -LL | let non_send_fut = make_non_send_future1(); - | ------------ created here LL | let _ = non_send_fut.await; - | ^^^^^^^^^^^^ await occurs here + | ^^^^^^^^^^^^ await occurs here on type `impl std::future::Future`, which is not `Send` error: future cannot be sent between threads safely --> $DIR/issue-68112.rs:43:5 @@ -26,14 +24,14 @@ LL | require_send(send_fut); | ^^^^^^^^^^^^ future created by async block is not `Send` | = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` -note: future is not `Send` as this value is used in an await +note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:40:17 | LL | let _ = make_non_send_future1().await; - | ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl std::future::Future`, which is not `Send` error[E0277]: `std::cell::RefCell` cannot be shared between threads safely - --> $DIR/issue-68112.rs:58:5 + --> $DIR/issue-68112.rs:60:5 | LL | fn require_send(_: impl Send) {} | ------------ ---- required by this bound in `require_send` @@ -49,8 +47,8 @@ LL | require_send(send_fut); = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `{std::future::ResumeTy, impl std::future::Future, (), i32, Ready}` - = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:53:26: 57:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:53:26: 57:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]>` + = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]` + = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]>` = note: required because it appears within the type `impl std::future::Future` error: aborting due to 3 previous errors diff --git a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr index d9b3c96c0b27b..40f3e394f77b7 100644 --- a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr +++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr @@ -14,7 +14,7 @@ note: future is not `Send` as this value is used across an await LL | bar(Foo(std::ptr::null())).await; | ^^^^^^^^----------------^^^^^^^^- `std::ptr::null()` is later dropped here | | | - | | has type `*const u8` + | | has type `*const u8` which is not `Send` | await occurs here, with `std::ptr::null()` maybe used later help: consider moving this into a `let` binding to create a shorter lived borrow --> $DIR/issue-65436-raw-ptr-not-send.rs:14:13 diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr index f40771d2826d6..4148b503ba858 100644 --- a/src/test/ui/generator/issue-68112.stderr +++ b/src/test/ui/generator/issue-68112.stderr @@ -8,11 +8,11 @@ LL | require_send(send_gen); | ^^^^^^^^^^^^ generator is not `Send` | = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` -note: generator is not `Send` as this value is used across an yield +note: generator is not `Send` as this value is used across a yield --> $DIR/issue-68112.rs:31:9 | LL | let _non_send_gen = make_non_send_generator(); - | ------------- created here + | ------------- has type `impl std::ops::Generator` which is not `Send` LL | yield; | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later LL | }; diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index fe8b3b27fab1b..fff170178fb0b 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -21,11 +21,11 @@ LL | assert_sync(|| { | ^^^^^^^^^^^ generator is not `Sync` | = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` -note: generator is not `Sync` as this value is used across an yield +note: generator is not `Sync` as this value is used across a yield --> $DIR/not-send-sync.rs:12:9 | LL | let a = Cell::new(2); - | - has type `std::cell::Cell` + | - has type `std::cell::Cell` which is not `Sync` LL | yield; | ^^^^^ yield occurs here, with `a` maybe used later LL | }); From 5aac1f3851c93b183cda3acf495aa19fa1b4f8df Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 10 Apr 2020 17:24:36 +0100 Subject: [PATCH 15/22] Update stdarch submodule to use llvm_asm! instead of asm! --- src/libcore/macros/mod.rs | 4 ++++ src/stdarch | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libcore/macros/mod.rs b/src/libcore/macros/mod.rs index 9c885ef99a980..79f2bdf752d74 100644 --- a/src/libcore/macros/mod.rs +++ b/src/libcore/macros/mod.rs @@ -1316,6 +1316,10 @@ pub(crate) mod builtin { issue = "70173", reason = "inline assembly is not stable enough for use and is subject to change" )] + #[rustc_deprecated( + since = "1.44.0", + reason = "the syntax of asm! will change soon, use llvm_asm! to avoid breakage" + )] #[rustc_builtin_macro] #[macro_export] macro_rules! asm { diff --git a/src/stdarch b/src/stdarch index 1a577bd78e84e..b00ecbeb268ee 160000 --- a/src/stdarch +++ b/src/stdarch @@ -1 +1 @@ -Subproject commit 1a577bd78e84e357e29c5336ff8beb432873046b +Subproject commit b00ecbeb268ee97cef9fa9b2375e6f6cf0864db2 From 921579cc3cdc57dbcfac48b275d92b7927234988 Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Fri, 10 Apr 2020 12:10:05 -0400 Subject: [PATCH 16/22] Add or_insert_with_key to Entry of HashMap/BTreeMap Going along with or_insert_with, or_insert_with_key provides the Entry's key to the lambda, avoiding the need to either clone the key or the need to reimplement this body of this method from scratch each time. This is useful when the initial value for a map entry is derived from the key. For example, the introductory Rust book has an example Cacher struct that takes an expensive-to-compute lambda and then can, given an argument to the lambda, produce either the cached result or execute the lambda. --- src/liballoc/collections/btree/map.rs | 27 +++++++++++++++++++++++++++ src/libstd/collections/hash/map.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index a1e59b2e6afb3..650582850ab96 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -2378,6 +2378,33 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { } } + #[unstable(feature = "or_insert_with_key", issue = "70996")] + /// Ensures a value is in the entry by inserting, if empty, the result of the default function, + /// which takes the key as its argument, and returns a mutable reference to the value in the + /// entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); + /// + /// assert_eq!(map["poneyland"], 9); + /// ``` + #[inline] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => { + let value = default(entry.key()); + entry.insert(value) + } + } + } + /// Returns a reference to this entry's key. /// /// # Examples diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index d1cb8e92d5688..277b37dd31043 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1943,6 +1943,33 @@ impl<'a, K, V> Entry<'a, K, V> { } } + #[unstable(feature = "or_insert_with_key", issue = "70996")] + /// Ensures a value is in the entry by inserting, if empty, the result of the default function, + /// which takes the key as its argument, and returns a mutable reference to the value in the + /// entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, usize> = HashMap::new(); + /// + /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); + /// + /// assert_eq!(map["poneyland"], 9); + /// ``` + #[inline] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => { + let value = default(entry.key()); + entry.insert(value) + } + } + } + /// Returns a reference to this entry's key. /// /// # Examples From 78102377d03b476ab39c9103c519afc9e5d79e01 Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Fri, 10 Apr 2020 13:39:35 -0400 Subject: [PATCH 17/22] Fixed doc tests for added methods --- src/liballoc/collections/btree/map.rs | 1 + src/libstd/collections/hash/map.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 650582850ab96..dd2f0fd4c0fb1 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -2386,6 +2386,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { /// # Examples /// /// ``` + /// #![feature(or_insert_with_key)] /// use std::collections::BTreeMap; /// /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 277b37dd31043..e1f2450645796 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1951,6 +1951,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// # Examples /// /// ``` + /// #![feature(or_insert_with_key)] /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, usize> = HashMap::new(); From 34d608d431e4ff32b4ff3cb321870492ab1d25d9 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 10 Apr 2020 17:31:31 +0100 Subject: [PATCH 18/22] Update parking_lot dependency to avoid use of deprecated asm! --- Cargo.lock | 24 ++++++++++++------------ src/librustc_query_system/Cargo.toml | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 908bfa355571b..03b47346b4be2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1747,7 +1747,7 @@ checksum = "5b31c9b90731276fdd24d896f31bb10aecf2e5151733364ae81123186643d939" dependencies = [ "jsonrpc-core", "log", - "parking_lot 0.10.0", + "parking_lot 0.10.2", "serde", ] @@ -1866,9 +1866,9 @@ checksum = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" [[package]] name = "lock_api" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" dependencies = [ "scopeguard", ] @@ -2406,12 +2406,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" +checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" dependencies = [ "lock_api", - "parking_lot_core 0.7.0", + "parking_lot_core 0.7.1", ] [[package]] @@ -2431,9 +2431,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" +checksum = "0e136c1904604defe99ce5fd71a28d473fa60a12255d511aa78a9ddf11237aeb" dependencies = [ "cfg-if", "cloudabi", @@ -3251,7 +3251,7 @@ dependencies = [ "lazy_static 1.4.0", "log", "measureme", - "parking_lot 0.10.0", + "parking_lot 0.10.2", "rustc-ap-graphviz", "rustc-ap-rustc_index", "rustc-ap-serialize", @@ -3696,7 +3696,7 @@ dependencies = [ "lazy_static 1.4.0", "log", "measureme", - "parking_lot 0.10.0", + "parking_lot 0.10.2", "rustc-hash", "rustc-rayon", "rustc-rayon-core", @@ -3991,7 +3991,7 @@ dependencies = [ "jobserver", "log", "measureme", - "parking_lot 0.10.0", + "parking_lot 0.10.2", "polonius-engine", "rustc-rayon", "rustc-rayon-core", @@ -4140,7 +4140,7 @@ name = "rustc_query_system" version = "0.0.0" dependencies = [ "log", - "parking_lot 0.9.0", + "parking_lot 0.10.2", "rustc-rayon-core", "rustc_data_structures", "rustc_errors", diff --git a/src/librustc_query_system/Cargo.toml b/src/librustc_query_system/Cargo.toml index e1657a8f3c607..7520da1f32bcd 100644 --- a/src/librustc_query_system/Cargo.toml +++ b/src/librustc_query_system/Cargo.toml @@ -18,5 +18,5 @@ rustc_index = { path = "../librustc_index" } rustc_macros = { path = "../librustc_macros" } rustc_serialize = { path = "../libserialize", package = "serialize" } rustc_span = { path = "../librustc_span" } -parking_lot = "0.9" +parking_lot = "0.10" smallvec = { version = "1.0", features = ["union", "may_dangle"] } From 43ee31f4aa711a92209c810e1e9f918e8bb56491 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 10 Apr 2020 17:34:30 +0100 Subject: [PATCH 19/22] Deprecate the asm! macro --- src/libcore/macros/mod.rs | 10 +++++++--- src/libcore/prelude/v1.rs | 1 + src/libstd/lib.rs | 1 + src/libstd/prelude/v1.rs | 1 + src/test/ui/feature-gates/feature-gate-asm.rs | 1 + src/test/ui/feature-gates/feature-gate-asm.stderr | 10 +++++++++- src/test/ui/feature-gates/feature-gate-asm2.rs | 1 + src/test/ui/feature-gates/feature-gate-asm2.stderr | 10 +++++++++- 8 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/libcore/macros/mod.rs b/src/libcore/macros/mod.rs index 79f2bdf752d74..73404a73e3d00 100644 --- a/src/libcore/macros/mod.rs +++ b/src/libcore/macros/mod.rs @@ -1316,9 +1316,13 @@ pub(crate) mod builtin { issue = "70173", reason = "inline assembly is not stable enough for use and is subject to change" )] - #[rustc_deprecated( - since = "1.44.0", - reason = "the syntax of asm! will change soon, use llvm_asm! to avoid breakage" + #[cfg_attr( + not(bootstrap), + rustc_deprecated( + since = "1.44.0", + reason = "the syntax of asm! will change soon, use llvm_asm! to avoid breakage", + suggestion = "llvm_asm", + ) )] #[rustc_builtin_macro] #[macro_export] diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index 9b4ed4e820512..6a51d39ab9d4e 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -54,6 +54,7 @@ pub use crate::fmt::macros::Debug; pub use crate::hash::macros::Hash; #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[allow(deprecated)] #[doc(no_inline)] pub use crate::{ asm, assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a9a519f0a3a71..dfb5177bf6725 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -523,6 +523,7 @@ pub use core::{ // Re-export built-in macros defined through libcore. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[allow(deprecated)] pub use core::{ asm, assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, format_args_nl, global_asm, include, include_bytes, include_str, line, llvm_asm, log_syntax, diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index 03686d789d721..92e3ea8485036 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -36,6 +36,7 @@ pub use crate::result::Result::{self, Err, Ok}; // Re-exported built-in macros #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[allow(deprecated)] #[doc(no_inline)] pub use core::prelude::v1::{ asm, assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, diff --git a/src/test/ui/feature-gates/feature-gate-asm.rs b/src/test/ui/feature-gates/feature-gate-asm.rs index 7eeeb4bc4e243..70f5845550d17 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.rs +++ b/src/test/ui/feature-gates/feature-gate-asm.rs @@ -3,6 +3,7 @@ fn main() { unsafe { asm!(""); //~ ERROR inline assembly is not stable enough + //~^ WARN use of deprecated item 'asm' llvm_asm!(""); //~ ERROR inline assembly is not stable enough } } diff --git a/src/test/ui/feature-gates/feature-gate-asm.stderr b/src/test/ui/feature-gates/feature-gate-asm.stderr index 1f9eaa5632e4a..516518b5200bf 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm.stderr @@ -8,7 +8,7 @@ LL | asm!(""); = help: add `#![feature(asm)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'llvm_asm': inline assembly is not stable enough for use and is subject to change - --> $DIR/feature-gate-asm.rs:6:9 + --> $DIR/feature-gate-asm.rs:7:9 | LL | llvm_asm!(""); | ^^^^^^^^ @@ -16,6 +16,14 @@ LL | llvm_asm!(""); = note: see issue #70173 for more information = help: add `#![feature(llvm_asm)]` to the crate attributes to enable +warning: use of deprecated item 'asm': the syntax of asm! will change soon, use llvm_asm! to avoid breakage + --> $DIR/feature-gate-asm.rs:5:9 + | +LL | asm!(""); + | ^^^ help: replace the use of the deprecated item: `llvm_asm` + | + = note: `#[warn(deprecated)]` on by default + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-asm2.rs b/src/test/ui/feature-gates/feature-gate-asm2.rs index 666a4894f6275..e3e86592a480a 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.rs +++ b/src/test/ui/feature-gates/feature-gate-asm2.rs @@ -3,6 +3,7 @@ fn main() { unsafe { println!("{:?}", asm!("")); //~ ERROR inline assembly is not stable + //~^ WARN use of deprecated item 'asm' println!("{:?}", llvm_asm!("")); //~ ERROR inline assembly is not stable } } diff --git a/src/test/ui/feature-gates/feature-gate-asm2.stderr b/src/test/ui/feature-gates/feature-gate-asm2.stderr index 17ba66e9842fa..43b5f7329652e 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm2.stderr @@ -8,7 +8,7 @@ LL | println!("{:?}", asm!("")); = help: add `#![feature(asm)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'llvm_asm': inline assembly is not stable enough for use and is subject to change - --> $DIR/feature-gate-asm2.rs:6:26 + --> $DIR/feature-gate-asm2.rs:7:26 | LL | println!("{:?}", llvm_asm!("")); | ^^^^^^^^ @@ -16,6 +16,14 @@ LL | println!("{:?}", llvm_asm!("")); = note: see issue #70173 for more information = help: add `#![feature(llvm_asm)]` to the crate attributes to enable +warning: use of deprecated item 'asm': the syntax of asm! will change soon, use llvm_asm! to avoid breakage + --> $DIR/feature-gate-asm2.rs:5:26 + | +LL | println!("{:?}", asm!("")); + | ^^^ help: replace the use of the deprecated item: `llvm_asm` + | + = note: `#[warn(deprecated)]` on by default + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From 7f4048c710249daafacdb6004da312e0681954f5 Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Sat, 11 Apr 2020 12:56:25 +0200 Subject: [PATCH 20/22] Store UNICODE_VERSION as a tuple Remove the UnicodeVersion struct containing major, minor and update fields and replace it with a 3-tuple containing the version number. As the value of each field is limited to 255 use u8 to store them. --- src/libcore/char/mod.rs | 2 -- src/libcore/unicode/mod.rs | 13 ++++--------- src/libcore/unicode/unicode_data.rs | 2 +- src/libcore/unicode/version.rs | 18 ------------------ src/test/ui/char_unicode.rs | 4 ++-- src/tools/unicode-table-generator/src/main.rs | 2 +- 6 files changed, 8 insertions(+), 33 deletions(-) delete mode 100644 src/libcore/unicode/version.rs diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index cf5576e549cdf..715ad8992ad6b 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -37,8 +37,6 @@ pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; // unstable re-exports #[unstable(feature = "unicode_version", issue = "49726")] -pub use crate::unicode::version::UnicodeVersion; -#[unstable(feature = "unicode_version", issue = "49726")] pub use crate::unicode::UNICODE_VERSION; use crate::fmt::{self, Write}; diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index 94a2507e26ccb..3952ae4482e9f 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -3,19 +3,14 @@ pub(crate) mod printable; mod unicode_data; -pub(crate) mod version; - -use version::UnicodeVersion; /// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of /// `char` and `str` methods are based on. +/// +/// The version numbering scheme is explained in +/// [Unicode 11.0 or later, Section 3.1 Versions of the Unicode Standard](https://www.unicode.org/versions/Unicode11.0.0/ch03.pdf#page=4). #[unstable(feature = "unicode_version", issue = "49726")] -pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { - major: unicode_data::UNICODE_VERSION.0, - minor: unicode_data::UNICODE_VERSION.1, - micro: unicode_data::UNICODE_VERSION.2, - _priv: (), -}; +pub const UNICODE_VERSION: (u8, u8, u8) = unicode_data::UNICODE_VERSION; // For use in liballoc, not re-exported in libstd. pub mod derived_property { diff --git a/src/libcore/unicode/unicode_data.rs b/src/libcore/unicode/unicode_data.rs index 48caa21fb0aa1..9c92a8ba28ae4 100644 --- a/src/libcore/unicode/unicode_data.rs +++ b/src/libcore/unicode/unicode_data.rs @@ -94,7 +94,7 @@ fn skip_search( offset_idx % 2 == 1 } -pub const UNICODE_VERSION: (u32, u32, u32) = (13, 0, 0); +pub const UNICODE_VERSION: (u8, u8, u8) = (13, 0, 0); #[rustfmt::skip] pub mod alphabetic { diff --git a/src/libcore/unicode/version.rs b/src/libcore/unicode/version.rs deleted file mode 100644 index 4d68d2e8c2ef7..0000000000000 --- a/src/libcore/unicode/version.rs +++ /dev/null @@ -1,18 +0,0 @@ -/// Represents a Unicode Version. -/// -/// See also: -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] -#[unstable(feature = "unicode_version", issue = "49726")] -pub struct UnicodeVersion { - /// Major version. - pub major: u32, - - /// Minor version. - pub minor: u32, - - /// Micro (or Update) version. - pub micro: u32, - - // Private field to keep struct expandable. - pub(crate) _priv: (), -} diff --git a/src/test/ui/char_unicode.rs b/src/test/ui/char_unicode.rs index 93e5300e36fe9..8d28f0080dd56 100644 --- a/src/test/ui/char_unicode.rs +++ b/src/test/ui/char_unicode.rs @@ -7,6 +7,6 @@ pub fn main() { check(std::char::UNICODE_VERSION); } -pub fn check(unicode_version: std::char::UnicodeVersion) { - assert!(unicode_version.major >= 10); +pub fn check(unicode_version: (u8, u8, u8)) { + assert!(unicode_version.0 >= 10); } diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs index d5562ff91df4d..6f73b172feae3 100644 --- a/src/tools/unicode-table-generator/src/main.rs +++ b/src/tools/unicode-table-generator/src/main.rs @@ -295,7 +295,7 @@ fn main() { fn version() -> String { let mut out = String::new(); - out.push_str("pub const UNICODE_VERSION: (u32, u32, u32) = "); + out.push_str("pub const UNICODE_VERSION: (u8, u8, u8) = "); let readme = std::fs::read_to_string(std::path::Path::new(UNICODE_DIRECTORY).join("ReadMe.txt")) From b78ff993fdbaba227f2fe7884ab1e6c0186514c7 Mon Sep 17 00:00:00 2001 From: robojumper Date: Sat, 11 Apr 2020 12:59:19 +0200 Subject: [PATCH 21/22] Use write!-style syntax for MIR assert terminator --- src/librustc_middle/mir/mod.rs | 19 ++++++++++++++++++- ...main.SimplifyCfg-elaborate-drops.after.mir | 2 +- ...main.SimplifyCfg-elaborate-drops.after.mir | 2 +- .../32bit/rustc.norm2.InstCombine.diff | 4 ++-- .../64bit/rustc.norm2.InstCombine.diff | 4 ++-- .../32bit/rustc.main.ConstProp.diff | 4 ++-- .../64bit/rustc.main.ConstProp.diff | 4 ++-- .../32bit/rustc.main.ConstProp.diff | 4 ++-- .../64bit/rustc.main.ConstProp.diff | 4 ++-- .../repeat/32bit/rustc.main.ConstProp.diff | 4 ++-- .../repeat/64bit/rustc.main.ConstProp.diff | 4 ++-- .../slice_len/32bit/rustc.main.ConstProp.diff | 4 ++-- .../slice_len/64bit/rustc.main.ConstProp.diff | 4 ++-- .../32bit/rustc.main.nll.0.mir | 2 +- .../64bit/rustc.main.nll.0.mir | 2 +- 15 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index b82008f429fa4..212061cfd824f 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -1403,6 +1403,21 @@ impl AssertKind { BoundsCheck { .. } => bug!("Unexpected AssertKind"), } } + + /// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing. + fn fmt_assert_args(&self, f: &mut W) -> fmt::Result + where + O: Debug, + { + match self { + AssertKind::BoundsCheck { ref len, ref index } => write!( + f, + "\"index out of bounds: the len is {{}} but the index is {{}}\", {:?}, {:?}", + len, index + ), + _ => write!(f, "\"{}\"", self.description()), + } + } } impl fmt::Debug for AssertKind { @@ -1480,7 +1495,9 @@ impl<'tcx> TerminatorKind<'tcx> { if !expected { write!(fmt, "!")?; } - write!(fmt, "{:?}, \"{:?}\")", cond, msg) + write!(fmt, "{:?}, ", cond)?; + msg.fmt_assert_args(fmt)?; + write!(fmt, ")") } FalseEdges { .. } => write!(fmt, "falseEdges"), FalseUnwind { .. } => write!(fmt, "falseUnwind"), diff --git a/src/test/mir-opt/array-index-is-temporary/32bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/array-index-is-temporary/32bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir index 052a335d00be6..0016cebbb4c06 100644 --- a/src/test/mir-opt/array-index-is-temporary/32bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/array-index-is-temporary/32bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir @@ -75,7 +75,7 @@ fn main() -> () { _7 = _2; // bb1[2]: scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8 _8 = Len(_1); // bb1[3]: scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 _9 = Lt(_7, _8); // bb1[4]: scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 - assert(move _9, "index out of bounds: the len is move _8 but the index is _7") -> bb2; // bb1[5]: scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // bb1[5]: scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 } bb2: { diff --git a/src/test/mir-opt/array-index-is-temporary/64bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/array-index-is-temporary/64bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir index e180f44969548..a004ab4a06aed 100644 --- a/src/test/mir-opt/array-index-is-temporary/64bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/array-index-is-temporary/64bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir @@ -75,7 +75,7 @@ fn main() -> () { _7 = _2; // bb1[2]: scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8 _8 = Len(_1); // bb1[3]: scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 _9 = Lt(_7, _8); // bb1[4]: scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 - assert(move _9, "index out of bounds: the len is move _8 but the index is _7") -> bb2; // bb1[5]: scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // bb1[5]: scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 } bb2: { diff --git a/src/test/mir-opt/combine_array_len/32bit/rustc.norm2.InstCombine.diff b/src/test/mir-opt/combine_array_len/32bit/rustc.norm2.InstCombine.diff index 7ec1c9ac637b3..1deeee0f61239 100644 --- a/src/test/mir-opt/combine_array_len/32bit/rustc.norm2.InstCombine.diff +++ b/src/test/mir-opt/combine_array_len/32bit/rustc.norm2.InstCombine.diff @@ -44,7 +44,7 @@ + // + span: $DIR/combine_array_len.rs:5:13: 5:17 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) } _5 = Lt(_3, _4); // bb0[4]: scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 - assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1; // bb0[5]: scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // bb0[5]: scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 } bb1: { @@ -68,7 +68,7 @@ + // + span: $DIR/combine_array_len.rs:6:13: 6:17 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) } _9 = Lt(_7, _8); // bb1[6]: scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 - assert(move _9, "index out of bounds: the len is move _8 but the index is _7") -> bb2; // bb1[7]: scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // bb1[7]: scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 } bb2: { diff --git a/src/test/mir-opt/combine_array_len/64bit/rustc.norm2.InstCombine.diff b/src/test/mir-opt/combine_array_len/64bit/rustc.norm2.InstCombine.diff index 0bab28738d8ac..7120829e2b54a 100644 --- a/src/test/mir-opt/combine_array_len/64bit/rustc.norm2.InstCombine.diff +++ b/src/test/mir-opt/combine_array_len/64bit/rustc.norm2.InstCombine.diff @@ -44,7 +44,7 @@ + // + span: $DIR/combine_array_len.rs:5:13: 5:17 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) } _5 = Lt(_3, _4); // bb0[4]: scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 - assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1; // bb0[5]: scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // bb0[5]: scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 } bb1: { @@ -68,7 +68,7 @@ + // + span: $DIR/combine_array_len.rs:6:13: 6:17 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) } _9 = Lt(_7, _8); // bb1[6]: scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 - assert(move _9, "index out of bounds: the len is move _8 but the index is _7") -> bb2; // bb1[7]: scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // bb1[7]: scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 } bb2: { diff --git a/src/test/mir-opt/const_prop/array_index/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/array_index/32bit/rustc.main.ConstProp.diff index f956ef82707bc..99d79b23e9e60 100644 --- a/src/test/mir-opt/const_prop/array_index/32bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/array_index/32bit/rustc.main.ConstProp.diff @@ -56,7 +56,7 @@ // + span: $DIR/array_index.rs:5:18: 5:33 // + literal: Const { ty: usize, val: Value(Scalar(0x00000004)) } - _5 = Lt(_3, _4); // bb0[6]: scope 0 at $DIR/array_index.rs:5:18: 5:33 -- assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1; // bb0[7]: scope 0 at $DIR/array_index.rs:5:18: 5:33 +- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // bb0[7]: scope 0 at $DIR/array_index.rs:5:18: 5:33 + _5 = const true; // bb0[6]: scope 0 at $DIR/array_index.rs:5:18: 5:33 + // ty::Const + // + ty: bool @@ -64,7 +64,7 @@ + // mir::Constant + // + span: $DIR/array_index.rs:5:18: 5:33 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } -+ assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1; // bb0[7]: scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ assert(const true, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // bb0[7]: scope 0 at $DIR/array_index.rs:5:18: 5:33 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) diff --git a/src/test/mir-opt/const_prop/array_index/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/array_index/64bit/rustc.main.ConstProp.diff index c336d6e66ae4d..629ca226f2ad6 100644 --- a/src/test/mir-opt/const_prop/array_index/64bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/array_index/64bit/rustc.main.ConstProp.diff @@ -56,7 +56,7 @@ // + span: $DIR/array_index.rs:5:18: 5:33 // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000004)) } - _5 = Lt(_3, _4); // bb0[6]: scope 0 at $DIR/array_index.rs:5:18: 5:33 -- assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1; // bb0[7]: scope 0 at $DIR/array_index.rs:5:18: 5:33 +- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // bb0[7]: scope 0 at $DIR/array_index.rs:5:18: 5:33 + _5 = const true; // bb0[6]: scope 0 at $DIR/array_index.rs:5:18: 5:33 + // ty::Const + // + ty: bool @@ -64,7 +64,7 @@ + // mir::Constant + // + span: $DIR/array_index.rs:5:18: 5:33 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } -+ assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1; // bb0[7]: scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ assert(const true, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // bb0[7]: scope 0 at $DIR/array_index.rs:5:18: 5:33 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/optimizes_into_variable/32bit/rustc.main.ConstProp.diff index d8bd397d74a65..41ffedf06bc98 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable/32bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable/32bit/rustc.main.ConstProp.diff @@ -119,7 +119,7 @@ // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34 // + literal: Const { ty: usize, val: Value(Scalar(0x00000006)) } - _7 = Lt(_5, _6); // bb1[7]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 -- assert(move _7, "index out of bounds: the len is move _6 but the index is _5") -> bb2; // bb1[8]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 +- assert(move _7, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // bb1[8]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + _7 = const true; // bb1[7]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + // ty::Const + // + ty: bool @@ -127,7 +127,7 @@ + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } -+ assert(const true, "index out of bounds: the len is move _6 but the index is _5") -> bb2; // bb1[8]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ assert(const true, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // bb1[8]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/optimizes_into_variable/64bit/rustc.main.ConstProp.diff index 9e646e7336d80..fd3281f527372 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable/64bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/optimizes_into_variable/64bit/rustc.main.ConstProp.diff @@ -119,7 +119,7 @@ // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34 // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000006)) } - _7 = Lt(_5, _6); // bb1[7]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 -- assert(move _7, "index out of bounds: the len is move _6 but the index is _5") -> bb2; // bb1[8]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 +- assert(move _7, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // bb1[8]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + _7 = const true; // bb1[7]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + // ty::Const + // + ty: bool @@ -127,7 +127,7 @@ + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } -+ assert(const true, "index out of bounds: the len is move _6 but the index is _5") -> bb2; // bb1[8]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ assert(const true, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // bb1[8]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) diff --git a/src/test/mir-opt/const_prop/repeat/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/repeat/32bit/rustc.main.ConstProp.diff index dce98d88e3d92..9d62fa31a4565 100644 --- a/src/test/mir-opt/const_prop/repeat/32bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/repeat/32bit/rustc.main.ConstProp.diff @@ -40,7 +40,7 @@ // + span: $DIR/repeat.rs:6:18: 6:28 // + literal: Const { ty: usize, val: Value(Scalar(0x00000008)) } - _6 = Lt(_4, _5); // bb0[7]: scope 0 at $DIR/repeat.rs:6:18: 6:28 -- assert(move _6, "index out of bounds: the len is move _5 but the index is _4") -> bb1; // bb0[8]: scope 0 at $DIR/repeat.rs:6:18: 6:28 +- assert(move _6, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // bb0[8]: scope 0 at $DIR/repeat.rs:6:18: 6:28 + _6 = const true; // bb0[7]: scope 0 at $DIR/repeat.rs:6:18: 6:28 + // ty::Const + // + ty: bool @@ -48,7 +48,7 @@ + // mir::Constant + // + span: $DIR/repeat.rs:6:18: 6:28 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } -+ assert(const true, "index out of bounds: the len is move _5 but the index is _4") -> bb1; // bb0[8]: scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ assert(const true, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // bb0[8]: scope 0 at $DIR/repeat.rs:6:18: 6:28 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) diff --git a/src/test/mir-opt/const_prop/repeat/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/repeat/64bit/rustc.main.ConstProp.diff index c9e640291f2f5..cb84ee82cfea8 100644 --- a/src/test/mir-opt/const_prop/repeat/64bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/repeat/64bit/rustc.main.ConstProp.diff @@ -40,7 +40,7 @@ // + span: $DIR/repeat.rs:6:18: 6:28 // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000008)) } - _6 = Lt(_4, _5); // bb0[7]: scope 0 at $DIR/repeat.rs:6:18: 6:28 -- assert(move _6, "index out of bounds: the len is move _5 but the index is _4") -> bb1; // bb0[8]: scope 0 at $DIR/repeat.rs:6:18: 6:28 +- assert(move _6, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // bb0[8]: scope 0 at $DIR/repeat.rs:6:18: 6:28 + _6 = const true; // bb0[7]: scope 0 at $DIR/repeat.rs:6:18: 6:28 + // ty::Const + // + ty: bool @@ -48,7 +48,7 @@ + // mir::Constant + // + span: $DIR/repeat.rs:6:18: 6:28 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } -+ assert(const true, "index out of bounds: the len is move _5 but the index is _4") -> bb1; // bb0[8]: scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ assert(const true, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // bb0[8]: scope 0 at $DIR/repeat.rs:6:18: 6:28 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) diff --git a/src/test/mir-opt/const_prop/slice_len/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/slice_len/32bit/rustc.main.ConstProp.diff index 5f821078b75fd..dbb4171e7f0ed 100644 --- a/src/test/mir-opt/const_prop/slice_len/32bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/slice_len/32bit/rustc.main.ConstProp.diff @@ -39,7 +39,7 @@ // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) } - _7 = Len((*_2)); // bb0[11]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 - _8 = Lt(_6, _7); // bb0[12]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 -- assert(move _8, "index out of bounds: the len is move _7 but the index is _6") -> bb1; // bb0[13]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 +- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // bb0[13]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _7 = const 3usize; // bb0[11]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 + // ty::Const + // + ty: usize @@ -54,7 +54,7 @@ + // mir::Constant + // + span: $DIR/slice_len.rs:5:5: 5:33 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } -+ assert(const true, "index out of bounds: the len is move _7 but the index is _6") -> bb1; // bb0[13]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 ++ assert(const true, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // bb0[13]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) diff --git a/src/test/mir-opt/const_prop/slice_len/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/slice_len/64bit/rustc.main.ConstProp.diff index 46f98b7f0aef8..3c4415e055838 100644 --- a/src/test/mir-opt/const_prop/slice_len/64bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/slice_len/64bit/rustc.main.ConstProp.diff @@ -39,7 +39,7 @@ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) } - _7 = Len((*_2)); // bb0[11]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 - _8 = Lt(_6, _7); // bb0[12]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 -- assert(move _8, "index out of bounds: the len is move _7 but the index is _6") -> bb1; // bb0[13]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 +- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // bb0[13]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _7 = const 3usize; // bb0[11]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 + // ty::Const + // + ty: usize @@ -54,7 +54,7 @@ + // mir::Constant + // + span: $DIR/slice_len.rs:5:5: 5:33 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } -+ assert(const true, "index out of bounds: the len is move _7 but the index is _6") -> bb1; // bb0[13]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 ++ assert(const true, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // bb0[13]: scope 0 at $DIR/slice_len.rs:5:5: 5:33 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) diff --git a/src/test/mir-opt/nll/region-subtyping-basic/32bit/rustc.main.nll.0.mir b/src/test/mir-opt/nll/region-subtyping-basic/32bit/rustc.main.nll.0.mir index f6ec2d925021e..1f75658aa265a 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic/32bit/rustc.main.nll.0.mir +++ b/src/test/mir-opt/nll/region-subtyping-basic/32bit/rustc.main.nll.0.mir @@ -75,7 +75,7 @@ fn main() -> () { // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 - assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 + assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 } bb1 (cleanup): { diff --git a/src/test/mir-opt/nll/region-subtyping-basic/64bit/rustc.main.nll.0.mir b/src/test/mir-opt/nll/region-subtyping-basic/64bit/rustc.main.nll.0.mir index fa3a9a0e1222a..8305c3fe7c493 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic/64bit/rustc.main.nll.0.mir +++ b/src/test/mir-opt/nll/region-subtyping-basic/64bit/rustc.main.nll.0.mir @@ -75,7 +75,7 @@ fn main() -> () { // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 - assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 + assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:16:14: 16:18 } bb1 (cleanup): { From db0c39fba5d596e286238c21b11b9aa9e1701b5b Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Sat, 11 Apr 2020 08:46:12 -0400 Subject: [PATCH 22/22] Change issue number to point to tracking issue --- src/liballoc/collections/btree/map.rs | 2 +- src/libstd/collections/hash/map.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index dd2f0fd4c0fb1..a76525e6beaf1 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -2378,7 +2378,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { } } - #[unstable(feature = "or_insert_with_key", issue = "70996")] + #[unstable(feature = "or_insert_with_key", issue = "71024")] /// Ensures a value is in the entry by inserting, if empty, the result of the default function, /// which takes the key as its argument, and returns a mutable reference to the value in the /// entry. diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index e1f2450645796..706b388f78323 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1943,7 +1943,7 @@ impl<'a, K, V> Entry<'a, K, V> { } } - #[unstable(feature = "or_insert_with_key", issue = "70996")] + #[unstable(feature = "or_insert_with_key", issue = "71024")] /// Ensures a value is in the entry by inserting, if empty, the result of the default function, /// which takes the key as its argument, and returns a mutable reference to the value in the /// entry.