From 3f661d25f9ce3b5ac6139c8d8bf4614b55dca5be Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 11 May 2020 10:29:05 +0200 Subject: [PATCH 01/44] borrowck `DefId` -> `LocalDefId` --- .../diagnostics/conflict_errors.rs | 89 +++++++++---------- .../borrow_check/diagnostics/move_errors.rs | 2 +- .../diagnostics/mutability_errors.rs | 2 +- .../borrow_check/diagnostics/region_errors.rs | 2 +- .../borrow_check/diagnostics/region_name.rs | 9 +- src/librustc_mir/borrow_check/mod.rs | 14 ++- src/librustc_mir/borrow_check/nll.rs | 8 +- 7 files changed, 59 insertions(+), 67 deletions(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 5f1c0911da2bf..d0050f801fc6b 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -214,7 +214,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let generics = tcx.generics_of(self.mir_def_id); let param = generics.type_param(¶m_ty, tcx); if let Some(generics) = - tcx.hir().get_generics(tcx.closure_base_def_id(self.mir_def_id)) + tcx.hir().get_generics(tcx.closure_base_def_id(self.mir_def_id.to_def_id())) { suggest_constraining_type_param( tcx, @@ -865,49 +865,42 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("`{}` would have to be valid for `{}`...", name, region_name), ); - if let Some(def_id) = self.mir_def_id.as_local() { - let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(def_id); - err.span_label( - drop_span, - format!( - "...but `{}` will be dropped here, when the {} returns", - name, - self.infcx - .tcx - .hir() - .opt_name(fn_hir_id) - .map(|name| format!("function `{}`", name)) - .unwrap_or_else(|| { - match &self - .infcx - .tcx - .typeck_tables_of(def_id) - .node_type(fn_hir_id) - .kind - { - ty::Closure(..) => "enclosing closure", - ty::Generator(..) => "enclosing generator", - kind => bug!("expected closure or generator, found {:?}", kind), - } - .to_string() - }) - ), - ); + let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id); + err.span_label( + drop_span, + format!( + "...but `{}` will be dropped here, when the {} returns", + name, + self.infcx + .tcx + .hir() + .opt_name(fn_hir_id) + .map(|name| format!("function `{}`", name)) + .unwrap_or_else(|| { + match &self + .infcx + .tcx + .typeck_tables_of(self.mir_def_id) + .node_type(fn_hir_id) + .kind + { + ty::Closure(..) => "enclosing closure", + ty::Generator(..) => "enclosing generator", + kind => bug!("expected closure or generator, found {:?}", kind), + } + .to_string() + }) + ), + ); - err.note( - "functions cannot return a borrow to data owned within the function's scope, \ - functions can only return borrows to data passed as arguments", - ); - err.note( - "to learn more, visit ", - ); - } else { - err.span_label( - drop_span, - format!("...but `{}` dropped here while still borrowed", name), - ); - } + err.note( + "functions cannot return a borrow to data owned within the function's scope, \ + functions can only return borrows to data passed as arguments", + ); + err.note( + "to learn more, visit ", + ); if let BorrowExplanation::MustBeValidFor { .. } = explanation { } else { @@ -1237,7 +1230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> DiagnosticBuilder<'cx> { let tcx = self.infcx.tcx; - let (_, escapes_from) = tcx.article_and_description(self.mir_def_id); + let (_, escapes_from) = tcx.article_and_description(self.mir_def_id.to_def_id()); let mut err = borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from); @@ -1572,14 +1565,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> Option> { // Define a fallback for when we can't match a closure. let fallback = || { - let is_closure = self.infcx.tcx.is_closure(self.mir_def_id); + let is_closure = self.infcx.tcx.is_closure(self.mir_def_id.to_def_id()); if is_closure { None } else { let ty = self.infcx.tcx.type_of(self.mir_def_id); match ty.kind { - ty::FnDef(_, _) | ty::FnPtr(_) => self - .annotate_fn_sig(self.mir_def_id, self.infcx.tcx.fn_sig(self.mir_def_id)), + ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig( + self.mir_def_id.to_def_id(), + self.infcx.tcx.fn_sig(self.mir_def_id), + ), _ => None, } } diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs index 67254811ec52a..b49e4187fb810 100644 --- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs @@ -331,7 +331,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.cannot_move_out_of_interior_noncopy(span, ty, None) } ty::Closure(def_id, closure_substs) - if def_id == self.mir_def_id && upvar_field.is_some() => + if def_id.as_local() == Some(self.mir_def_id) && upvar_field.is_some() => { let closure_kind_ty = closure_substs.as_closure().kind_ty(); let closure_kind = closure_kind_ty.to_opt_closure_kind(); diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs index 402eac47c462b..e04ed8b83debd 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs @@ -492,7 +492,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.span_label(sp, format!("cannot {}", act)); let hir = self.infcx.tcx.hir(); - let closure_id = hir.as_local_hir_id(self.mir_def_id.expect_local()); + let closure_id = hir.as_local_hir_id(self.mir_def_id); let fn_call_id = hir.get_parent_node(closure_id); let node = hir.get(fn_call_id); let item_id = hir.get_parent_item(fn_call_id); diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 98c0542f9c0dc..f24d668739949 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -502,7 +502,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut diag = self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough"); - let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id); + let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id.to_def_id()); let fr_name = self.give_region_a_name(*fr).unwrap(); fr_name.highlight_region_name(&mut diag); diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs index 37e2e0475048d..aee825a811380 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs @@ -237,8 +237,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } ty::BoundRegion::BrEnv => { - let mir_hir_id = - self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id.expect_local()); + let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id); let def_ty = self.regioncx.universal_regions().defining_ty; if let DefiningTy::Closure(_, substs) = def_ty { @@ -324,7 +323,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { argument_ty: Ty<'tcx>, argument_index: usize, ) -> Option { - let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id.as_local()?); + let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id); let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?; let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?; match argument_hir_ty.kind { @@ -635,7 +634,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); let type_name = self.infcx.extract_type_name(&return_ty, Some(highlight)).0; - let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id.expect_local()); + let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id); let (return_span, mir_description) = match tcx.hir().get(mir_hir_id) { hir::Node::Expr(hir::Expr { @@ -687,7 +686,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); let type_name = self.infcx.extract_type_name(&yield_ty, Some(highlight)).0; - let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id.expect_local()); + let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id); let yield_span = match tcx.hir().get(mir_hir_id) { hir::Node::Expr(hir::Expr { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index d3ab7df817b38..baba3cb1babcc 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -4,10 +4,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; -use rustc_hir::{ - def_id::{DefId, LocalDefId}, - HirId, Node, -}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{HirId, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -174,7 +172,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut body = input_body.clone(); let mut promoted = input_promoted.clone(); let free_regions = - nll::replace_regions_in_mir(infcx, def_id.to_def_id(), param_env, &mut body, &mut promoted); + nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted); let body = &body; // no further changes let location_table = &LocationTable::new(&body); @@ -275,7 +273,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut promoted_mbcx = MirBorrowckCtxt { infcx, body: promoted_body, - mir_def_id: def_id.to_def_id(), + mir_def_id: def_id, move_data: &move_data, location_table: &LocationTable::new(promoted_body), movable_generator, @@ -307,7 +305,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut mbcx = MirBorrowckCtxt { infcx, body, - mir_def_id: def_id.to_def_id(), + mir_def_id: def_id, move_data: &mdpe.move_data, location_table, movable_generator, @@ -459,7 +457,7 @@ fn do_mir_borrowck<'a, 'tcx>( crate struct MirBorrowckCtxt<'cx, 'tcx> { crate infcx: &'cx InferCtxt<'cx, 'tcx>, body: &'cx Body<'tcx>, - mir_def_id: DefId, + mir_def_id: LocalDefId, move_data: &'cx MoveData<'tcx>, /// Map from MIR `Location` to `LocationIndex`; created diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index 29636a067092b..eb453c4bb7b3b 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::Diagnostic; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::{ @@ -58,7 +58,7 @@ crate struct NllOutput<'tcx> { /// `compute_regions`. pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, - def_id: DefId, + def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec>, @@ -66,12 +66,12 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( debug!("replace_regions_in_mir(def_id={:?})", def_id); // Compute named region information. This also renumbers the inputs/outputs. - let universal_regions = UniversalRegions::new(infcx, def_id.expect_local(), param_env); + let universal_regions = UniversalRegions::new(infcx, def_id, param_env); // Replace all remaining regions with fresh inference variables. renumber::renumber_mir(infcx, body, promoted); - let source = MirSource::item(def_id); + let source = MirSource::item(def_id.to_def_id()); mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(())); universal_regions From a8ed9aa9f016c60f5fa55326f1f6a30e2be9d83e Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 13 Apr 2020 21:41:45 +0800 Subject: [PATCH 02/44] impl From<[T; N]> for Box<[T]> Based on https://github.com/rust-lang/rust/pull/68692 --- src/liballoc/boxed.rs | 19 ++++++++++++++ .../alloc-traits-impls-length-32.rs | 4 +++ .../alloc-types-no-impls-length-33.rs | 2 ++ .../alloc-types-no-impls-length-33.stderr | 25 ++++++++++++++----- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8ef6090c743a9..8cc6f04c0653a 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -865,6 +865,25 @@ impl From> for Box<[u8]> { } } +#[stable(feature = "box_from_array", since = "1.45.0")] +impl From<[T; N]> for Box<[T]> +where + [T; N]: LengthAtMost32, +{ + /// Converts a `[T; N]` into a `Box<[T]>` + /// + /// This conversion moves the array to newly heap-allocated memory. + /// + /// # Examples + /// ```rust + /// let boxed: Box<[u8]> = Box::from([4, 2]); + /// println!("{:?}", boxed); + /// ``` + fn from(array: [T; N]) -> Box<[T]> { + box array + } +} + #[stable(feature = "boxed_slice_try_from", since = "1.43.0")] impl TryFrom> for Box<[T; N]> where diff --git a/src/test/ui/const-generics/array-impls/alloc-traits-impls-length-32.rs b/src/test/ui/const-generics/array-impls/alloc-traits-impls-length-32.rs index 0d0765e971d50..b4a083636b64f 100644 --- a/src/test/ui/const-generics/array-impls/alloc-traits-impls-length-32.rs +++ b/src/test/ui/const-generics/array-impls/alloc-traits-impls-length-32.rs @@ -18,6 +18,10 @@ pub fn yes_array_into_vec() -> Vec { [].into() } +pub fn yes_array_into_box() -> Box<[T]> { + [].into() +} + use std::collections::VecDeque; pub fn yes_vecdeque_partial_eq_array() -> impl PartialEq<[B; 32]> diff --git a/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.rs b/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.rs index 4b195f3a06edc..48cf21d489ada 100644 --- a/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.rs +++ b/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.rs @@ -12,6 +12,8 @@ pub fn no_box() { let boxed_array = >::try_from(boxed_slice); //~^ ERROR the trait bound `std::boxed::Box<[i32; 33]>: std::convert::From>` is not satisfied //~^^ ERROR the trait bound `std::boxed::Box<[i32; 33]>: std::convert::TryFrom>` is not satisfied + let boxed_slice = >::from([0; 33]); + //~^ 15:42: 15:49: arrays only have std trait implementations for lengths 0..=32 [E0277] } pub fn no_rc() { diff --git a/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr index ce1c9ae551ea5..5c01603ab881c 100644 --- a/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr +++ b/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr @@ -18,10 +18,23 @@ LL | let boxed_array = >::try_from(boxed_slice); as std::convert::From<&str>> as std::convert::From>> as std::convert::From> - and 21 others + and 22 others = note: required because of the requirements on the impl of `std::convert::Into>` for `std::boxed::Box<[i32]>` = note: required because of the requirements on the impl of `std::convert::TryFrom>` for `std::boxed::Box<[i32; 33]>` +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/alloc-types-no-impls-length-33.rs:15:42 + | +LL | let boxed_slice = >::from([0; 33]); + | ^^^^^^^ + | | + | expected an implementor of trait `std::convert::From<[{integer}; 33]>` + | help: consider borrowing here: `&[0; 33]` + | + = note: the trait bound `[i32; 33]: std::convert::From<[{integer}; 33]>` is not satisfied + = note: required because of the requirements on the impl of `std::convert::From<[i32; 33]>` for `std::boxed::Box<[i32]>` + = note: required by `std::convert::From::from` + error[E0277]: the trait bound `std::boxed::Box<[i32; 33]>: std::convert::TryFrom>` is not satisfied --> $DIR/alloc-types-no-impls-length-33.rs:12:23 | @@ -32,7 +45,7 @@ LL | let boxed_array = >::try_from(boxed_slice); as std::convert::TryFrom>> error[E0277]: the trait bound `std::rc::Rc<[i32; 33]>: std::convert::From>` is not satisfied - --> $DIR/alloc-types-no-impls-length-33.rs:19:23 + --> $DIR/alloc-types-no-impls-length-33.rs:21:23 | LL | let boxed_array = >::try_from(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From>` is not implemented for `std::rc::Rc<[i32; 33]>` @@ -47,7 +60,7 @@ LL | let boxed_array = >::try_from(boxed_slice); = note: required because of the requirements on the impl of `std::convert::TryFrom>` for `std::rc::Rc<[i32; 33]>` error[E0277]: the trait bound `std::rc::Rc<[i32; 33]>: std::convert::TryFrom>` is not satisfied - --> $DIR/alloc-types-no-impls-length-33.rs:19:23 + --> $DIR/alloc-types-no-impls-length-33.rs:21:23 | LL | let boxed_array = >::try_from(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom>` is not implemented for `std::rc::Rc<[i32; 33]>` @@ -56,7 +69,7 @@ LL | let boxed_array = >::try_from(boxed_slice); as std::convert::TryFrom>> error[E0277]: the trait bound `std::sync::Arc<[i32; 33]>: std::convert::From>` is not satisfied - --> $DIR/alloc-types-no-impls-length-33.rs:26:23 + --> $DIR/alloc-types-no-impls-length-33.rs:28:23 | LL | let boxed_array = >::try_from(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From>` is not implemented for `std::sync::Arc<[i32; 33]>` @@ -71,7 +84,7 @@ LL | let boxed_array = >::try_from(boxed_slice); = note: required because of the requirements on the impl of `std::convert::TryFrom>` for `std::sync::Arc<[i32; 33]>` error[E0277]: the trait bound `std::sync::Arc<[i32; 33]>: std::convert::TryFrom>` is not satisfied - --> $DIR/alloc-types-no-impls-length-33.rs:26:23 + --> $DIR/alloc-types-no-impls-length-33.rs:28:23 | LL | let boxed_array = >::try_from(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom>` is not implemented for `std::sync::Arc<[i32; 33]>` @@ -79,6 +92,6 @@ LL | let boxed_array = >::try_from(boxed_slice); = help: the following implementations were found: as std::convert::TryFrom>> -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0277`. From eccaa0186f8fa2a432bf612b74f18a319406134c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 2 May 2020 01:59:35 +0300 Subject: [PATCH 03/44] rustc_target: Add a target spec option for static-pie support --- src/librustc_codegen_ssa/back/link.rs | 7 ++++--- src/librustc_target/spec/mod.rs | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index d87b84f880a35..288a4a41e07f0 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1143,9 +1143,10 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { }; // Adjust the output kind to target capabilities. - let pic_exe_supported = sess.target.target.options.position_independent_executables; - let static_pic_exe_supported = false; // FIXME: Add this option to target specs. - let static_dylib_supported = sess.target.target.options.crt_static_allows_dylibs; + let opts = &sess.target.target.options; + let pic_exe_supported = opts.position_independent_executables; + let static_pic_exe_supported = opts.static_position_independent_executables; + let static_dylib_supported = opts.crt_static_allows_dylibs; match kind { LinkOutputKind::DynamicPicExe if !pic_exe_supported => LinkOutputKind::DynamicNoPicExe, LinkOutputKind::StaticPicExe if !static_pic_exe_supported => LinkOutputKind::StaticNoPicExe, diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 41c2f1d93d2c4..d92f5cdeab5a5 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -855,6 +855,8 @@ pub struct TargetOptions { /// the functions in the executable are not randomized and can be used /// during an exploit of a vulnerability in any code. pub position_independent_executables: bool, + /// Executables that are both statically linked and position-independent are supported. + pub static_position_independent_executables: bool, /// Determines if the target always requires using the PLT for indirect /// library calls or not. This controls the default value of the `-Z plt` flag. pub needs_plt: bool, @@ -1028,6 +1030,7 @@ impl Default for TargetOptions { has_rpath: false, no_default_libraries: true, position_independent_executables: false, + static_position_independent_executables: false, needs_plt: false, relro_level: RelroLevel::None, pre_link_objects: Default::default(), @@ -1432,6 +1435,7 @@ impl Target { key!(has_rpath, bool); key!(no_default_libraries, bool); key!(position_independent_executables, bool); + key!(static_position_independent_executables, bool); key!(needs_plt, bool); key!(relro_level, RelroLevel)?; key!(archive_format); @@ -1663,6 +1667,7 @@ impl ToJson for Target { target_option_val!(has_rpath); target_option_val!(no_default_libraries); target_option_val!(position_independent_executables); + target_option_val!(static_position_independent_executables); target_option_val!(needs_plt); target_option_val!(relro_level); target_option_val!(archive_format); From 96a466c3128945627c2f81ec13b8ae98be7c3749 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 2 May 2020 02:22:48 +0300 Subject: [PATCH 04/44] linker: Support `-static-pie` and `-static -shared` --- src/librustc_codegen_ssa/back/link.rs | 22 +-- src/librustc_codegen_ssa/back/linker.rs | 227 ++++++++++++------------ 2 files changed, 118 insertions(+), 131 deletions(-) diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 288a4a41e07f0..7addfd15f1cdd 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1530,16 +1530,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( } // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - // FIXME: Support `StaticPicExe` correctly. - match link_output_kind { - LinkOutputKind::DynamicPicExe | LinkOutputKind::StaticPicExe => { - cmd.position_independent_executable() - } - LinkOutputKind::DynamicNoPicExe | LinkOutputKind::StaticNoPicExe => { - cmd.no_position_independent_executable() - } - _ => {} - } + cmd.set_output_kind(link_output_kind, out_filename); // OBJECT-FILES-NO, AUDIT-ORDER add_relro_args(cmd, sess); @@ -1568,17 +1559,6 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( tmpdir, ); - // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - // FIXME: Merge with the previous `link_output_kind` match, - // and support `StaticPicExe` and `StaticDylib` correctly. - match link_output_kind { - LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => { - cmd.build_static_executable() - } - LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => cmd.build_dylib(out_filename), - _ => {} - } - // OBJECT-FILES-NO, AUDIT-ORDER if sess.opts.cg.profile_generate.enabled() { cmd.pgo_gen(); diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index ee5bcf4b9f58b..80d1f7006847d 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -17,7 +17,7 @@ use rustc_serialize::{json, Encoder}; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; use rustc_session::Session; use rustc_span::symbol::Symbol; -use rustc_target::spec::{LinkerFlavor, LldFlavor}; +use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor}; /// Disables non-English messages from localized linkers. /// Such messages may cause issues with text encoding on Windows (#35785) @@ -102,6 +102,7 @@ impl LinkerInfo { /// MSVC linker (e.g., `link.exe`) is being used. pub trait Linker { fn cmd(&mut self) -> &mut Command; + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); fn link_dylib(&mut self, lib: Symbol); fn link_rust_dylib(&mut self, lib: Symbol, path: &Path); fn link_framework(&mut self, framework: Symbol); @@ -114,8 +115,6 @@ pub trait Linker { fn output_filename(&mut self, path: &Path); fn add_object(&mut self, path: &Path); fn gc_sections(&mut self, keep_metadata: bool); - fn position_independent_executable(&mut self); - fn no_position_independent_executable(&mut self); fn full_relro(&mut self); fn partial_relro(&mut self); fn no_relro(&mut self); @@ -125,8 +124,6 @@ pub trait Linker { fn debuginfo(&mut self, strip: Strip); fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); - fn build_dylib(&mut self, out_filename: &Path); - fn build_static_executable(&mut self); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); fn subsystem(&mut self, subsystem: &str); fn group_start(&mut self); @@ -233,12 +230,94 @@ impl<'a> GccLinker<'a> { let target_cpu = self.target_cpu; self.linker_arg(&format!("-plugin-opt=mcpu={}", target_cpu)); } + + fn build_dylib(&mut self, out_filename: &Path) { + // On mac we need to tell the linker to let this library be rpathed + if self.sess.target.target.options.is_like_osx { + self.cmd.arg("-dynamiclib"); + self.linker_arg("-dylib"); + + // Note that the `osx_rpath_install_name` option here is a hack + // purely to support rustbuild right now, we should get a more + // principled solution at some point to force the compiler to pass + // the right `-Wl,-install_name` with an `@rpath` in it. + if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name { + self.linker_arg("-install_name"); + let mut v = OsString::from("@rpath/"); + v.push(out_filename.file_name().unwrap()); + self.linker_arg(&v); + } + } else { + self.cmd.arg("-shared"); + if self.sess.target.target.options.is_like_windows { + // The output filename already contains `dll_suffix` so + // the resulting import library will have a name in the + // form of libfoo.dll.a + let implib_name = + out_filename.file_name().and_then(|file| file.to_str()).map(|file| { + format!( + "{}{}{}", + self.sess.target.target.options.staticlib_prefix, + file, + self.sess.target.target.options.staticlib_suffix + ) + }); + if let Some(implib_name) = implib_name { + let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); + if let Some(implib) = implib { + self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap())); + } + } + } + } + } } impl<'a> Linker for GccLinker<'a> { fn cmd(&mut self) -> &mut Command { &mut self.cmd } + + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + match output_kind { + LinkOutputKind::DynamicNoPicExe => { + if !self.is_ld { + self.cmd.arg("-no-pie"); + } + } + LinkOutputKind::DynamicPicExe => { + // `-pie` works for both gcc wrapper and ld. + self.cmd.arg("-pie"); + } + LinkOutputKind::StaticNoPicExe => { + // `-static` works for both gcc wrapper and ld. + self.cmd.arg("-static"); + if !self.is_ld { + self.cmd.arg("-no-pie"); + } + } + LinkOutputKind::StaticPicExe => { + if !self.is_ld { + // Note that combination `-static -pie` doesn't work as expected + // for the gcc wrapper, `-static` in that case suppresses `-pie`. + self.cmd.arg("-static-pie"); + } else { + // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing + // a static pie, but currently passed because gcc and clang pass them. + // The former suppresses the `INTERP` ELF header specifying dynamic linker, + // which is otherwise implicitly injected by ld (but not lld). + // The latter doesn't change anything, only ensures that everything is pic. + self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); + } + } + LinkOutputKind::DynamicDylib => self.build_dylib(out_filename), + LinkOutputKind::StaticDylib => { + self.cmd.arg("-static"); + self.build_dylib(out_filename); + } + } + } + fn link_dylib(&mut self, lib: Symbol) { self.hint_dynamic(); self.cmd.arg(format!("-l{}", lib)); @@ -263,14 +342,6 @@ impl<'a> Linker for GccLinker<'a> { fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } - fn position_independent_executable(&mut self) { - self.cmd.arg("-pie"); - } - fn no_position_independent_executable(&mut self) { - if !self.is_ld { - self.cmd.arg("-no-pie"); - } - } fn full_relro(&mut self) { self.linker_arg("-zrelro"); self.linker_arg("-znow"); @@ -281,9 +352,6 @@ impl<'a> Linker for GccLinker<'a> { fn no_relro(&mut self) { self.linker_arg("-znorelro"); } - fn build_static_executable(&mut self) { - self.cmd.arg("-static"); - } fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { self.hint_dynamic(); @@ -419,47 +487,6 @@ impl<'a> Linker for GccLinker<'a> { } } - fn build_dylib(&mut self, out_filename: &Path) { - // On mac we need to tell the linker to let this library be rpathed - if self.sess.target.target.options.is_like_osx { - self.cmd.arg("-dynamiclib"); - self.linker_arg("-dylib"); - - // Note that the `osx_rpath_install_name` option here is a hack - // purely to support rustbuild right now, we should get a more - // principled solution at some point to force the compiler to pass - // the right `-Wl,-install_name` with an `@rpath` in it. - if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name { - self.linker_arg("-install_name"); - let mut v = OsString::from("@rpath/"); - v.push(out_filename.file_name().unwrap()); - self.linker_arg(&v); - } - } else { - self.cmd.arg("-shared"); - if self.sess.target.target.options.is_like_windows { - // The output filename already contains `dll_suffix` so - // the resulting import library will have a name in the - // form of libfoo.dll.a - let implib_name = - out_filename.file_name().and_then(|file| file.to_str()).map(|file| { - format!( - "{}{}{}", - self.sess.target.target.options.staticlib_prefix, - file, - self.sess.target.target.options.staticlib_suffix - ) - }); - if let Some(implib_name) = implib_name { - let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); - if let Some(implib) = implib { - self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap())); - } - } - } - } - } - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { // Symbol visibility in object files typically takes care of this. if crate_type == CrateType::Executable @@ -583,6 +610,22 @@ impl<'a> Linker for MsvcLinker<'a> { fn cmd(&mut self) -> &mut Command { &mut self.cmd } + + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + match output_kind { + LinkOutputKind::DynamicNoPicExe + | LinkOutputKind::DynamicPicExe + | LinkOutputKind::StaticNoPicExe + | LinkOutputKind::StaticPicExe => {} + LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { + self.cmd.arg("/DLL"); + let mut arg: OsString = "/IMPLIB:".into(); + arg.push(out_filename.with_extension("dll.lib")); + self.cmd.arg(arg); + } + } + } + fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); } @@ -590,17 +633,6 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg(path); } - fn build_dylib(&mut self, out_filename: &Path) { - self.cmd.arg("/DLL"); - let mut arg: OsString = "/IMPLIB:".into(); - arg.push(out_filename.with_extension("dll.lib")); - self.cmd.arg(arg); - } - - fn build_static_executable(&mut self) { - // noop - } - fn gc_sections(&mut self, _keep_metadata: bool) { // MSVC's ICF (Identical COMDAT Folding) link optimization is // slow for Rust and thus we disable it by default when not in @@ -633,14 +665,6 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg(&format!("{}.lib", lib)); } - fn position_independent_executable(&mut self) { - // noop - } - - fn no_position_independent_executable(&mut self) { - // noop - } - fn full_relro(&mut self) { // noop } @@ -818,6 +842,9 @@ impl<'a> Linker for EmLinker<'a> { fn cmd(&mut self) -> &mut Command { &mut self.cmd } + + fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } @@ -857,14 +884,6 @@ impl<'a> Linker for EmLinker<'a> { self.add_object(lib); } - fn position_independent_executable(&mut self) { - // noop - } - - fn no_position_independent_executable(&mut self) { - // noop - } - fn full_relro(&mut self) { // noop } @@ -926,14 +945,6 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]); } - fn build_dylib(&mut self, _out_filename: &Path) { - bug!("building dynamic library is unsupported on Emscripten") - } - - fn build_static_executable(&mut self) { - // noop - } - fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { let symbols = &self.info.exports[&crate_type]; @@ -1032,6 +1043,18 @@ impl<'a> Linker for WasmLd<'a> { &mut self.cmd } + fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) { + match output_kind { + LinkOutputKind::DynamicNoPicExe + | LinkOutputKind::DynamicPicExe + | LinkOutputKind::StaticNoPicExe + | LinkOutputKind::StaticPicExe => {} + LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { + self.cmd.arg("--no-entry"); + } + } + } + fn link_dylib(&mut self, lib: Symbol) { self.cmd.arg("-l").sym_arg(lib); } @@ -1060,16 +1083,12 @@ impl<'a> Linker for WasmLd<'a> { self.cmd.arg(path); } - fn position_independent_executable(&mut self) {} - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} fn no_relro(&mut self) {} - fn build_static_executable(&mut self) {} - fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { self.cmd.arg("-l").sym_arg(lib); } @@ -1125,10 +1144,6 @@ impl<'a> Linker for WasmLd<'a> { fn no_default_libraries(&mut self) {} - fn build_dylib(&mut self, _out_filename: &Path) { - self.cmd.arg("--no-entry"); - } - fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { for sym in self.info.exports[&crate_type].iter() { self.cmd.arg("--export").arg(&sym); @@ -1144,8 +1159,6 @@ impl<'a> Linker for WasmLd<'a> { fn subsystem(&mut self, _subsystem: &str) {} - fn no_position_independent_executable(&mut self) {} - fn finalize(&mut self) {} // Not needed for now with LLD @@ -1208,6 +1221,8 @@ impl<'a> Linker for PtxLinker<'a> { &mut self.cmd } + fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn link_rlib(&mut self, path: &Path) { self.cmd.arg("--rlib").arg(path); } @@ -1274,16 +1289,12 @@ impl<'a> Linker for PtxLinker<'a> { panic!("frameworks not supported") } - fn position_independent_executable(&mut self) {} - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} fn no_relro(&mut self) {} - fn build_static_executable(&mut self) {} - fn gc_sections(&mut self, _keep_metadata: bool) {} fn pgo_gen(&mut self) {} @@ -1296,14 +1307,10 @@ impl<'a> Linker for PtxLinker<'a> { self.sess.warn("Windows Control Flow Guard is not supported by this linker."); } - fn build_dylib(&mut self, _out_filename: &Path) {} - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {} fn subsystem(&mut self, _subsystem: &str) {} - fn no_position_independent_executable(&mut self) {} - fn group_start(&mut self) {} fn group_end(&mut self) {} From 08df3116e92356311735be2d0c588d461e16fbff Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 24 Apr 2020 00:17:29 -0700 Subject: [PATCH 05/44] librustc_mir: Add support for const fn offset/arith_offset Miri's pointer_offset_inbounds implementation has been moved into librustc_mir as ptr_offset_inbounds (to avoid breaking miri on a nightly update). The comments have been slightly reworked to better match `offset`'s external documentation about what causes UB. The intrinsic implementations are taken directly from miri. Signed-off-by: Joe Richey --- src/librustc_mir/interpret/intrinsics.rs | 53 +++++++++++++++++++++++- src/librustc_span/symbol.rs | 2 + 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index fc4be82ad90ad..0db9c7026588d 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -10,11 +10,11 @@ use rustc_middle::mir::{ }; use rustc_middle::ty; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size}; -use super::{ImmTy, InterpCx, Machine, OpTy, PlaceTy}; +use super::{CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy}; mod caller_location; mod type_name; @@ -279,7 +279,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = Scalar::from_uint(truncated_bits, layout.size); self.write_scalar(result, dest)?; } + sym::offset => { + let ptr = self.read_scalar(args[0])?.not_undef()?; + let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?; + let pointee_ty = substs.type_at(0); + let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?; + self.write_scalar(offset_ptr, dest)?; + } + sym::arith_offset => { + let ptr = self.read_scalar(args[0])?.not_undef()?; + let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?; + let pointee_ty = substs.type_at(0); + + let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); + let offset_bytes = offset_count.wrapping_mul(pointee_size); + let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self); + self.write_scalar(offset_ptr, dest)?; + } sym::ptr_offset_from => { let a = self.read_immediate(args[0])?.to_scalar()?; let b = self.read_immediate(args[1])?.to_scalar()?; @@ -409,4 +426,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // `Rem` says this is all right, so we can let `Div` do its job. self.binop_ignore_overflow(BinOp::Div, a, b, dest) } + + /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its + /// allocation. For integer pointers, we consider each of them their own tiny allocation of size + /// 0, so offset-by-0 (and only 0) is okay -- except that NULL cannot be offset by _any_ value. + pub fn ptr_offset_inbounds( + &self, + ptr: Scalar, + pointee_ty: Ty<'tcx>, + offset_count: i64, + ) -> InterpResult<'tcx, Scalar> { + let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); + // The computed offset, in bytes, cannot overflow an isize. + let offset_bytes = offset_count + .checked_mul(pointee_size) + .ok_or(err_ub_format!("inbounds pointer arithmetic: overflow computing offset"))?; + // The offset being in bounds cannot rely on "wrapping around" the address space. + // So, first rule out overflows in the pointer arithmetic. + let offset_ptr = ptr.ptr_signed_offset(offset_bytes, self)?; + // ptr and offset_ptr must be in bounds of the same allocated object. This means all of the + // memory between these pointers must be accessible. Note that we do not require the + // pointers to be properly aligned (unlike a read/write operation). + let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr }; + let size = offset_bytes.checked_abs().unwrap(); + // This call handles checking for integer/NULL pointers. + self.memory.check_ptr_access_align( + min_ptr, + Size::from_bytes(size), + None, + CheckInAllocMsg::InboundsTest, + )?; + Ok(offset_ptr) + } } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 6a6098710e828..9b055beb99dfd 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -147,6 +147,7 @@ symbols! { Arc, Arguments, ArgumentV1, + arith_offset, arm_target_feature, asm, assert, @@ -516,6 +517,7 @@ symbols! { not, note, object_safe_for_dispatch, + offset, Ok, omit_gdb_pretty_printer_section, on, From 9b3dfd8ea987ce1d4b5ccbcb4c032f60a71c8cfb Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 24 Apr 2020 00:19:11 -0700 Subject: [PATCH 06/44] core: Make pointer offset methods "const fn" Signed-off-by: Joe Richey --- src/libcore/intrinsics.rs | 2 ++ src/libcore/lib.rs | 1 + src/libcore/ptr/const_ptr.rs | 18 ++++++++++++------ src/libcore/ptr/mut_ptr.rs | 18 ++++++++++++------ 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 9006e4cfaf7bb..2d97fecf8a766 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1314,6 +1314,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is /// [`std::pointer::offset`](../../std/primitive.pointer.html#method.offset). #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] pub fn offset(dst: *const T, offset: isize) -> *const T; /// Calculates the offset from a pointer, potentially wrapping. @@ -1331,6 +1332,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is /// [`std::pointer::wrapping_offset`](../../std/primitive.pointer.html#method.wrapping_offset). #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] pub fn arith_offset(dst: *const T, offset: isize) -> *const T; /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ca13433caec8d..7d21f9a9a66d0 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -85,6 +85,7 @@ #![feature(const_panic)] #![feature(const_fn_union)] #![feature(const_generics)] +#![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_result)] #![feature(const_slice_from_raw_parts)] diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index 85ba5fc0638ea..835183d171a79 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -151,8 +151,9 @@ impl *const T { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn offset(self, count: isize) -> *const T + pub const unsafe fn offset(self, count: isize) -> *const T where T: Sized, { @@ -210,8 +211,9 @@ impl *const T { /// ``` #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_offset(self, count: isize) -> *const T + pub const fn wrapping_offset(self, count: isize) -> *const T where T: Sized, { @@ -393,8 +395,9 @@ impl *const T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn add(self, count: usize) -> Self + pub const unsafe fn add(self, count: usize) -> Self where T: Sized, { @@ -455,8 +458,9 @@ impl *const T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn sub(self, count: usize) -> Self + pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, { @@ -511,8 +515,9 @@ impl *const T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_add(self, count: usize) -> Self + pub const fn wrapping_add(self, count: usize) -> Self where T: Sized, { @@ -567,8 +572,9 @@ impl *const T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_sub(self, count: usize) -> Self + pub const fn wrapping_sub(self, count: usize) -> Self where T: Sized, { diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index 0781d7e6cac45..40b5e4e22340e 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -145,8 +145,9 @@ impl *mut T { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn offset(self, count: isize) -> *mut T + pub const unsafe fn offset(self, count: isize) -> *mut T where T: Sized, { @@ -203,8 +204,9 @@ impl *mut T { /// ``` #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_offset(self, count: isize) -> *mut T + pub const fn wrapping_offset(self, count: isize) -> *mut T where T: Sized, { @@ -439,8 +441,9 @@ impl *mut T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn add(self, count: usize) -> Self + pub const unsafe fn add(self, count: usize) -> Self where T: Sized, { @@ -501,8 +504,9 @@ impl *mut T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn sub(self, count: usize) -> Self + pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, { @@ -557,8 +561,9 @@ impl *mut T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_add(self, count: usize) -> Self + pub const fn wrapping_add(self, count: usize) -> Self where T: Sized, { @@ -613,8 +618,9 @@ impl *mut T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_sub(self, count: usize) -> Self + pub const fn wrapping_sub(self, count: usize) -> Self where T: Sized, { From 88a37a20867a3b9840d2f56f806f77ec0990d50c Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 15 May 2020 01:28:33 -0700 Subject: [PATCH 07/44] test/ui/consts: Add tests for const ptr offsets Signed-off-by: Joe Richey --- src/test/ui/consts/offset.rs | 115 +++++++++++++++++++++ src/test/ui/consts/offset_ub.rs | 22 ++++ src/test/ui/consts/offset_ub.stderr | 154 ++++++++++++++++++++++++++++ 3 files changed, 291 insertions(+) create mode 100644 src/test/ui/consts/offset.rs create mode 100644 src/test/ui/consts/offset_ub.rs create mode 100644 src/test/ui/consts/offset_ub.stderr diff --git a/src/test/ui/consts/offset.rs b/src/test/ui/consts/offset.rs new file mode 100644 index 0000000000000..f64242d568e31 --- /dev/null +++ b/src/test/ui/consts/offset.rs @@ -0,0 +1,115 @@ +// run-pass +#![feature(const_ptr_offset)] +#![feature(const_ptr_offset_from)] +#![feature(ptr_offset_from)] +use std::ptr; + +#[repr(C)] +struct Struct { + a: u32, + b: u32, + c: u32, +} +static S: Struct = Struct { a: 0, b: 0, c: 0 }; + +// For these tests we use offset_from to check that two pointers are equal. +// Rust doesn't currently support comparing pointers in const fn. + +static OFFSET_NO_CHANGE: bool = unsafe { + let p1 = &S.b as *const u32; + let p2 = p1.offset(2).offset(-2); + p1.offset_from(p2) == 0 +}; +static OFFSET_MIDDLE: bool = unsafe { + let p1 = (&S.a as *const u32).offset(1); + let p2 = (&S.c as *const u32).offset(-1); + p1.offset_from(p2) == 0 +}; +// Pointing to the end of the allocation is OK +static OFFSET_END: bool = unsafe { + let p1 = (&S.a as *const u32).offset(3); + let p2 = (&S.c as *const u32).offset(1); + p1.offset_from(p2) == 0 +}; +// Casting though a differently sized type is OK +static OFFSET_U8_PTR: bool = unsafe { + let p1 = (&S.a as *const u32 as *const u8).offset(5); + let p2 = (&S.c as *const u32 as *const u8).offset(-3); + p1.offset_from(p2) == 0 +}; +// Any offset with a ZST does nothing +const OFFSET_ZST: bool = unsafe { + let pz = &() as *const (); + // offset_from can't work with ZSTs, so cast to u8 ptr + let p1 = pz.offset(5) as *const u8; + let p2 = pz.offset(isize::MIN) as *const u8; + p1.offset_from(p2) == 0 +}; +const OFFSET_ZERO: bool = unsafe { + let p = [0u8; 0].as_ptr(); + p.offset(0).offset_from(p) == 0 +}; +const OFFSET_ONE: bool = unsafe { + let p = &42u32 as *const u32; + p.offset(1).offset_from(p) == 1 +}; +const OFFSET_DANGLING: bool = unsafe { + let p = ptr::NonNull::::dangling().as_ptr(); + p.offset(0).offset_from(p) == 0 +}; +const OFFSET_UNALIGNED: bool = unsafe { + let arr = [0u8; 32]; + let p1 = arr.as_ptr(); + let p2 = (p1.offset(2) as *const u32).offset(1); + (p2 as *const u8).offset_from(p1) == 6 +}; + +const WRAP_OFFSET_NO_CHANGE: bool = unsafe { + let p1 = &42u32 as *const u32; + let p2 = p1.wrapping_offset(1000).wrapping_offset(-1000); + let p3 = p1.wrapping_offset(-1000).wrapping_offset(1000); + (p1.offset_from(p2) == 0) & (p1.offset_from(p3) == 0) +}; +const WRAP_ADDRESS_SPACE: bool = unsafe { + let p1 = &42u8 as *const u8; + let p2 = p1.wrapping_offset(isize::MIN).wrapping_offset(isize::MIN); + p1.offset_from(p2) == 0 +}; +// Wrap on the count*size_of::() calculation. +const WRAP_SIZE_OF: bool = unsafe { + // Make sure that if p1 moves backwards, we are still in range + let arr = [0u32; 2]; + let p = &arr[1] as *const u32; + // With wrapping arithmetic, isize::MAX * 4 == -4 + let wrapped = p.wrapping_offset(isize::MAX); + let backward = p.wrapping_offset(-1); + wrapped.offset_from(backward) == 0 +}; +const WRAP_INTEGER_POINTER: bool = unsafe { + let p1 = (0x42 as *const u32).wrapping_offset(4); + let p2 = 0x52 as *const u32; + p1.offset_from(p2) == 0 +}; +const WRAP_NULL: bool = unsafe { + let p1 = ptr::null::().wrapping_offset(1); + let p2 = 0x4 as *const u32; + p1.offset_from(p2) == 0 +}; + +fn main() { + assert!(OFFSET_NO_CHANGE); + assert!(OFFSET_MIDDLE); + assert!(OFFSET_END); + assert!(OFFSET_U8_PTR); + assert!(OFFSET_ZST); + assert!(OFFSET_ZERO); + assert!(OFFSET_ONE); + assert!(OFFSET_DANGLING); + assert!(OFFSET_UNALIGNED); + + assert!(WRAP_OFFSET_NO_CHANGE); + assert!(WRAP_ADDRESS_SPACE); + assert!(WRAP_SIZE_OF); + assert!(WRAP_INTEGER_POINTER); + assert!(WRAP_NULL); +} diff --git a/src/test/ui/consts/offset_ub.rs b/src/test/ui/consts/offset_ub.rs new file mode 100644 index 0000000000000..ac12078969480 --- /dev/null +++ b/src/test/ui/consts/offset_ub.rs @@ -0,0 +1,22 @@ +// ignore-tidy-linelength +#![feature(const_ptr_offset)] +use std::ptr; + +// normalize-stderr-test "alloc\d+" -> "allocN" + +pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~NOTE +pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~NOTE +pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~NOTE + +pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~NOTE +pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~NOTE +pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~NOTE +pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~NOTE + +pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~NOTE +pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; //~NOTE + +// Right now, a zero offset from null is UB +pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::().offset(0) }; //~NOTE + +fn main() {} diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr new file mode 100644 index 0000000000000..b2b77586a504d --- /dev/null +++ b/src/test/ui/consts/offset_ub.stderr @@ -0,0 +1,154 @@ +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | overflowing in-bounds pointer arithmetic + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `BEFORE_START` at $DIR/offset_ub.rs:7:46 + | + ::: $DIR/offset_ub.rs:7:1 + | +LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; + | ------------------------------------------------------------------------------ + | + = note: `#[deny(const_err)]` on by default + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1 + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `AFTER_END` at $DIR/offset_ub.rs:8:43 + | + ::: $DIR/offset_ub.rs:8:1 + | +LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; + | -------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100 + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `AFTER_ARRAY` at $DIR/offset_ub.rs:9:45 + | + ::: $DIR/offset_ub.rs:9:1 + | +LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; + | ------------------------------------------------------------------------------ + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds pointer arithmetic: overflow computing offset + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `OVERFLOW` at $DIR/offset_ub.rs:11:43 + | + ::: $DIR/offset_ub.rs:11:1 + | +LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; + | ---------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds pointer arithmetic: overflow computing offset + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44 + | + ::: $DIR/offset_ub.rs:12:1 + | +LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; + | ----------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | overflowing in-bounds pointer arithmetic + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `OVERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:13:56 + | + ::: $DIR/offset_ub.rs:13:1 + | +LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; + | --------------------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | overflowing in-bounds pointer arithmetic + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `UNDERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:14:57 + | + ::: $DIR/offset_ub.rs:14:1 + | +LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; + | -------------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0 + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:16:50 + | + ::: $DIR/offset_ub.rs:16:1 + | +LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; + | ------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) as *mut T + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unable to turn bytes into a pointer + | inside `std::ptr::mut_ptr::::offset` at $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL + | inside `DANGLING` at $DIR/offset_ub.rs:17:42 + | + ::: $DIR/offset_ub.rs:17:1 + | +LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; + | --------------------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: 0x0 is not a valid pointer + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:20:50 + | + ::: $DIR/offset_ub.rs:20:1 + | +LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::().offset(0) }; + | ------------------------------------------------------------------------------- + +error: aborting due to 10 previous errors + From 6b20f58c0d15500b2814a6f3579c29783463add0 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 18 May 2020 16:00:14 -0700 Subject: [PATCH 08/44] miri_unleached: We now allow offset in const fn Signed-off-by: Joe Richey --- .../ui/consts/miri_unleashed/ptr_arith.rs | 10 +-------- .../ui/consts/miri_unleashed/ptr_arith.stderr | 21 +++++-------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.rs b/src/test/ui/consts/miri_unleashed/ptr_arith.rs index 81985f9f625a5..65fc49c0b27a6 100644 --- a/src/test/ui/consts/miri_unleashed/ptr_arith.rs +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.rs @@ -2,8 +2,7 @@ #![feature(core_intrinsics)] #![allow(const_err)] -// A test demonstrating that we prevent doing even trivial -// pointer arithmetic or comparison during CTFE. +// During CTFE, we prevent pointer comparison and pointer-to-int casts. static CMP: () = { let x = &0 as *const _; @@ -19,11 +18,4 @@ static INT_PTR_ARITH: () = unsafe { //~| NOTE pointer-to-integer cast }; -static PTR_ARITH: () = unsafe { - let x = &0 as *const _; - let _v = core::intrinsics::offset(x, 0); - //~^ ERROR could not evaluate static initializer - //~| NOTE calling intrinsic `offset` -}; - fn main() {} diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr index 5bd534a16b863..805ba9c6b0307 100644 --- a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr @@ -1,39 +1,28 @@ error[E0080]: could not evaluate static initializer - --> $DIR/ptr_arith.rs:10:14 + --> $DIR/ptr_arith.rs:9:14 | LL | let _v = x == x; | ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants error[E0080]: could not evaluate static initializer - --> $DIR/ptr_arith.rs:17:14 + --> $DIR/ptr_arith.rs:16:14 | LL | let _v = x + 0; | ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants -error[E0080]: could not evaluate static initializer - --> $DIR/ptr_arith.rs:24:14 - | -LL | let _v = core::intrinsics::offset(x, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "calling intrinsic `offset`" needs an rfc before being allowed inside constants - warning: skipping const checks | help: skipping check for `const_compare_raw_pointers` feature - --> $DIR/ptr_arith.rs:10:14 + --> $DIR/ptr_arith.rs:9:14 | LL | let _v = x == x; | ^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/ptr_arith.rs:16:20 + --> $DIR/ptr_arith.rs:15:20 | LL | let x: usize = std::mem::transmute(&0); | ^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/ptr_arith.rs:24:14 - | -LL | let _v = core::intrinsics::offset(x, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. From 55577b411cd829b6793be8fd0af0e8811ba89e5c Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 25 May 2020 13:40:01 -0700 Subject: [PATCH 09/44] librustc_mir: Add back use statement Signed-off-by: Joe Richey --- src/librustc_mir/interpret/intrinsics.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 0db9c7026588d..b474805926254 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -2,6 +2,8 @@ //! looking at their MIR. Intrinsics/functions supported here are shared by CTFE //! and miri. +use std::convert::TryFrom; + use rustc_hir::def_id::DefId; use rustc_middle::mir::{ self, From 6367b544b781889abee296d34d2b7d353a6ae0f8 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 26 May 2020 01:57:49 -0700 Subject: [PATCH 10/44] librustc_middle: Add function for computing unsigned abs This is tricky to get right if we want to avoid panicking or wrapping. Signed-off-by: Joe Richey --- src/librustc_middle/mir/interpret/mod.rs | 9 +++++++++ src/librustc_middle/mir/interpret/pointer.rs | 13 +++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/librustc_middle/mir/interpret/mod.rs b/src/librustc_middle/mir/interpret/mod.rs index d9e52af89007c..061bc9750e1c2 100644 --- a/src/librustc_middle/mir/interpret/mod.rs +++ b/src/librustc_middle/mir/interpret/mod.rs @@ -598,3 +598,12 @@ pub fn truncate(value: u128, size: Size) -> u128 { // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). (value << shift) >> shift } + +/// Computes the unsigned absolute value without wrapping or panicking. +#[inline] +pub fn uabs(value: i64) -> u64 { + // The only tricky part here is if value == i64::MIN. In that case, + // wrapping_abs() returns i64::MIN == -2^63. Casting this value to a u64 + // gives 2^63, the correct value. + value.wrapping_abs() as u64 +} diff --git a/src/librustc_middle/mir/interpret/pointer.rs b/src/librustc_middle/mir/interpret/pointer.rs index 70cc546199b79..019c96bc511eb 100644 --- a/src/librustc_middle/mir/interpret/pointer.rs +++ b/src/librustc_middle/mir/interpret/pointer.rs @@ -1,4 +1,4 @@ -use super::{AllocId, InterpResult}; +use super::{uabs, AllocId, InterpResult}; use rustc_macros::HashStable; use rustc_target::abi::{HasDataLayout, Size}; @@ -48,15 +48,12 @@ pub trait PointerArithmetic: HasDataLayout { #[inline] fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) { - if i < 0 { - // Trickery to ensure that `i64::MIN` works fine: compute `n = -i`. - // This formula only works for true negative values; it overflows for zero! - let n = u64::MAX - (i as u64) + 1; + let n = uabs(i); + if i >= 0 { + self.overflowing_offset(val, n) + } else { let res = val.overflowing_sub(n); self.truncate_to_ptr(res) - } else { - // `i >= 0`, so the cast is safe. - self.overflowing_offset(val, i as u64) } } From 71ef8414bd86cbd79b29f8b1a0145da96e2f2f09 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 26 May 2020 02:00:02 -0700 Subject: [PATCH 11/44] Add checks and tests for computing abs(offset_bytes) The previous code paniced if offset_bytes == i64::MIN. This commit: - Properly computes the absoulte value to avoid this panic - Adds a test for this edge case Signed-off-by: Joe Richey --- src/librustc_mir/interpret/intrinsics.rs | 5 +++-- src/test/ui/consts/offset_ub.rs | 3 +++ src/test/ui/consts/offset_ub.stderr | 17 ++++++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index b474805926254..239115076bc4b 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -7,7 +7,7 @@ use std::convert::TryFrom; use rustc_hir::def_id::DefId; use rustc_middle::mir::{ self, - interpret::{ConstValue, GlobalId, InterpResult, Scalar}, + interpret::{uabs, ConstValue, GlobalId, InterpResult, Scalar}, BinOp, }; use rustc_middle::ty; @@ -438,6 +438,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pointee_ty: Ty<'tcx>, offset_count: i64, ) -> InterpResult<'tcx, Scalar> { + // We cannot overflow i64 as a type's size must be <= isize::MAX. let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); // The computed offset, in bytes, cannot overflow an isize. let offset_bytes = offset_count @@ -450,7 +451,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // memory between these pointers must be accessible. Note that we do not require the // pointers to be properly aligned (unlike a read/write operation). let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr }; - let size = offset_bytes.checked_abs().unwrap(); + let size: u64 = uabs(offset_bytes); // This call handles checking for integer/NULL pointers. self.memory.check_ptr_access_align( min_ptr, diff --git a/src/test/ui/consts/offset_ub.rs b/src/test/ui/consts/offset_ub.rs index ac12078969480..4f943ed9ad194 100644 --- a/src/test/ui/consts/offset_ub.rs +++ b/src/test/ui/consts/offset_ub.rs @@ -19,4 +19,7 @@ pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr() // Right now, a zero offset from null is UB pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::().offset(0) }; //~NOTE +// Make sure that we don't panic when computing abs(offset*size_of::()) +pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; //~NOTE + fn main() {} diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr index b2b77586a504d..e808939682f30 100644 --- a/src/test/ui/consts/offset_ub.stderr +++ b/src/test/ui/consts/offset_ub.stderr @@ -150,5 +150,20 @@ LL | intrinsics::offset(self, count) LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::().offset(0) }; | ------------------------------------------------------------------------------- -error: aborting due to 10 previous errors +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unable to turn bytes into a pointer + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `UNDERFLOW_ABS` at $DIR/offset_ub.rs:23:47 + | + ::: $DIR/offset_ub.rs:23:1 + | +LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; + | --------------------------------------------------------------------------------------------- + +error: aborting due to 11 previous errors From 1de3ebb39d659d0f1ae85f6b87e2bec96d902d72 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 12 May 2020 20:09:55 -0700 Subject: [PATCH 12/44] Add Extend::{extend_one,extend_reserve} This adds new optional methods on `Extend`: `extend_one` add a single element to the collection, and `extend_reserve` pre-allocates space for the predicted number of incoming elements. These are used in `Iterator` for `partition` and `unzip` as they shuffle elements one-at-a-time into their respective collections. --- src/liballoc/collections/binary_heap.rs | 20 ++++++++++++++ src/liballoc/collections/btree/map.rs | 10 +++++++ src/liballoc/collections/btree/set.rs | 10 +++++++ src/liballoc/collections/linked_list.rs | 10 +++++++ src/liballoc/collections/vec_deque.rs | 20 ++++++++++++++ src/liballoc/lib.rs | 1 + src/liballoc/string.rs | 35 ++++++++++++++++++++++++ src/liballoc/vec.rs | 20 ++++++++++++++ src/libcore/iter/traits/collect.rs | 15 +++++++++- src/libcore/iter/traits/iterator.rs | 14 +++++++--- src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/thin_vec.rs | 14 ++++++++++ src/librustc_index/lib.rs | 1 + src/librustc_index/vec.rs | 10 +++++++ src/librustc_infer/lib.rs | 1 + src/librustc_infer/traits/util.rs | 8 ++++++ src/libstd/collections/hash/map.rs | 29 ++++++++++++++++++++ src/libstd/collections/hash/set.rs | 20 ++++++++++++++ src/libstd/lib.rs | 1 + src/libstd/path.rs | 5 ++++ src/libstd/sys_common/wtf8.rs | 11 ++++++++ 21 files changed, 251 insertions(+), 5 deletions(-) diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index a3ef998918433..c2fe4691b34c0 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -1376,6 +1376,16 @@ impl Extend for BinaryHeap { fn extend>(&mut self, iter: I) { >::spec_extend(self, iter); } + + #[inline] + fn extend_one(&mut self, item: T) { + self.push(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } impl> SpecExtend for BinaryHeap { @@ -1406,4 +1416,14 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &item: &'a T) { + self.push(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index c6cb39b1bf511..fa1c09d9ece87 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1901,6 +1901,11 @@ impl Extend<(K, V)> for BTreeMap { self.insert(k, v); }); } + + #[inline] + fn extend_one(&mut self, (k, v): (K, V)) { + self.insert(k, v); + } } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -1908,6 +1913,11 @@ impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); } + + #[inline] + fn extend_one(&mut self, (&k, &v): (&'a K, &'a V)) { + self.insert(k, v); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index dee5fb878ff2a..525ef38c32fa2 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -1152,6 +1152,11 @@ impl Extend for BTreeSet { self.insert(elem); }); } + + #[inline] + fn extend_one(&mut self, elem: T) { + self.insert(elem); + } } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -1159,6 +1164,11 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &elem: &'a T) { + self.insert(elem); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index cc0f07b822741..85f2505f756aa 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -1748,6 +1748,11 @@ impl Extend for LinkedList { fn extend>(&mut self, iter: I) { >::spec_extend(self, iter); } + + #[inline] + fn extend_one(&mut self, elem: T) { + self.push_back(elem); + } } impl SpecExtend for LinkedList { @@ -1767,6 +1772,11 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for LinkedList { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &elem: &'a T) { + self.push_back(elem); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 540649c61b332..ae54d3971baac 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -2881,6 +2881,16 @@ impl Extend for VecDeque { } } } + + #[inline] + fn extend_one(&mut self, elem: A) { + self.push_back(elem); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -2888,6 +2898,16 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for VecDeque { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &elem: &T) { + self.push_back(elem); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 7aaa91ee10d97..9bcfc9457f50e 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -93,6 +93,7 @@ #![feature(container_error_extra)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] +#![feature(extend_one)] #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(fundamental)] diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index f3fe1adebb141..0378ff5362a8b 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1799,6 +1799,16 @@ impl Extend for String { self.reserve(lower_bound); iterator.for_each(move |c| self.push(c)); } + + #[inline] + fn extend_one(&mut self, c: char) { + self.push(c); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -1806,6 +1816,16 @@ impl<'a> Extend<&'a char> for String { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &c: &'a char) { + self.push(c); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1813,6 +1833,11 @@ impl<'a> Extend<&'a str> for String { fn extend>(&mut self, iter: I) { iter.into_iter().for_each(move |s| self.push_str(s)); } + + #[inline] + fn extend_one(&mut self, s: &'a str) { + self.push_str(s); + } } #[stable(feature = "extend_string", since = "1.4.0")] @@ -1820,6 +1845,11 @@ impl Extend for String { fn extend>(&mut self, iter: I) { iter.into_iter().for_each(move |s| self.push_str(&s)); } + + #[inline] + fn extend_one(&mut self, s: String) { + self.push_str(&s); + } } #[stable(feature = "herd_cows", since = "1.19.0")] @@ -1827,6 +1857,11 @@ impl<'a> Extend> for String { fn extend>>(&mut self, iter: I) { iter.into_iter().for_each(move |s| self.push_str(&s)); } + + #[inline] + fn extend_one(&mut self, s: Cow<'a, str>) { + self.push_str(&s); + } } /// A convenience impl that delegates to the impl for `&str`. diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index d26cd77aae4b7..42fb1f8c737b3 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2045,6 +2045,16 @@ impl Extend for Vec { fn extend>(&mut self, iter: I) { >::spec_extend(self, iter.into_iter()) } + + #[inline] + fn extend_one(&mut self, item: T) { + self.push(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } // Specialization trait used for Vec::from_iter and Vec::extend @@ -2316,6 +2326,16 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for Vec { fn extend>(&mut self, iter: I) { self.spec_extend(iter.into_iter()) } + + #[inline] + fn extend_one(&mut self, &item: &'a T) { + self.push(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } macro_rules! __impl_slice_eq1 { diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs index f21ab8dbc3737..da859db545d7e 100644 --- a/src/libcore/iter/traits/collect.rs +++ b/src/libcore/iter/traits/collect.rs @@ -322,7 +322,7 @@ impl IntoIterator for I { pub trait Extend { /// Extends a collection with the contents of an iterator. /// - /// As this is the only method for this trait, the [trait-level] docs + /// As this is the only required method for this trait, the [trait-level] docs /// contain more details. /// /// [trait-level]: trait.Extend.html @@ -341,6 +341,18 @@ pub trait Extend { /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn extend>(&mut self, iter: T); + + /// Extends a collection with exactly one element. + #[unstable(feature = "extend_one", issue = "none")] + fn extend_one(&mut self, item: A) { + self.extend(Some(item)); + } + + /// Reserves capacity in a collection for the given number of additional elements. + /// + /// The default implementation does nothing. + #[unstable(feature = "extend_one", issue = "none")] + fn extend_reserve(&mut self, _additional: usize) {} } #[stable(feature = "extend_for_unit", since = "1.28.0")] @@ -348,4 +360,5 @@ impl Extend<()> for () { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(drop) } + fn extend_one(&mut self, _item: ()) {} } diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 1c3d95cbb8c35..30a23e7ecd185 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -1700,9 +1700,9 @@ pub trait Iterator { ) -> impl FnMut((), T) + 'a { move |(), x| { if f(&x) { - left.extend(Some(x)); + left.extend_one(x); } else { - right.extend(Some(x)); + right.extend_one(x); } } } @@ -2675,14 +2675,20 @@ pub trait Iterator { us: &'a mut impl Extend, ) -> impl FnMut((), (A, B)) + 'a { move |(), (t, u)| { - ts.extend(Some(t)); - us.extend(Some(u)); + ts.extend_one(t); + us.extend_one(u); } } let mut ts: FromA = Default::default(); let mut us: FromB = Default::default(); + let (lower_bound, _) = self.size_hint(); + if lower_bound > 0 { + ts.extend_reserve(lower_bound); + us.extend_reserve(lower_bound); + } + self.fold((), extend(&mut ts, &mut us)); (ts, us) diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 7ee60176dbead..0b2e7cda1b4cc 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -22,6 +22,7 @@ #![feature(test)] #![feature(associated_type_bounds)] #![feature(thread_id_value)] +#![feature(extend_one)] #![allow(rustc::default_hash_types)] #[macro_use] diff --git a/src/librustc_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs index 2befc0aa50487..43002178eb971 100644 --- a/src/librustc_data_structures/thin_vec.rs +++ b/src/librustc_data_structures/thin_vec.rs @@ -53,6 +53,20 @@ impl Extend for ThinVec { ThinVec(None) => *self = iter.into_iter().collect::>().into(), } } + + fn extend_one(&mut self, item: T) { + match *self { + ThinVec(Some(ref mut vec)) => vec.push(item), + ThinVec(None) => *self = vec![item].into(), + } + } + + fn extend_reserve(&mut self, additional: usize) { + match *self { + ThinVec(Some(ref mut vec)) => vec.reserve(additional), + ThinVec(None) => *self = Vec::with_capacity(additional).into(), + } + } } impl, CTX> HashStable for ThinVec { diff --git a/src/librustc_index/lib.rs b/src/librustc_index/lib.rs index e8aa1a209e929..3effc41645011 100644 --- a/src/librustc_index/lib.rs +++ b/src/librustc_index/lib.rs @@ -2,6 +2,7 @@ #![feature(const_if_match)] #![feature(const_fn)] #![feature(const_panic)] +#![feature(extend_one)] #![feature(unboxed_closures)] #![feature(test)] #![feature(fn_traits)] diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs index 67dcea58cf82b..4dde33283f575 100644 --- a/src/librustc_index/vec.rs +++ b/src/librustc_index/vec.rs @@ -736,6 +736,16 @@ impl Extend for IndexVec { fn extend>(&mut self, iter: J) { self.raw.extend(iter); } + + #[inline] + fn extend_one(&mut self, item: T) { + self.raw.push(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.raw.reserve(additional); + } } impl FromIterator for IndexVec { diff --git a/src/librustc_infer/lib.rs b/src/librustc_infer/lib.rs index 28d42cea6d300..ed04ee02b7203 100644 --- a/src/librustc_infer/lib.rs +++ b/src/librustc_infer/lib.rs @@ -16,6 +16,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(extend_one)] #![feature(never_type)] #![feature(or_patterns)] #![feature(range_is_empty)] diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 88fc1460475df..46d94f75a2ccd 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -87,6 +87,14 @@ impl>> Extend for PredicateSet<'tcx> { self.insert(pred.as_ref()); } } + + fn extend_one(&mut self, pred: T) { + self.insert(pred.as_ref()); + } + + fn extend_reserve(&mut self, additional: usize) { + Extend::>::extend_reserve(&mut self.set, additional); + } } /////////////////////////////////////////////////////////////////////////// diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 56cf9be339194..a51f1998e4452 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2426,6 +2426,24 @@ where fn extend>(&mut self, iter: T) { self.base.extend(iter) } + + #[inline] + fn extend_one(&mut self, (k, v): (K, V)) { + self.base.insert(k, v); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + // self.base.extend_reserve(additional); + // FIXME: hashbrown should implement this method. + // But until then, use the same reservation logic: + + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if self.is_empty() { additional } else { (additional + 1) / 2 }; + self.base.reserve(reserve); + } } #[stable(feature = "hash_extend_copy", since = "1.4.0")] @@ -2439,6 +2457,17 @@ where fn extend>(&mut self, iter: T) { self.base.extend(iter) } + + #[inline] + fn extend_one(&mut self, (&k, &v): (&'a K, &'a V)) { + self.base.insert(k, v); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + // self.base.extend_reserve(additional); + Extend::<(K, V)>::extend_reserve(self, additional) + } } /// `RandomState` is the default state for [`HashMap`] types. diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index ca06457291cae..cb2f829803b85 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -970,6 +970,16 @@ where fn extend>(&mut self, iter: I) { self.map.extend(iter.into_iter().map(|k| (k, ()))); } + + #[inline] + fn extend_one(&mut self, item: T) { + self.map.insert(item, ()); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.map.extend_reserve(additional); + } } #[stable(feature = "hash_extend_copy", since = "1.4.0")] @@ -982,6 +992,16 @@ where fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &item: &'a T) { + self.map.insert(item, ()); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + Extend::::extend_reserve(self, additional) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index cc3e613fa3d60..c165bb6ca74c4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -263,6 +263,7 @@ #![feature(duration_constants)] #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] +#![feature(extend_one)] #![feature(external_doc)] #![feature(fn_traits)] #![feature(format_args_nl)] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 0fe5451bb9564..8ff7508ba6457 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1534,6 +1534,11 @@ impl> iter::Extend

for PathBuf { fn extend>(&mut self, iter: I) { iter.into_iter().for_each(move |p| self.push(p.as_ref())); } + + #[inline] + fn extend_one(&mut self, p: P) { + self.push(p.as_ref()); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index a98407da44850..a5ba3daba3e87 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -386,6 +386,17 @@ impl Extend for Wtf8Buf { self.bytes.reserve(low); iterator.for_each(move |code_point| self.push(code_point)); } + + #[inline] + fn extend_one(&mut self, code_point: CodePoint) { + self.push(code_point); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + // Lower bound of one byte per code point (ASCII only) + self.bytes.reserve(additional); + } } /// A borrowed slice of well-formed WTF-8 data. From 6a26bb9e8dbeb639c975b2dbe7ae5ce668b15572 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 26 May 2020 14:01:26 -0700 Subject: [PATCH 13/44] Use a canonical name for extend_reserve(additional) Co-authored-by: David Tolnay --- src/libcore/iter/traits/collect.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs index da859db545d7e..4a90aca148547 100644 --- a/src/libcore/iter/traits/collect.rs +++ b/src/libcore/iter/traits/collect.rs @@ -352,7 +352,9 @@ pub trait Extend { /// /// The default implementation does nothing. #[unstable(feature = "extend_one", issue = "none")] - fn extend_reserve(&mut self, _additional: usize) {} + fn extend_reserve(&mut self, additional: usize) { + let _ = additional; + } } #[stable(feature = "extend_for_unit", since = "1.28.0")] From 7795c4bea3d75ffb9ea14a70e3db648a35e09ba8 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 26 May 2020 14:03:34 -0700 Subject: [PATCH 14/44] Remove an old comment from HashMap::extend_reserve --- src/libstd/collections/hash/map.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a51f1998e4452..5ba5eff44076b 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2465,7 +2465,6 @@ where #[inline] fn extend_reserve(&mut self, additional: usize) { - // self.base.extend_reserve(additional); Extend::<(K, V)>::extend_reserve(self, additional) } } From 02226e0685b749313d15e71c3028db9dfb62ac11 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 26 May 2020 14:15:29 -0700 Subject: [PATCH 15/44] Add extend_one tracking issue 72631 --- src/libcore/iter/traits/collect.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs index 4a90aca148547..9d20022b6ed6d 100644 --- a/src/libcore/iter/traits/collect.rs +++ b/src/libcore/iter/traits/collect.rs @@ -343,7 +343,7 @@ pub trait Extend { fn extend>(&mut self, iter: T); /// Extends a collection with exactly one element. - #[unstable(feature = "extend_one", issue = "none")] + #[unstable(feature = "extend_one", issue = "72631")] fn extend_one(&mut self, item: A) { self.extend(Some(item)); } @@ -351,7 +351,7 @@ pub trait Extend { /// Reserves capacity in a collection for the given number of additional elements. /// /// The default implementation does nothing. - #[unstable(feature = "extend_one", issue = "none")] + #[unstable(feature = "extend_one", issue = "72631")] fn extend_reserve(&mut self, additional: usize) { let _ = additional; } From a977df35d160c1fe7040c76a9276b64e7a7aedec Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 3 May 2020 23:11:34 +0200 Subject: [PATCH 16/44] Implement RFC 2585 --- src/librustc_feature/active.rs | 3 + src/librustc_middle/mir/mod.rs | 2 +- src/librustc_middle/mir/query.rs | 7 +++ src/librustc_mir/transform/check_unsafety.rs | 63 +++++++++++++++++--- src/librustc_mir_build/build/block.rs | 2 + src/librustc_session/lint/builtin.rs | 7 +++ src/librustc_span/symbol.rs | 1 + 7 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 90b2380d86450..fd35cb6c3f785 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -571,6 +571,9 @@ declare_features! ( /// Allows the use of `#[ffi_const]` on foreign functions. (active, ffi_const, "1.45.0", Some(58328), None), + /// No longer treat an unsafe function as an unsafe block. + (active, unsafe_block_in_unsafe_fn, "1.45.0", Some(71668), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index c279213e5bd0e..243f81459e760 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -408,7 +408,7 @@ impl<'tcx> Body<'tcx> { } } -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable, HashStable)] pub enum Safety { Safe, /// Unsafe because of a PushUnsafeBlock diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs index 63b8d8c8da782..f19270e5561f0 100644 --- a/src/librustc_middle/mir/query.rs +++ b/src/librustc_middle/mir/query.rs @@ -15,10 +15,17 @@ use super::{Field, SourceInfo}; #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] pub enum UnsafetyViolationKind { + /// Only permitted in regular `fn`s, prohibitted in `const fn`s. General, /// Permitted both in `const fn`s and regular `fn`s. GeneralAndConstFn, + /// Borrow of packed field. + /// Has to be handled as a lint for backwards compatibility. BorrowPacked(hir::HirId), + /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block. + /// Has to be handled as a lint for backwards compatibility. + /// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`. + UnsafeFn(hir::HirId), } #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index a335fa2de411b..bcadbd091076a 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -9,7 +9,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNUSED_UNSAFE}; +use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_span::symbol::{sym, Symbol}; use std::ops::Bound; @@ -351,14 +351,35 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { violation.kind = UnsafetyViolationKind::General; } } + UnsafetyViolationKind::UnsafeFn(_) => { + bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") + } + } + if !self.violations.contains(&violation) { + self.violations.push(violation) } + } + false + } + // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s + Safety::FnUnsafe if self.tcx.features().unsafe_block_in_unsafe_fn => { + for violation in violations { + let mut violation = *violation; + let lint_root = self.body.source_scopes[self.source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + + // FIXME(LeSeulArtichaut): what to do with `UnsafetyViolationKind::BorrowPacked`? + violation.kind = UnsafetyViolationKind::UnsafeFn(lint_root); if !self.violations.contains(&violation) { self.violations.push(violation) } } false } - // `unsafe` function bodies allow unsafe without additional unsafe blocks + // `unsafe` function bodies allow unsafe without additional unsafe blocks (before RFC 2585) Safety::BuiltinUnsafe | Safety::FnUnsafe => true, Safety::ExplicitUnsafe(hir_id) => { // mark unsafe block as used if there are any unsafe operations inside @@ -383,6 +404,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { self.violations.push(violation) } } + UnsafetyViolationKind::UnsafeFn(_) => bug!( + "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context" + ), } } } @@ -575,9 +599,12 @@ fn is_enclosed( kind: hir::ItemKind::Fn(ref sig, _, _), .. })) = tcx.hir().find(parent_id) { - match sig.header.unsafety { - hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)), - hir::Unsafety::Normal => None, + if sig.header.unsafety == hir::Unsafety::Unsafe + && !tcx.features().unsafe_block_in_unsafe_fn + { + Some(("fn".to_string(), parent_id)) + } else { + None } } else { is_enclosed(tcx, used_unsafe, parent_id) @@ -630,16 +657,20 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id.expect_local()); + let or_block_msg = if tcx.features().unsafe_block_in_unsafe_fn { "" } else { " or block" }; + for &UnsafetyViolation { source_info, description, details, kind } in violations.iter() { // Report an error. match kind { UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { + // once struct_span_err!( tcx.sess, source_info.span, E0133, - "{} is unsafe and requires unsafe function or block", - description + "{} is unsafe and requires unsafe function{}", + description, + or_block_msg, ) .span_label(source_info.span, &*description.as_str()) .note(&details.as_str()) @@ -655,8 +686,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { source_info.span, |lint| { lint.build(&format!( - "{} is unsafe and requires unsafe function or block (error E0133)", - description + "{} is unsafe and requires unsafe function{} (error E0133)", + description, or_block_msg, )) .note(&details.as_str()) .emit() @@ -664,6 +695,20 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { ) } } + UnsafetyViolationKind::UnsafeFn(lint_hir_id) => tcx.struct_span_lint_hir( + UNSAFE_OP_IN_UNSAFE_FN, + lint_hir_id, + source_info.span, + |lint| { + lint.build(&format!( + "{} is unsafe and requires unsafe block (error E0133)", + description + )) + .span_label(source_info.span, &*description.as_str()) + .note(&details.as_str()) + .emit(); + }, + ), } } diff --git a/src/librustc_mir_build/build/block.rs b/src/librustc_mir_build/build/block.rs index fa783ddcf409a..b052c839152de 100644 --- a/src/librustc_mir_build/build/block.rs +++ b/src/librustc_mir_build/build/block.rs @@ -217,6 +217,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert_eq!(self.push_unsafe_count, 0); match self.unpushed_unsafe { Safety::Safe => {} + // no longer treat `unsafe fn`s as `unsafe` contexts (see RFC #2585) + Safety::FnUnsafe if self.hir.tcx().features().unsafe_block_in_unsafe_fn => {} _ => return, } self.unpushed_unsafe = Safety::ExplicitUnsafe(hir_id); diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index e55ddc26a9441..7112ac35b082b 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -526,6 +526,12 @@ declare_lint! { "using only a subset of a register for inline asm inputs", } +declare_lint! { + pub UNSAFE_OP_IN_UNSAFE_FN, + Allow, + "unsafe operations in unsafe functions without an explicit unsafe block are deprecated", +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -597,6 +603,7 @@ declare_lint_pass! { SOFT_UNSTABLE, INLINE_NO_SANITIZE, ASM_SUB_REGISTER, + UNSAFE_OP_IN_UNSAFE_FN, ] } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 6a6098710e828..87952d409c896 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -806,6 +806,7 @@ symbols! { unmarked_api, unreachable_code, unrestricted_attribute_tokens, + unsafe_block_in_unsafe_fn, unsafe_no_drop_flag, unsized_locals, unsized_tuple_coercion, From 594c499db995abaacc10a74c0afbb9aeed48117d Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 3 May 2020 23:11:58 +0200 Subject: [PATCH 17/44] Add tests --- .../feature-gate-unsafe_block_in_unsafe_fn.rs | 11 +++++++ ...ture-gate-unsafe_block_in_unsafe_fn.stderr | 16 ++++++++++ .../unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 26 +++++++++++++++++ .../rfc-2585-unsafe_op_in_unsafe_fn.stderr | 29 +++++++++++++++++++ 4 files changed, 82 insertions(+) create mode 100644 src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs create mode 100644 src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr create mode 100644 src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs create mode 100644 src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs new file mode 100644 index 0000000000000..80005fd4ef632 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs @@ -0,0 +1,11 @@ +#![deny(unused_unsafe)] + +unsafe fn unsf() {} + +unsafe fn foo() { + unsafe { //~ ERROR unnecessary `unsafe` block + unsf() + } +} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr new file mode 100644 index 0000000000000..64874e590fb89 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr @@ -0,0 +1,16 @@ +error: unnecessary `unsafe` block + --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:6:5 + | +LL | unsafe fn foo() { + | --------------- because it's nested under this `unsafe` fn +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:9 + | +LL | #![deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs new file mode 100644 index 0000000000000..0ffb2827bfde2 --- /dev/null +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -0,0 +1,26 @@ +#![feature(unsafe_block_in_unsafe_fn)] +#![warn(unsafe_op_in_unsafe_fn)] +#![deny(unused_unsafe)] + +unsafe fn unsf() {} + +unsafe fn foo() { + unsf(); + //~^ WARNING call to unsafe function is unsafe and requires unsafe block +} + +unsafe fn bar() { + unsafe { unsf() } // no error +} + +unsafe fn baz() { + unsafe { unsafe { unsf() } } + //~^ ERROR unnecessary `unsafe` block +} + +#[allow(unsafe_op_in_unsafe_fn)] +unsafe fn qux() { + unsf(); // no error +} + +fn main() {} diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr new file mode 100644 index 0000000000000..be6af2a11c40a --- /dev/null +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr @@ -0,0 +1,29 @@ +warning: call to unsafe function is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:8:5 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9 + | +LL | #![warn(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:17:14 + | +LL | unsafe { unsafe { unsf() } } + | ------ ^^^^^^ unnecessary `unsafe` block + | | + | because it's nested under this `unsafe` block + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:3:9 + | +LL | #![deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + From bb6791502846b62e752c99396953e4db7739f28c Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 13 May 2020 23:43:21 +0200 Subject: [PATCH 18/44] Apply suggestions from code review --- src/librustc_lint/levels.rs | 19 +++++- src/librustc_middle/mir/query.rs | 5 +- src/librustc_mir/transform/check_unsafety.rs | 67 ++++++++++++------- src/librustc_mir_build/build/block.rs | 12 +++- .../feature-gate-unsafe_block_in_unsafe_fn.rs | 11 +-- ...ture-gate-unsafe_block_in_unsafe_fn.stderr | 36 +++++++--- .../unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 8 ++- .../rfc-2585-unsafe_op_in_unsafe_fn.stderr | 17 ++++- 8 files changed, 125 insertions(+), 50 deletions(-) diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 274e57ae64cac..7069472015402 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -17,8 +17,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::lint::{builtin, Level, Lint}; use rustc_session::parse::feature_err; use rustc_session::Session; -use rustc_span::source_map::MultiSpan; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP}; use std::cmp; @@ -80,6 +80,8 @@ impl<'s> LintLevelsBuilder<'s> { let level = cmp::min(level, self.sets.lint_cap); let lint_flag_val = Symbol::intern(lint_name); + self.check_gated_lint(lint_flag_val, DUMMY_SP); + let ids = match store.find_lints(&lint_name) { Ok(ids) => ids, Err(_) => continue, // errors handled in check_lint_name_cmdline above @@ -211,6 +213,7 @@ impl<'s> LintLevelsBuilder<'s> { let name = meta_item.path.segments.last().expect("empty lint name").ident.name; match store.check_lint_name(&name.as_str(), tool_name) { CheckLintNameResult::Ok(ids) => { + self.check_gated_lint(name, attr.span); let src = LintSource::Node(name, li.span(), reason); for id in ids { specs.insert(*id, (level, src)); @@ -383,6 +386,20 @@ impl<'s> LintLevelsBuilder<'s> { BuilderPush { prev, changed: prev != self.cur } } + fn check_gated_lint(&self, name: Symbol, span: Span) { + if name.as_str() == "unsafe_op_in_unsafe_fn" + && !self.sess.features_untracked().unsafe_block_in_unsafe_fn + { + feature_err( + &self.sess.parse_sess, + sym::unsafe_block_in_unsafe_fn, + span, + "the `unsafe_op_in_unsafe_fn` lint is unstable", + ) + .emit(); + } + } + /// Called after `push` when the scope of a set of attributes are exited. pub fn pop(&mut self, push: BuilderPush) { self.cur = push.prev; diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs index f19270e5561f0..c63d7215867c2 100644 --- a/src/librustc_middle/mir/query.rs +++ b/src/librustc_middle/mir/query.rs @@ -21,16 +21,17 @@ pub enum UnsafetyViolationKind { GeneralAndConstFn, /// Borrow of packed field. /// Has to be handled as a lint for backwards compatibility. - BorrowPacked(hir::HirId), + BorrowPacked, /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block. /// Has to be handled as a lint for backwards compatibility. /// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`. - UnsafeFn(hir::HirId), + UnsafeFn, } #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] pub struct UnsafetyViolation { pub source_info: SourceInfo, + pub lint_root: hir::HirId, pub description: Symbol, pub details: Symbol, pub kind: UnsafetyViolationKind, diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index bcadbd091076a..0434f3447bced 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::hir_id::HirId; use rustc_hir::intravisit; use rustc_hir::Node; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; @@ -10,6 +11,7 @@ use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; +use rustc_session::lint::Level; use rustc_span::symbol::{sym, Symbol}; use std::ops::Bound; @@ -220,7 +222,18 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { for (i, elem) in place.projection.iter().enumerate() { let proj_base = &place.projection[..i]; - let old_source_info = self.source_info; + if context.is_borrow() { + if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { + self.require_unsafe( + "borrow of packed field", + "fields of packed structs might be misaligned: dereferencing a \ + misaligned pointer or even just creating a misaligned reference \ + is undefined behavior", + UnsafetyViolationKind::BorrowPacked, + ); + } + } + let source_info = self.source_info; if let [] = proj_base { let decl = &self.body.local_decls[place.local]; if decl.internal { @@ -301,7 +314,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } _ => {} } - self.source_info = old_source_info; + self.source_info = source_info; } } } @@ -314,9 +327,15 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { kind: UnsafetyViolationKind, ) { let source_info = self.source_info; + let lint_root = self.body.source_scopes[self.source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; self.register_violations( &[UnsafetyViolation { source_info, + lint_root, description: Symbol::intern(description), details: Symbol::intern(details), kind, @@ -343,7 +362,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { match violation.kind { UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => {} - UnsafetyViolationKind::BorrowPacked(_) => { + UnsafetyViolationKind::BorrowPacked => { if self.min_const_fn { // const fns don't need to be backwards compatible and can // emit these violations as a hard error instead of a backwards @@ -351,7 +370,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { violation.kind = UnsafetyViolationKind::General; } } - UnsafetyViolationKind::UnsafeFn(_) => { + UnsafetyViolationKind::UnsafeFn => { bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") } } @@ -365,14 +384,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { Safety::FnUnsafe if self.tcx.features().unsafe_block_in_unsafe_fn => { for violation in violations { let mut violation = *violation; - let lint_root = self.body.source_scopes[self.source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .lint_root; // FIXME(LeSeulArtichaut): what to do with `UnsafetyViolationKind::BorrowPacked`? - violation.kind = UnsafetyViolationKind::UnsafeFn(lint_root); + violation.kind = UnsafetyViolationKind::UnsafeFn; if !self.violations.contains(&violation) { self.violations.push(violation) } @@ -394,7 +408,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { UnsafetyViolationKind::GeneralAndConstFn => {} // these things are forbidden in const fns UnsafetyViolationKind::General - | UnsafetyViolationKind::BorrowPacked(_) => { + | UnsafetyViolationKind::BorrowPacked => { let mut violation = *violation; // const fns don't need to be backwards compatible and can // emit these violations as a hard error instead of a backwards @@ -404,7 +418,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { self.violations.push(violation) } } - UnsafetyViolationKind::UnsafeFn(_) => bug!( + UnsafetyViolationKind::UnsafeFn => bug!( "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context" ), } @@ -657,10 +671,13 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id.expect_local()); - let or_block_msg = if tcx.features().unsafe_block_in_unsafe_fn { "" } else { " or block" }; - - for &UnsafetyViolation { source_info, description, details, kind } in violations.iter() { + for &UnsafetyViolation { source_info, lint_root, description, details, kind } in + violations.iter() + { // Report an error. + let unsafe_fn_msg = + if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { "" } else { " function or" }; + match kind { UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { // once @@ -668,26 +685,26 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { tcx.sess, source_info.span, E0133, - "{} is unsafe and requires unsafe function{}", + "{} is unsafe and requires unsafe{} block", description, - or_block_msg, + unsafe_fn_msg, ) .span_label(source_info.span, &*description.as_str()) .note(&details.as_str()) .emit(); } - UnsafetyViolationKind::BorrowPacked(lint_hir_id) => { + UnsafetyViolationKind::BorrowPacked => { if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) { tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id); } else { tcx.struct_span_lint_hir( SAFE_PACKED_BORROWS, - lint_hir_id, + lint_root, source_info.span, |lint| { lint.build(&format!( - "{} is unsafe and requires unsafe function{} (error E0133)", - description, or_block_msg, + "{} is unsafe and requires unsafe{} block (error E0133)", + description, unsafe_fn_msg, )) .note(&details.as_str()) .emit() @@ -695,9 +712,9 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { ) } } - UnsafetyViolationKind::UnsafeFn(lint_hir_id) => tcx.struct_span_lint_hir( + UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir( UNSAFE_OP_IN_UNSAFE_FN, - lint_hir_id, + lint_root, source_info.span, |lint| { lint.build(&format!( @@ -728,3 +745,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { report_unused_unsafe(tcx, &unsafe_used, block_id); } } + +fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool { + tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow +} diff --git a/src/librustc_mir_build/build/block.rs b/src/librustc_mir_build/build/block.rs index b052c839152de..4e4f0dc74cb7c 100644 --- a/src/librustc_mir_build/build/block.rs +++ b/src/librustc_mir_build/build/block.rs @@ -4,6 +4,8 @@ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::hair::*; use rustc_hir as hir; use rustc_middle::mir::*; +use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; +use rustc_session::lint::Level; use rustc_span::Span; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -218,7 +220,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match self.unpushed_unsafe { Safety::Safe => {} // no longer treat `unsafe fn`s as `unsafe` contexts (see RFC #2585) - Safety::FnUnsafe if self.hir.tcx().features().unsafe_block_in_unsafe_fn => {} + Safety::FnUnsafe + if self.hir.tcx().lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, hir_id).0 + != Level::Allow => {} _ => return, } self.unpushed_unsafe = Safety::ExplicitUnsafe(hir_id); @@ -233,7 +237,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .push_unsafe_count .checked_sub(1) .unwrap_or_else(|| span_bug!(span, "unsafe count underflow")); - if self.push_unsafe_count == 0 { Some(self.unpushed_unsafe) } else { None } + if self.push_unsafe_count == 0 { + Some(self.unpushed_unsafe) + } else { + None + } } }; diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs index 80005fd4ef632..bf33ac67fcae9 100644 --- a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs +++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs @@ -1,11 +1,4 @@ -#![deny(unused_unsafe)] - -unsafe fn unsf() {} - -unsafe fn foo() { - unsafe { //~ ERROR unnecessary `unsafe` block - unsf() - } -} +#![deny(unsafe_op_in_unsafe_fn)] +//~^ ERROR the `unsafe_op_in_unsafe_fn` lint is unstable fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr index 64874e590fb89..c5cad4a98d9ca 100644 --- a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr +++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr @@ -1,16 +1,30 @@ -error: unnecessary `unsafe` block - --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:6:5 +error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable + --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1 | -LL | unsafe fn foo() { - | --------------- because it's nested under this `unsafe` fn -LL | unsafe { - | ^^^^^^ unnecessary `unsafe` block +LL | #![deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the lint level is defined here - --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:9 + = note: see issue #71668 for more information + = help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable + +error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable + --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1 + | +LL | #![deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #71668 for more information + = help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable + +error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable + --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1 + | +LL | #![deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | #![deny(unused_unsafe)] - | ^^^^^^^^^^^^^ + = note: see issue #71668 for more information + = help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable -error: aborting due to previous error +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs index 0ffb2827bfde2..7feb68b98577f 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -21,6 +21,12 @@ unsafe fn baz() { #[allow(unsafe_op_in_unsafe_fn)] unsafe fn qux() { unsf(); // no error + + unsafe { unsf() } + //~^ ERROR unnecessary `unsafe` block } -fn main() {} +fn main() { + unsf() + //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block +} diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr index be6af2a11c40a..e812210498c4c 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr @@ -25,5 +25,20 @@ note: the lint level is defined here LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ -error: aborting due to previous error; 1 warning emitted +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:5 + | +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:30:5 + | +LL | unsf() + | ^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 3 previous errors; 1 warning emitted +For more information about this error, try `rustc --explain E0133`. From 3ce9d5c26982ff0516946dda7fa8d29580fa25b3 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 14 May 2020 20:37:23 +0200 Subject: [PATCH 19/44] Add more cases to the test --- .../unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs index 7feb68b98577f..618c911581597 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -1,16 +1,38 @@ #![feature(unsafe_block_in_unsafe_fn)] #![warn(unsafe_op_in_unsafe_fn)] #![deny(unused_unsafe)] +#![deny(safe_packed_borrows)] unsafe fn unsf() {} +const PTR: *const () = std::ptr::null(); +static mut VOID: () = (); + +#[repr(packed)] +pub struct Packed { + data: &'static u32, +} + +const PACKED: Packed = Packed { data: &0 }; unsafe fn foo() { unsf(); //~^ WARNING call to unsafe function is unsafe and requires unsafe block + *PTR; + //~^ WARNING dereference of raw pointer is unsafe and requires unsafe block + VOID = (); + //~^ WARNING use of mutable static is unsafe and requires unsafe block + &PACKED.data; // the level for the `safe_packed_borrows` lint is ignored + //~^ WARNING borrow of packed field is unsafe and requires unsafe block } unsafe fn bar() { - unsafe { unsf() } // no error + // no error + unsafe { + unsf(); + *PTR; + VOID = (); + &PACKED.data; + } } unsafe fn baz() { @@ -20,7 +42,11 @@ unsafe fn baz() { #[allow(unsafe_op_in_unsafe_fn)] unsafe fn qux() { - unsf(); // no error + // lint allowed -> no error + unsf(); + *PTR; + VOID = (); + &PACKED.data; unsafe { unsf() } //~^ ERROR unnecessary `unsafe` block From b3e012becc6539de9570eee6ce694f07879935d2 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Tue, 19 May 2020 00:18:50 +0200 Subject: [PATCH 20/44] Fix inverted `if` condition --- src/librustc_mir/transform/check_unsafety.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 0434f3447bced..3cff214f441c0 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -676,7 +676,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { { // Report an error. let unsafe_fn_msg = - if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { "" } else { " function or" }; + if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" }; match kind { UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { From a41f76321a05ce7941d843dc18ea11f7c8a11c6f Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Tue, 19 May 2020 00:19:31 +0200 Subject: [PATCH 21/44] Use the lowest of `unsafe_op_in_unsafe_fn` and `safe_borrow_packed` for packed borrows in unsafe fns --- src/librustc_middle/mir/query.rs | 4 +++ src/librustc_mir/transform/check_unsafety.rs | 33 +++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs index c63d7215867c2..99bfb74c243b4 100644 --- a/src/librustc_middle/mir/query.rs +++ b/src/librustc_middle/mir/query.rs @@ -26,6 +26,10 @@ pub enum UnsafetyViolationKind { /// Has to be handled as a lint for backwards compatibility. /// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`. UnsafeFn, + /// Borrow of packed field in an `unsafe fn` but outside an `unsafe` block. + /// Has to be handled as a lint for backwards compatibility. + /// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`. + UnsafeFnBorrowPacked, } #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 3cff214f441c0..177efa2fc0d6c 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -370,7 +370,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { violation.kind = UnsafetyViolationKind::General; } } - UnsafetyViolationKind::UnsafeFn => { + UnsafetyViolationKind::UnsafeFn + | UnsafetyViolationKind::UnsafeFnBorrowPacked => { bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") } } @@ -385,8 +386,11 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { for violation in violations { let mut violation = *violation; - // FIXME(LeSeulArtichaut): what to do with `UnsafetyViolationKind::BorrowPacked`? - violation.kind = UnsafetyViolationKind::UnsafeFn; + if violation.kind == UnsafetyViolationKind::BorrowPacked { + violation.kind = UnsafetyViolationKind::UnsafeFnBorrowPacked; + } else { + violation.kind = UnsafetyViolationKind::UnsafeFn; + } if !self.violations.contains(&violation) { self.violations.push(violation) } @@ -418,7 +422,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { self.violations.push(violation) } } - UnsafetyViolationKind::UnsafeFn => bug!( + UnsafetyViolationKind::UnsafeFn + | UnsafetyViolationKind::UnsafeFnBorrowPacked => bug!( "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context" ), } @@ -719,13 +724,31 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { |lint| { lint.build(&format!( "{} is unsafe and requires unsafe block (error E0133)", - description + description, )) .span_label(source_info.span, &*description.as_str()) .note(&details.as_str()) .emit(); }, ), + UnsafetyViolationKind::UnsafeFnBorrowPacked => { + let lint = if tcx.lint_level_at_node(SAFE_PACKED_BORROWS, lint_root).0 + <= tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, lint_root).0 + { + SAFE_PACKED_BORROWS + } else { + UNSAFE_OP_IN_UNSAFE_FN + }; + tcx.struct_span_lint_hir(&lint, lint_root, source_info.span, |lint| { + lint.build(&format!( + "{} is unsafe and requires unsafe block (error E0133)", + description, + )) + .span_label(source_info.span, &*description.as_str()) + .note(&details.as_str()) + .emit(); + }) + } } } From a3bae5ce73a65671ee35037ac988766973628295 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Tue, 19 May 2020 12:16:40 +0200 Subject: [PATCH 22/44] Fix wrong conflict resolution --- src/librustc_mir/transform/check_unsafety.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 177efa2fc0d6c..7be640ae24310 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -204,18 +204,12 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { if context.is_borrow() { if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { - let source_info = self.source_info; - let lint_root = self.body.source_scopes[source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .lint_root; self.require_unsafe( "borrow of packed field", "fields of packed structs might be misaligned: dereferencing a \ misaligned pointer or even just creating a misaligned reference \ is undefined behavior", - UnsafetyViolationKind::BorrowPacked(lint_root), + UnsafetyViolationKind::BorrowPacked, ); } } From 925d5ac45f4a44dd61f1ebd4b7bd3cc89fcb2b5f Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 21 May 2020 23:53:12 +0200 Subject: [PATCH 23/44] Fix and bless tests --- .../unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 71 +++++++++-- .../rfc-2585-unsafe_op_in_unsafe_fn.stderr | 118 ++++++++++++++++-- 2 files changed, 168 insertions(+), 21 deletions(-) diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs index 618c911581597..6dfb97c230d66 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -1,5 +1,5 @@ #![feature(unsafe_block_in_unsafe_fn)] -#![warn(unsafe_op_in_unsafe_fn)] +#![deny(unsafe_op_in_unsafe_fn)] #![deny(unused_unsafe)] #![deny(safe_packed_borrows)] @@ -14,18 +14,34 @@ pub struct Packed { const PACKED: Packed = Packed { data: &0 }; -unsafe fn foo() { +unsafe fn deny_level() { unsf(); - //~^ WARNING call to unsafe function is unsafe and requires unsafe block + //~^ ERROR call to unsafe function is unsafe and requires unsafe block *PTR; - //~^ WARNING dereference of raw pointer is unsafe and requires unsafe block + //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block VOID = (); - //~^ WARNING use of mutable static is unsafe and requires unsafe block - &PACKED.data; // the level for the `safe_packed_borrows` lint is ignored - //~^ WARNING borrow of packed field is unsafe and requires unsafe block + //~^ ERROR use of mutable static is unsafe and requires unsafe block + &PACKED.data; + //~^ ERROR borrow of packed field is unsafe and requires unsafe block + //~| WARNING this was previously accepted by the compiler but is being phased out } -unsafe fn bar() { +// Check that `unsafe_op_in_unsafe_fn` works starting from the `warn` level. +#[warn(unsafe_op_in_unsafe_fn)] +#[deny(warnings)] +unsafe fn warning_level() { + unsf(); + //~^ ERROR call to unsafe function is unsafe and requires unsafe block + *PTR; + //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block + VOID = (); + //~^ ERROR use of mutable static is unsafe and requires unsafe block + &PACKED.data; + //~^ ERROR borrow of packed field is unsafe and requires unsafe block + //~| WARNING this was previously accepted by the compiler but is being phased out +} + +unsafe fn explicit_block() { // no error unsafe { unsf(); @@ -35,13 +51,25 @@ unsafe fn bar() { } } -unsafe fn baz() { +unsafe fn two_explicit_blocks() { unsafe { unsafe { unsf() } } //~^ ERROR unnecessary `unsafe` block } +#[warn(safe_packed_borrows)] +unsafe fn warn_packed_borrows() { + &PACKED.data; + //~^ WARNING borrow of packed field is unsafe and requires unsafe block + //~| WARNING this was previously accepted by the compiler but is being phased out +} + +#[allow(safe_packed_borrows)] +unsafe fn allow_packed_borrows() { + &PACKED.data; // `safe_packed_borrows` is allowed, no error +} + #[allow(unsafe_op_in_unsafe_fn)] -unsafe fn qux() { +unsafe fn allow_level() { // lint allowed -> no error unsf(); *PTR; @@ -52,7 +80,26 @@ unsafe fn qux() { //~^ ERROR unnecessary `unsafe` block } +unsafe fn nested_allow_level() { + #[allow(unsafe_op_in_unsafe_fn)] + { + // lint allowed -> no error + unsf(); + *PTR; + VOID = (); + &PACKED.data; + + unsafe { unsf() } + //~^ ERROR unnecessary `unsafe` block + } +} + fn main() { - unsf() - //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block + unsf(); + //~^ ERROR call to unsafe function is unsafe and requires unsafe block + #[allow(unsafe_op_in_unsafe_fn)] + { + unsf(); + //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block + } } diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr index e812210498c4c..efc53f0b28b29 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr @@ -1,5 +1,5 @@ -warning: call to unsafe function is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:8:5 +error: call to unsafe function is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:18:5 | LL | unsf(); | ^^^^^^ call to unsafe function @@ -7,12 +7,83 @@ LL | unsf(); note: the lint level is defined here --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9 | -LL | #![warn(unsafe_op_in_unsafe_fn)] +LL | #![deny(unsafe_op_in_unsafe_fn)] | ^^^^^^^^^^^^^^^^^^^^^^ = note: consult the function's documentation for information on how to avoid undefined behavior +error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:5 + | +LL | *PTR; + | ^^^^ dereference of raw pointer + | + = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: use of mutable static is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:5 + | +LL | VOID = (); + | ^^^^^^^^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9 + | +LL | #![deny(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: call to unsafe function is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:8 + | +LL | #[deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]` + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:35:5 + | +LL | *PTR; + | ^^^^ dereference of raw pointer + | + = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: use of mutable static is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:37:5 + | +LL | VOID = (); + | ^^^^^^^^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:39:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:17:14 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:55:14 | LL | unsafe { unsafe { unsf() } } | ------ ^^^^^^ unnecessary `unsafe` block @@ -25,20 +96,49 @@ note: the lint level is defined here LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ +warning: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:61:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:59:8 + | +LL | #[warn(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:79:5 | LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block -error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:30:5 +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:92:9 | -LL | unsf() +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error[E0133]: call to unsafe function is unsafe and requires unsafe block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:98:5 + | +LL | unsf(); | ^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to 3 previous errors; 1 warning emitted +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:102:9 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 13 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0133`. From 9671b44609d2adbf041fcc5f8b63183786417ba7 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Fri, 22 May 2020 20:21:26 +0200 Subject: [PATCH 24/44] Add tests for packed borrows in unsafe fns --- ...c-2585-safe_packed_borrows-in-unsafe-fn.rs | 67 +++++++++++++++++++ ...85-safe_packed_borrows-in-unsafe-fn.stderr | 60 +++++++++++++++++ .../unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 29 -------- .../rfc-2585-unsafe_op_in_unsafe_fn.stderr | 66 ++++-------------- 4 files changed, 140 insertions(+), 82 deletions(-) create mode 100644 src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs create mode 100644 src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr diff --git a/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs new file mode 100644 index 0000000000000..540612a7dce05 --- /dev/null +++ b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs @@ -0,0 +1,67 @@ +#![feature(unsafe_block_in_unsafe_fn)] + +#[repr(packed)] +pub struct Packed { + data: &'static u32, +} + +const PACKED: Packed = Packed { data: &0 }; + +#[allow(safe_packed_borrows)] +#[allow(unsafe_op_in_unsafe_fn)] +unsafe fn allow_allow() { + &PACKED.data; // allowed +} + +#[allow(safe_packed_borrows)] +#[warn(unsafe_op_in_unsafe_fn)] +unsafe fn allow_warn() { + &PACKED.data; // allowed +} + +#[allow(safe_packed_borrows)] +#[deny(unsafe_op_in_unsafe_fn)] +unsafe fn allow_deny() { + &PACKED.data; // allowed +} + +#[warn(safe_packed_borrows)] +#[allow(unsafe_op_in_unsafe_fn)] +unsafe fn warn_allow() { + &PACKED.data; // allowed +} + +#[warn(safe_packed_borrows)] +#[warn(unsafe_op_in_unsafe_fn)] +unsafe fn warn_warn() { + &PACKED.data; //~ WARN + //~| WARNING this was previously accepted by the compiler but is being phased out +} + +#[warn(safe_packed_borrows)] +#[deny(unsafe_op_in_unsafe_fn)] +unsafe fn warn_deny() { + &PACKED.data; //~ WARN + //~| WARNING this was previously accepted by the compiler but is being phased out +} + +#[deny(safe_packed_borrows)] +#[allow(unsafe_op_in_unsafe_fn)] +unsafe fn deny_allow() { + &PACKED.data; // allowed +} + +#[deny(safe_packed_borrows)] +#[warn(unsafe_op_in_unsafe_fn)] +unsafe fn deny_warn() { + &PACKED.data; //~ WARN +} + +#[deny(safe_packed_borrows)] +#[deny(unsafe_op_in_unsafe_fn)] +unsafe fn deny_deny() { + &PACKED.data; //~ ERROR + //~| WARNING this was previously accepted by the compiler but is being phased out +} + +fn main() {} diff --git a/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr new file mode 100644 index 0000000000000..fda15159643b6 --- /dev/null +++ b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr @@ -0,0 +1,60 @@ +warning: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:37:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:34:8 + | +LL | #[warn(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +warning: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:44:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:41:8 + | +LL | #[warn(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +warning: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:57:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:55:8 + | +LL | #[warn(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:63:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:60:8 + | +LL | #[deny(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: aborting due to previous error; 3 warnings emitted + diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs index 6dfb97c230d66..1e57b03ced48b 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -1,19 +1,11 @@ #![feature(unsafe_block_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)] #![deny(unused_unsafe)] -#![deny(safe_packed_borrows)] unsafe fn unsf() {} const PTR: *const () = std::ptr::null(); static mut VOID: () = (); -#[repr(packed)] -pub struct Packed { - data: &'static u32, -} - -const PACKED: Packed = Packed { data: &0 }; - unsafe fn deny_level() { unsf(); //~^ ERROR call to unsafe function is unsafe and requires unsafe block @@ -21,9 +13,6 @@ unsafe fn deny_level() { //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block VOID = (); //~^ ERROR use of mutable static is unsafe and requires unsafe block - &PACKED.data; - //~^ ERROR borrow of packed field is unsafe and requires unsafe block - //~| WARNING this was previously accepted by the compiler but is being phased out } // Check that `unsafe_op_in_unsafe_fn` works starting from the `warn` level. @@ -36,9 +25,6 @@ unsafe fn warning_level() { //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block VOID = (); //~^ ERROR use of mutable static is unsafe and requires unsafe block - &PACKED.data; - //~^ ERROR borrow of packed field is unsafe and requires unsafe block - //~| WARNING this was previously accepted by the compiler but is being phased out } unsafe fn explicit_block() { @@ -47,7 +33,6 @@ unsafe fn explicit_block() { unsf(); *PTR; VOID = (); - &PACKED.data; } } @@ -56,25 +41,12 @@ unsafe fn two_explicit_blocks() { //~^ ERROR unnecessary `unsafe` block } -#[warn(safe_packed_borrows)] -unsafe fn warn_packed_borrows() { - &PACKED.data; - //~^ WARNING borrow of packed field is unsafe and requires unsafe block - //~| WARNING this was previously accepted by the compiler but is being phased out -} - -#[allow(safe_packed_borrows)] -unsafe fn allow_packed_borrows() { - &PACKED.data; // `safe_packed_borrows` is allowed, no error -} - #[allow(unsafe_op_in_unsafe_fn)] unsafe fn allow_level() { // lint allowed -> no error unsf(); *PTR; VOID = (); - &PACKED.data; unsafe { unsf() } //~^ ERROR unnecessary `unsafe` block @@ -87,7 +59,6 @@ unsafe fn nested_allow_level() { unsf(); *PTR; VOID = (); - &PACKED.data; unsafe { unsf() } //~^ ERROR unnecessary `unsafe` block diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr index efc53f0b28b29..cc595df12cc44 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr @@ -1,5 +1,5 @@ error: call to unsafe function is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:18:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:10:5 | LL | unsf(); | ^^^^^^ call to unsafe function @@ -12,7 +12,7 @@ LL | #![deny(unsafe_op_in_unsafe_fn)] = note: consult the function's documentation for information on how to avoid undefined behavior error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5 | LL | *PTR; | ^^^^ dereference of raw pointer @@ -20,36 +20,21 @@ LL | *PTR; = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: use of mutable static is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5 | LL | VOID = (); | ^^^^^^^^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: borrow of packed field is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5 - | -LL | &PACKED.data; - | ^^^^^^^^^^^^ borrow of packed field - | -note: the lint level is defined here - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9 - | -LL | #![deny(safe_packed_borrows)] - | ^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - error: call to unsafe function is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:5 | LL | unsf(); | ^^^^^^ call to unsafe function | note: the lint level is defined here - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:8 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:8 | LL | #[deny(warnings)] | ^^^^^^^^ @@ -57,7 +42,7 @@ LL | #[deny(warnings)] = note: consult the function's documentation for information on how to avoid undefined behavior error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:35:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5 | LL | *PTR; | ^^^^ dereference of raw pointer @@ -65,25 +50,15 @@ LL | *PTR; = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: use of mutable static is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:37:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:5 | LL | VOID = (); | ^^^^^^^^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: borrow of packed field is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:39:5 - | -LL | &PACKED.data; - | ^^^^^^^^^^^^ borrow of packed field - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:55:14 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:40:14 | LL | unsafe { unsafe { unsf() } } | ------ ^^^^^^ unnecessary `unsafe` block @@ -96,35 +71,20 @@ note: the lint level is defined here LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ -warning: borrow of packed field is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:61:5 - | -LL | &PACKED.data; - | ^^^^^^^^^^^^ borrow of packed field - | -note: the lint level is defined here - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:59:8 - | -LL | #[warn(safe_packed_borrows)] - | ^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:79:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:51:5 | LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:92:9 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:63:9 | LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error[E0133]: call to unsafe function is unsafe and requires unsafe block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:98:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:69:5 | LL | unsf(); | ^^^^^^ call to unsafe function @@ -132,13 +92,13 @@ LL | unsf(); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:102:9 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:73:9 | LL | unsf(); | ^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to 13 previous errors; 1 warning emitted +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0133`. From 3599ada976568d0b5326e890d4b0c2f22dcdc985 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 23 May 2020 22:15:14 +0200 Subject: [PATCH 25/44] Mark deduplicated errors as expected in gate test --- .../ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs index bf33ac67fcae9..61e512a12a18d 100644 --- a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs +++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs @@ -1,4 +1,6 @@ #![deny(unsafe_op_in_unsafe_fn)] //~^ ERROR the `unsafe_op_in_unsafe_fn` lint is unstable +//~| ERROR the `unsafe_op_in_unsafe_fn` lint is unstable +//~| ERROR the `unsafe_op_in_unsafe_fn` lint is unstable fn main() {} From 4a538d31e056c7563d7e29a6bc7c89e9e46d8ee8 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 23 May 2020 22:22:01 +0200 Subject: [PATCH 26/44] Do not hardcode lint name --- src/librustc_lint/levels.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 7069472015402..2e3fc162b530f 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -9,6 +9,7 @@ use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::{intravisit, HirId}; +use rustc_lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; use rustc_middle::hir::map::Map; use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource}; @@ -387,7 +388,7 @@ impl<'s> LintLevelsBuilder<'s> { } fn check_gated_lint(&self, name: Symbol, span: Span) { - if name.as_str() == "unsafe_op_in_unsafe_fn" + if name.as_str() == UNSAFE_OP_IN_UNSAFE_FN.name && !self.sess.features_untracked().unsafe_block_in_unsafe_fn { feature_err( From e3d27ec1c82e223277b16f30e2355056144ca0da Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 23 May 2020 22:32:40 +0200 Subject: [PATCH 27/44] Add explanation about taking the minimum of the two lints --- src/librustc_mir/transform/check_unsafety.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 7be640ae24310..1f01bc0e19513 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -726,6 +726,17 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { }, ), UnsafetyViolationKind::UnsafeFnBorrowPacked => { + // When `unsafe_op_in_unsafe_fn` is disallowed, the behavior of safe and unsafe functions + // should be the same in terms of warnings and errors. Therefore, with `#[warn(safe_packed_borrows)]`, + // a safe packed borrow should emit a warning *but not an error* in an unsafe function, + // just like in a safe function, even if `unsafe_op_in_unsafe_fn` is `deny`. + // + // Also, `#[warn(unsafe_op_in_unsafe_fn)]` can't cause any new errors. Therefore, with + // `#[deny(safe_packed_borrows)]` and `#[warn(unsafe_op_in_unsafe_fn)]`, a packed borrow + // should only issue a warning for the sake of backwards compatibility. + // + // The solution those 2 expectations is to always take the minimum of both lints. + // This prevent any new errors (unless both lints are explicitely set to `deny`). let lint = if tcx.lint_level_at_node(SAFE_PACKED_BORROWS, lint_root).0 <= tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, lint_root).0 { From 1b0885062266a21e67fdeb12320c92ac7c00742e Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 23 May 2020 22:39:07 +0200 Subject: [PATCH 28/44] Fix import --- src/librustc_lint/levels.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 2e3fc162b530f..8dd683ae7995d 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -9,7 +9,6 @@ use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::{intravisit, HirId}; -use rustc_lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; use rustc_middle::hir::map::Map; use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource}; @@ -388,7 +387,7 @@ impl<'s> LintLevelsBuilder<'s> { } fn check_gated_lint(&self, name: Symbol, span: Span) { - if name.as_str() == UNSAFE_OP_IN_UNSAFE_FN.name + if name.as_str() == builtin::UNSAFE_OP_IN_UNSAFE_FN.name && !self.sess.features_untracked().unsafe_block_in_unsafe_fn { feature_err( From 63066c0c06de27bc84f7fbbe683b59d4cb0441db Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 23 May 2020 23:11:55 +0200 Subject: [PATCH 29/44] Use `LintId`s to check for gated lints --- src/librustc_lint/levels.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 8dd683ae7995d..3d2ddf12a0a1f 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -14,7 +14,7 @@ use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_session::lint::{builtin, Level, Lint}; +use rustc_session::lint::{builtin, Level, Lint, LintId}; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; @@ -80,13 +80,13 @@ impl<'s> LintLevelsBuilder<'s> { let level = cmp::min(level, self.sets.lint_cap); let lint_flag_val = Symbol::intern(lint_name); - self.check_gated_lint(lint_flag_val, DUMMY_SP); let ids = match store.find_lints(&lint_name) { Ok(ids) => ids, Err(_) => continue, // errors handled in check_lint_name_cmdline above }; for id in ids { + self.check_gated_lint(id, DUMMY_SP); let src = LintSource::CommandLine(lint_flag_val); specs.insert(id, (level, src)); } @@ -213,9 +213,9 @@ impl<'s> LintLevelsBuilder<'s> { let name = meta_item.path.segments.last().expect("empty lint name").ident.name; match store.check_lint_name(&name.as_str(), tool_name) { CheckLintNameResult::Ok(ids) => { - self.check_gated_lint(name, attr.span); let src = LintSource::Node(name, li.span(), reason); for id in ids { + self.check_gated_lint(*id, attr.span); specs.insert(*id, (level, src)); } } @@ -386,8 +386,8 @@ impl<'s> LintLevelsBuilder<'s> { BuilderPush { prev, changed: prev != self.cur } } - fn check_gated_lint(&self, name: Symbol, span: Span) { - if name.as_str() == builtin::UNSAFE_OP_IN_UNSAFE_FN.name + fn check_gated_lint(&self, id: LintId, span: Span) { + if id == LintId::of(builtin::UNSAFE_OP_IN_UNSAFE_FN) && !self.sess.features_untracked().unsafe_block_in_unsafe_fn { feature_err( From db684beb4e40aae70a38e22e4aa91251349bf49b Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 27 May 2020 19:32:00 +0200 Subject: [PATCH 30/44] Whitelist `unsafe_op_in_unsafe_fn` in rustdoc --- src/librustdoc/core.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index bf59b3f25734d..331ce1453e139 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -226,6 +226,11 @@ where { let warnings_lint_name = lint::builtin::WARNINGS.name; + // Whitelist feature-gated lints to avoid feature errors when trying to + // allow all lints. + // FIXME(LeSeulArtichaut): handle feature-gated lints properly. + let unsafe_op_in_unsafe_fn_name = rustc_lint::builtin::UNSAFE_OP_IN_UNSAFE_FN.name; + whitelisted_lints.push(warnings_lint_name.to_owned()); whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); @@ -236,7 +241,13 @@ where }; let lint_opts = lints() - .filter_map(|lint| if lint.name == warnings_lint_name { None } else { filter_call(lint) }) + .filter_map(|lint| { + if lint.name == warnings_lint_name || lint.name == unsafe_op_in_unsafe_fn_name { + None + } else { + filter_call(lint) + } + }) .chain(lint_opts.into_iter()) .collect::>(); From 3fea832fd7cbff73cf8d5d409ea9aeee0577b0ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 19 Dec 2019 19:44:06 -0800 Subject: [PATCH 31/44] Fix spacing of expected/found notes without a label --- src/librustc_errors/diagnostic.rs | 15 ++++++++++++--- .../project-fn-ret-invariant.transmute.stderr | 8 ++++---- .../dyn-trait.stderr | 8 ++++---- src/test/ui/issues/issue-16683.stderr | 4 ++-- src/test/ui/issues/issue-17758.stderr | 4 ++-- src/test/ui/issues/issue-20831-debruijn.stderr | 4 ++-- src/test/ui/issues/issue-52213.stderr | 4 ++-- src/test/ui/issues/issue-55796.stderr | 8 ++++---- src/test/ui/nll/issue-55394.stderr | 4 ++-- .../ui/nll/normalization-bounds-error.stderr | 4 ++-- src/test/ui/nll/type-alias-free-regions.stderr | 16 ++++++++-------- .../constant-in-expr-inherent-1.stderr | 4 ++-- .../constant-in-expr-trait-item-3.stderr | 4 ++-- .../object-lifetime-default-elision.stderr | 8 ++++---- .../region-object-lifetime-in-coercion.stderr | 8 ++++---- ...soc-type-region-bound-in-trait-not-met.stderr | 8 ++++---- ...soc-type-static-bound-in-trait-not-met.stderr | 4 ++-- .../regions-close-object-into-object-2.stderr | 4 ++-- .../regions-close-object-into-object-4.stderr | 4 ++-- ...ons-close-over-type-parameter-multiple.stderr | 4 ++-- .../ui/regions/regions-creating-enums4.stderr | 8 ++++---- src/test/ui/regions/regions-nested-fns.stderr | 4 ++-- ...regions-normalize-in-where-clause-list.stderr | 4 ++-- .../ui/regions/regions-ret-borrowed-1.stderr | 4 ++-- src/test/ui/regions/regions-ret-borrowed.stderr | 4 ++-- .../regions-trait-object-subtyping.stderr | 4 ++-- src/test/ui/reject-specialized-drops-8142.stderr | 4 ++-- ...pertrait-has-wrong-lifetime-parameters.stderr | 4 ++-- .../dyn-trait-underscore.stderr | 4 ++-- 29 files changed, 88 insertions(+), 79 deletions(-) diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 1cc5daafed14e..cff83c3d5cda2 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -193,9 +193,18 @@ impl Diagnostic { expected_extra: &dyn fmt::Display, found_extra: &dyn fmt::Display, ) -> &mut Self { - let expected_label = format!("expected {}", expected_label); - - let found_label = format!("found {}", found_label); + let expected_label = expected_label.to_string(); + let expected_label = if expected_label.is_empty() { + "expected".to_string() + } else { + format!("expected {}", expected_label) + }; + let found_label = found_label.to_string(); + let found_label = if found_label.is_empty() { + "found".to_string() + } else { + format!("found {}", found_label) + }; let (found_padding, expected_padding) = if expected_label.len() > found_label.len() { (expected_label.len() - found_label.len(), 0) } else { diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index 3e39c8a792446..137cb83ccd327 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -14,16 +14,16 @@ note: ...so that the expression is assignable | LL | bar(foo, x) | ^ - = note: expected `Type<'_>` - found `Type<'a>` + = note: expected `Type<'_>` + found `Type<'a>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that the expression is assignable --> $DIR/project-fn-ret-invariant.rs:48:4 | LL | bar(foo, x) | ^^^^^^^^^^^ - = note: expected `Type<'static>` - found `Type<'_>` + = note: expected `Type<'static>` + found `Type<'_>` error: aborting due to previous error diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index 3300293bb36ca..268008c211129 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -14,16 +14,16 @@ note: ...so that the expression is assignable | LL | static_val(x); | ^ - = note: expected `std::boxed::Box` - found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>` + = note: expected `std::boxed::Box` + found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that the types are compatible --> $DIR/dyn-trait.rs:20:5 | LL | static_val(x); | ^^^^^^^^^^ - = note: expected `StaticTrait` - found `StaticTrait` + = note: expected `StaticTrait` + found `StaticTrait` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr index 99700f2084e4a..4f65833075814 100644 --- a/src/test/ui/issues/issue-16683.stderr +++ b/src/test/ui/issues/issue-16683.stderr @@ -26,8 +26,8 @@ note: ...so that the types are compatible | LL | self.a(); | ^ - = note: expected `&'a Self` - found `&Self` + = note: expected `&'a Self` + found `&Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr index adfc3f5085826..31788cfa61c4c 100644 --- a/src/test/ui/issues/issue-17758.stderr +++ b/src/test/ui/issues/issue-17758.stderr @@ -27,8 +27,8 @@ note: ...so that the types are compatible | LL | self.foo(); | ^^^ - = note: expected `&'a Self` - found `&Self` + = note: expected `&'a Self` + found `&Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr index a785a956ca9f5..160a4213a4043 100644 --- a/src/test/ui/issues/issue-20831-debruijn.stderr +++ b/src/test/ui/issues/issue-20831-debruijn.stderr @@ -117,8 +117,8 @@ note: ...so that the types are compatible | LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `Publisher<'_>` - found `Publisher<'_>` + = note: expected `Publisher<'_>` + found `Publisher<'_>` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-52213.stderr b/src/test/ui/issues/issue-52213.stderr index a8960f7756367..7463af9332a76 100644 --- a/src/test/ui/issues/issue-52213.stderr +++ b/src/test/ui/issues/issue-52213.stderr @@ -14,8 +14,8 @@ note: ...so that the types are compatible | LL | match (&t,) { | ^^^^^ - = note: expected `(&&(T,),)` - found `(&&'a (T,),)` + = note: expected `(&&(T,),)` + found `(&&'a (T,),)` note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 1:27... --> $DIR/issue-52213.rs:1:27 | diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr index b8cafdc5c14b5..6bfb7af54446d 100644 --- a/src/test/ui/issues/issue-55796.stderr +++ b/src/test/ui/issues/issue-55796.stderr @@ -20,8 +20,8 @@ note: ...so that the expression is assignable | LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` - found `std::boxed::Box>::Node>>` + = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` + found `std::boxed::Box>::Node>>` error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/issue-55796.rs:21:9 @@ -45,8 +45,8 @@ note: ...so that the expression is assignable | LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` - found `std::boxed::Box>::Node>>` + = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` + found `std::boxed::Box>::Node>>` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/issue-55394.stderr b/src/test/ui/nll/issue-55394.stderr index 69a6ab004fd91..ba8d91b8455bf 100644 --- a/src/test/ui/nll/issue-55394.stderr +++ b/src/test/ui/nll/issue-55394.stderr @@ -26,8 +26,8 @@ note: ...so that the expression is assignable | LL | Foo { bar } | ^^^^^^^^^^^ - = note: expected `Foo<'_>` - found `Foo<'_>` + = note: expected `Foo<'_>` + found `Foo<'_>` error: aborting due to previous error diff --git a/src/test/ui/nll/normalization-bounds-error.stderr b/src/test/ui/nll/normalization-bounds-error.stderr index 58f206742f4f5..d003acd879a77 100644 --- a/src/test/ui/nll/normalization-bounds-error.stderr +++ b/src/test/ui/nll/normalization-bounds-error.stderr @@ -19,8 +19,8 @@ note: ...so that the types are compatible | LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `Visitor<'d>` - found `Visitor<'_>` + = note: expected `Visitor<'d>` + found `Visitor<'_>` error: aborting due to previous error diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr index 5191deca281cc..3317aae83bb08 100644 --- a/src/test/ui/nll/type-alias-free-regions.stderr +++ b/src/test/ui/nll/type-alias-free-regions.stderr @@ -16,8 +16,8 @@ note: ...so that the expression is assignable | LL | C { f: b } | ^ - = note: expected `std::boxed::Box>` - found `std::boxed::Box>` + = note: expected `std::boxed::Box>` + found `std::boxed::Box>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6... --> $DIR/type-alias-free-regions.rs:15:6 | @@ -28,8 +28,8 @@ note: ...so that the expression is assignable | LL | C { f: b } | ^^^^^^^^^^ - = note: expected `C<'a>` - found `C<'_>` + = note: expected `C<'a>` + found `C<'_>` error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/type-alias-free-regions.rs:27:16 @@ -49,8 +49,8 @@ note: ...so that the expression is assignable | LL | C { f: Box::new(b.0) } | ^^^ - = note: expected `std::boxed::Box<&isize>` - found `std::boxed::Box<&isize>` + = note: expected `std::boxed::Box<&isize>` + found `std::boxed::Box<&isize>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6... --> $DIR/type-alias-free-regions.rs:25:6 | @@ -61,8 +61,8 @@ note: ...so that the expression is assignable | LL | C { f: Box::new(b.0) } | ^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `C<'a>` - found `C<'_>` + = note: expected `C<'a>` + found `C<'_>` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr index 37be450fd0a79..8421dc1d0c130 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr @@ -14,8 +14,8 @@ note: ...so that the types are compatible | LL | >::C | ^^^^^^^^^^^^ - = note: expected `Foo<'_>` - found `Foo<'a>` + = note: expected `Foo<'_>` + found `Foo<'a>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that reference does not outlive borrowed content --> $DIR/constant-in-expr-inherent-1.rs:8:5 diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr index 4ee32847c5ec8..ba0a1748c5e9f 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr @@ -14,8 +14,8 @@ note: ...so that the types are compatible | LL | T::C | ^^^^ - = note: expected `Foo<'_>` - found `Foo<'a>` + = note: expected `Foo<'_>` + found `Foo<'a>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that reference does not outlive borrowed content --> $DIR/constant-in-expr-trait-item-3.rs:10:5 diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr index 1952ee8269d5b..79ded5fc875a2 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr @@ -24,8 +24,8 @@ note: ...so that the expression is assignable | LL | ss | ^^ - = note: expected `&'b (dyn SomeTrait + 'b)` - found `&dyn SomeTrait` + = note: expected `&'b (dyn SomeTrait + 'b)` + found `&dyn SomeTrait` error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/object-lifetime-default-elision.rs:71:5 @@ -53,8 +53,8 @@ note: ...so that the expression is assignable | LL | ss | ^^ - = note: expected `&'b (dyn SomeTrait + 'b)` - found `&dyn SomeTrait` + = note: expected `&'b (dyn SomeTrait + 'b)` + found `&dyn SomeTrait` error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index e889651647034..069b897603cb9 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -39,8 +39,8 @@ note: ...so that the expression is assignable | LL | Box::new(v) | ^ - = note: expected `&[u8]` - found `&'a [u8]` + = note: expected `&[u8]` + found `&'a [u8]` note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9... --> $DIR/region-object-lifetime-in-coercion.rs:25:9 | @@ -51,8 +51,8 @@ note: ...so that the expression is assignable | LL | Box::new(v) | ^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn Foo + 'b)>` - found `std::boxed::Box` + = note: expected `std::boxed::Box<(dyn Foo + 'b)>` + found `std::boxed::Box` error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr index 865e967fba32e..c134b3b3ed554 100644 --- a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr +++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr @@ -14,8 +14,8 @@ note: ...so that the types are compatible | LL | impl<'a> Foo<'static> for &'a i32 { | ^^^^^^^^^^^^ - = note: expected `Foo<'static>` - found `Foo<'static>` + = note: expected `Foo<'static>` + found `Foo<'static>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that the type `&i32` will meet its required lifetime bounds --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10 @@ -39,8 +39,8 @@ note: ...so that the types are compatible | LL | impl<'a,'b> Foo<'b> for &'a i64 { | ^^^^^^^ - = note: expected `Foo<'b>` - found `Foo<'_>` + = note: expected `Foo<'b>` + found `Foo<'_>` note: but, the lifetime must be valid for the lifetime `'b` as defined on the impl at 19:9... --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:9 | diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr index 6a34871c07efd..ac8c55ccc8fd4 100644 --- a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr +++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr @@ -14,8 +14,8 @@ note: ...so that the types are compatible | LL | impl<'a> Foo for &'a i32 { | ^^^ - = note: expected `Foo` - found `Foo` + = note: expected `Foo` + found `Foo` = note: but, the lifetime must be valid for the static lifetime... note: ...so that the type `&i32` will meet its required lifetime bounds --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10 diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 28873ab807f8d..147f7f3541816 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -20,8 +20,8 @@ note: ...so that the expression is assignable | LL | box B(&*v) as Box | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn X + 'static)>` - found `std::boxed::Box` + = note: expected `std::boxed::Box<(dyn X + 'static)>` + found `std::boxed::Box` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 449a5b5fdd4d6..6e7d6152cd09a 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -20,8 +20,8 @@ note: ...so that the expression is assignable | LL | box B(&*v) as Box | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn X + 'static)>` - found `std::boxed::Box` + = note: expected `std::boxed::Box<(dyn X + 'static)>` + found `std::boxed::Box` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr index b2a7afaf1b452..2070ce257b18d 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr @@ -24,8 +24,8 @@ note: ...so that the expression is assignable | LL | box v as Box | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn SomeTrait + 'c)>` - found `std::boxed::Box` + = note: expected `std::boxed::Box<(dyn SomeTrait + 'c)>` + found `std::boxed::Box` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-creating-enums4.stderr b/src/test/ui/regions/regions-creating-enums4.stderr index 58f74e4ee142d..b24db1df18b0a 100644 --- a/src/test/ui/regions/regions-creating-enums4.stderr +++ b/src/test/ui/regions/regions-creating-enums4.stderr @@ -14,8 +14,8 @@ note: ...so that the expression is assignable | LL | Ast::Add(x, y) | ^ - = note: expected `&Ast<'_>` - found `&Ast<'a>` + = note: expected `&Ast<'_>` + found `&Ast<'a>` note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:19... --> $DIR/regions-creating-enums4.rs:6:19 | @@ -26,8 +26,8 @@ note: ...so that the expression is assignable | LL | Ast::Add(x, y) | ^^^^^^^^^^^^^^ - = note: expected `Ast<'b>` - found `Ast<'_>` + = note: expected `Ast<'b>` + found `Ast<'_>` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr index 8fce1609d7830..9e405d83140d8 100644 --- a/src/test/ui/regions/regions-nested-fns.stderr +++ b/src/test/ui/regions/regions-nested-fns.stderr @@ -39,8 +39,8 @@ LL | | if false { return ay; } LL | | return z; LL | | })); | |_____^ - = note: expected `&isize` - found `&isize` + = note: expected `&isize` + found `&isize` error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/regions-nested-fns.rs:14:27 diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr index c35516d2c0871..a274fd9d658a9 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -29,8 +29,8 @@ LL | | where <() as Project<'a, 'b>>::Item : Eq LL | | { LL | | } | |_^ - = note: expected `Project<'a, 'b>` - found `Project<'_, '_>` + = note: expected `Project<'a, 'b>` + found `Project<'_, '_>` error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/regions-normalize-in-where-clause-list.rs:22:1 diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr index 2895a0ccdeec8..2c4769d8e3751 100644 --- a/src/test/ui/regions/regions-ret-borrowed-1.stderr +++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr @@ -14,8 +14,8 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&isize` - found `&isize` + = note: expected `&isize` + found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14... --> $DIR/regions-ret-borrowed-1.rs:9:14 | diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr index b74f10f5075eb..da560107cea99 100644 --- a/src/test/ui/regions/regions-ret-borrowed.stderr +++ b/src/test/ui/regions/regions-ret-borrowed.stderr @@ -14,8 +14,8 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&isize` - found `&isize` + = note: expected `&isize` + found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14... --> $DIR/regions-ret-borrowed.rs:12:14 | diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr index 58b79d212700c..7478b53bd3ccc 100644 --- a/src/test/ui/regions/regions-trait-object-subtyping.stderr +++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr @@ -41,8 +41,8 @@ note: ...so that the expression is assignable | LL | x | ^ - = note: expected `&'b mut (dyn Dummy + 'b)` - found `&mut (dyn Dummy + 'b)` + = note: expected `&'b mut (dyn Dummy + 'b)` + found `&mut (dyn Dummy + 'b)` error[E0308]: mismatched types --> $DIR/regions-trait-object-subtyping.rs:22:5 diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr index c09418de51830..f819faa278995 100644 --- a/src/test/ui/reject-specialized-drops-8142.stderr +++ b/src/test/ui/reject-specialized-drops-8142.stderr @@ -118,8 +118,8 @@ note: ...so that the types are compatible | LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `W<'l1, 'l2>` - found `W<'_, '_>` + = note: expected `W<'l1, 'l2>` + found `W<'_, '_>` error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:61:14 diff --git a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr index 9fdcd4de495c0..46aa7db967ad4 100644 --- a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr +++ b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr @@ -19,8 +19,8 @@ note: ...so that the types are compatible | LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { | ^^^^^^^^^^ - = note: expected `T1<'a>` - found `T1<'_>` + = note: expected `T1<'a>` + found `T1<'_>` error: aborting due to previous error diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index e6029e0d4623a..e3c9d50dfe5b3 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -23,8 +23,8 @@ note: ...so that the expression is assignable | LL | Box::new(items.iter()) | ^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::iter::Iterator + 'static)>` - found `std::boxed::Box>` + = note: expected `std::boxed::Box<(dyn std::iter::Iterator + 'static)>` + found `std::boxed::Box>` error: aborting due to previous error From 5ba22205a48f3c4232a899effc47fa1925ed9900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 20 Dec 2019 11:56:03 -0800 Subject: [PATCH 32/44] Name `RegionKind::ReVar` lifetimes in diagnostics --- .../infer/error_reporting/mod.rs | 9 ++-- .../trait_impl_difference.rs | 51 ++++++++++++++++++- src/test/ui/coercion/coerce-mut.rs | 4 +- src/test/ui/coercion/coerce-mut.stderr | 4 +- .../reordered-type-param.stderr | 2 +- src/test/ui/hrtb/hrtb-exists-forall-fn.stderr | 2 +- .../impl-generic-mismatch-ab.stderr | 2 +- src/test/ui/impl-trait/trait_type.stderr | 2 +- .../mismatched_trait_impl-2.stderr | 4 +- .../mismatched_trait_impl.stderr | 4 +- src/test/ui/issues/issue-13033.rs | 2 +- src/test/ui/issues/issue-13033.stderr | 2 +- src/test/ui/issues/issue-16683.stderr | 2 +- src/test/ui/issues/issue-17758.stderr | 2 +- src/test/ui/issues/issue-20225.stderr | 8 ++- src/test/ui/issues/issue-21332.stderr | 2 +- ...ime-mismatch-between-trait-and-impl.stderr | 4 +- src/test/ui/mismatched_types/E0053.stderr | 2 +- .../trait-impl-fn-incompatibility.stderr | 2 +- .../ui/nll/type-alias-free-regions.stderr | 4 +- ...ons-fn-subtyping-return-static-fail.stderr | 2 +- .../region-object-lifetime-in-coercion.stderr | 2 +- .../regions-fn-subtyping-return-static.stderr | 2 +- src/test/ui/regions/regions-nested-fns.stderr | 2 +- .../ui/regions/regions-ret-borrowed-1.stderr | 2 +- .../ui/regions/regions-ret-borrowed.stderr | 2 +- src/test/ui/regions/regions-trait-1.stderr | 2 +- .../regions-trait-object-subtyping.stderr | 2 +- .../resolve-inconsistent-binding-mode.stderr | 4 +- src/test/ui/span/coerce-suggestions.stderr | 4 +- .../traits/trait-impl-method-mismatch.stderr | 2 +- src/test/ui/type/type-mismatch.stderr | 4 +- src/test/ui/unsafe/unsafe-trait-impl.rs | 2 +- src/test/ui/unsafe/unsafe-trait-impl.stderr | 2 +- src/test/ui/wrong-mul-method-signature.stderr | 2 +- 35 files changed, 105 insertions(+), 45 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index cc479aa17ce95..66e7c87f2c351 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -987,13 +987,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } fn push_ty_ref<'tcx>( - r: &ty::Region<'tcx>, + region: &ty::Region<'tcx>, ty: Ty<'tcx>, mutbl: hir::Mutability, s: &mut DiagnosticStyledString, ) { - let mut r = r.to_string(); - if r == "'_" { + let mut r = region.to_string(); + if let ty::RegionKind::ReVar(var) = region { + // Show these named, not as `'_` or elide them in "expected/found" notes. + r = format!("'z{} ", var.index()); + } else if r == "'_" { r.clear(); } else { r.push(' '); diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 695f3e47fb5d7..2e54a4e28e98c 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -1,11 +1,15 @@ //! Error Reporting for `impl` items that do not match the obligations from their `trait`. +use crate::hir::def_id::DefId; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{Subtype, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::ErrorReported; -use rustc_middle::ty::Ty; +use rustc_middle::ty::error::ExpectedFound; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Ty}; use rustc_span::Span; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -52,9 +56,52 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .tcx() .sess .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); - err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); err.span_label(sp, &format!("found {:?}", found)); err.span_label(impl_sp, &format!("expected {:?}", expected)); + + struct EarlyBoundRegionHighlighter(FxHashSet); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for EarlyBoundRegionHighlighter { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + debug!("LateBoundRegionNameCollector visit_region {:?}", r); + match *r { + ty::ReFree(free) => { + self.0.insert(free.scope); + } + + ty::ReEarlyBound(bound) => { + self.0.insert(bound.def_id); + } + _ => {} + } + r.super_visit_with(self) + } + } + + let mut visitor = EarlyBoundRegionHighlighter(FxHashSet::default()); + expected.visit_with(&mut visitor); + + let note = !visitor.0.is_empty(); + + if let Some((expected, found)) = self + .tcx() + .infer_ctxt() + .enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found })) + { + err.note_expected_found(&"", expected, &"", found); + } else { + // This fallback shouldn't be necessary, but let's keep it in just in case. + err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); + } + if note { + err.note( + "the lifetime requirements from the `trait` could not be fulfilled by the \ + `impl`", + ); + err.help( + "consider adding a named lifetime to the `trait` that constrains the item's \ + `self` argument, its inputs and its output with it", + ); + } err.emit(); } } diff --git a/src/test/ui/coercion/coerce-mut.rs b/src/test/ui/coercion/coerce-mut.rs index 43f0b55856d3c..3ccfe1cede7ac 100644 --- a/src/test/ui/coercion/coerce-mut.rs +++ b/src/test/ui/coercion/coerce-mut.rs @@ -4,7 +4,7 @@ fn main() { let x = 0; f(&x); //~^ ERROR mismatched types - //~| expected mutable reference `&mut i32` - //~| found reference `&{integer}` + //~| expected mutable reference `&'z1 mut i32` + //~| found reference `&'z2 {integer}` //~| types differ in mutability } diff --git a/src/test/ui/coercion/coerce-mut.stderr b/src/test/ui/coercion/coerce-mut.stderr index 2601ca5e91e5b..f5b13f6c59099 100644 --- a/src/test/ui/coercion/coerce-mut.stderr +++ b/src/test/ui/coercion/coerce-mut.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | f(&x); | ^^ types differ in mutability | - = note: expected mutable reference `&mut i32` - found reference `&{integer}` + = note: expected mutable reference `&'z1 mut i32` + found reference `&'z2 {integer}` error: aborting due to previous error diff --git a/src/test/ui/compare-method/reordered-type-param.stderr b/src/test/ui/compare-method/reordered-type-param.stderr index f1f8a663f2120..9eed16fa994e3 100644 --- a/src/test/ui/compare-method/reordered-type-param.stderr +++ b/src/test/ui/compare-method/reordered-type-param.stderr @@ -11,7 +11,7 @@ LL | fn b(&self, _x: G) -> G { panic!() } | expected type parameter | = note: expected fn pointer `fn(&E, F) -> F` - found fn pointer `fn(&E, G) -> G` + found fn pointer `fn(&'z0 E, G) -> G` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr index 328e98657effb..4d09fe74e16fc 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -7,7 +7,7 @@ LL | let _: for<'b> fn(&'b u32) = foo(); | expected due to this | = note: expected fn pointer `for<'b> fn(&'b u32)` - found fn pointer `fn(&u32)` + found fn pointer `fn(&'z0 u32)` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr index 638a0093fb21d..d5725efbac3c6 100644 --- a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr +++ b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr @@ -10,7 +10,7 @@ LL | fn foo(&self, a: &impl Debug, b: &B) { } | expected type parameter | = note: expected fn pointer `fn(&(), &B, &impl Debug)` - found fn pointer `fn(&(), &impl Debug, &B)` + found fn pointer `fn(&'z0 (), &impl Debug, &B)` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr index 748bc639a03c2..3cc9c1a7fb054 100644 --- a/src/test/ui/impl-trait/trait_type.stderr +++ b/src/test/ui/impl-trait/trait_type.stderr @@ -5,7 +5,7 @@ LL | fn fmt(&self, x: &str) -> () { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` - found fn pointer `fn(&MyType, &str)` + found fn pointer `fn(&'z0 MyType, &str)` error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2 --> $DIR/trait_type.rs:12:11 diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index c1c4ec9ed7b92..349f813b20d50 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -10,7 +10,9 @@ LL | fn deref(&self) -> &Self::Target; | --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static) | = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` - found `fn(&Struct) -> &dyn Trait` + found `fn(&'z0 Struct) -> &dyn Trait` + = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index 15891c9e7a62d..72960a41f93df 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -8,7 +8,9 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32 | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` - found `fn(&i32, &u32, &u32) -> &u32` + found `fn(&'z0 i32, &'z1 u32, &'z2 u32) -> &'z2 u32` + = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it error[E0623]: lifetime mismatch --> $DIR/mismatched_trait_impl.rs:10:9 diff --git a/src/test/ui/issues/issue-13033.rs b/src/test/ui/issues/issue-13033.rs index 7631831a81a5b..3fa94fac23759 100644 --- a/src/test/ui/issues/issue-13033.rs +++ b/src/test/ui/issues/issue-13033.rs @@ -8,7 +8,7 @@ impl Foo for Baz { fn bar(&mut self, other: &dyn Foo) {} //~^ ERROR method `bar` has an incompatible type for trait //~| expected fn pointer `fn(&mut Baz, &mut dyn Foo)` - //~| found fn pointer `fn(&mut Baz, &dyn Foo)` + //~| found fn pointer `fn(&'z0 mut Baz, &dyn Foo)` } fn main() {} diff --git a/src/test/ui/issues/issue-13033.stderr b/src/test/ui/issues/issue-13033.stderr index a8473c8a52413..238f41782ba5a 100644 --- a/src/test/ui/issues/issue-13033.stderr +++ b/src/test/ui/issues/issue-13033.stderr @@ -8,7 +8,7 @@ LL | fn bar(&mut self, other: &dyn Foo) {} | ^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)` - found fn pointer `fn(&mut Baz, &dyn Foo)` + found fn pointer `fn(&'z0 mut Baz, &dyn Foo)` help: consider change the type to match the mutability in trait | LL | fn bar(&mut self, other: &mut dyn Foo) {} diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr index 4f65833075814..fa782d043312d 100644 --- a/src/test/ui/issues/issue-16683.stderr +++ b/src/test/ui/issues/issue-16683.stderr @@ -27,7 +27,7 @@ note: ...so that the types are compatible LL | self.a(); | ^ = note: expected `&'a Self` - found `&Self` + found `&'z0 Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr index 31788cfa61c4c..7c382b95ae9af 100644 --- a/src/test/ui/issues/issue-17758.stderr +++ b/src/test/ui/issues/issue-17758.stderr @@ -28,7 +28,7 @@ note: ...so that the types are compatible LL | self.foo(); | ^^^ = note: expected `&'a Self` - found `&Self` + found `&'z0 Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20225.stderr b/src/test/ui/issues/issue-20225.stderr index 3bcc50ded8425..351973d444b05 100644 --- a/src/test/ui/issues/issue-20225.stderr +++ b/src/test/ui/issues/issue-20225.stderr @@ -7,7 +7,9 @@ LL | extern "rust-call" fn call(&self, (_,): (T,)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T` | = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))` - found fn pointer `extern "rust-call" fn(&Foo, (T,))` + found fn pointer `extern "rust-call" fn(&'z0 Foo, (T,))` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0053]: method `call_mut` has an incompatible type for trait --> $DIR/issue-20225.rs:11:3 @@ -18,7 +20,9 @@ LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T` | = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))` - found fn pointer `extern "rust-call" fn(&mut Foo, (T,))` + found fn pointer `extern "rust-call" fn(&'z0 mut Foo, (T,))` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0053]: method `call_once` has an incompatible type for trait --> $DIR/issue-20225.rs:18:3 diff --git a/src/test/ui/issues/issue-21332.stderr b/src/test/ui/issues/issue-21332.stderr index ace3e014647c9..cc95b31acb7a7 100644 --- a/src/test/ui/issues/issue-21332.stderr +++ b/src/test/ui/issues/issue-21332.stderr @@ -5,7 +5,7 @@ LL | fn next(&mut self) -> Result { Ok(7) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | = note: expected fn pointer `fn(&mut S) -> std::option::Option` - found fn pointer `fn(&mut S) -> std::result::Result` + found fn pointer `fn(&'z0 mut S) -> std::result::Result` error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr index d07f305954b6e..57d145dcc20a0 100644 --- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -8,7 +8,9 @@ LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32 | = note: expected `fn(&i32, &'a i32) -> &'a i32` - found `fn(&i32, &i32) -> &i32` + found `fn(&'z0 i32, &'z0 i32) -> &'z0 i32` + = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/E0053.stderr b/src/test/ui/mismatched_types/E0053.stderr index fef83e6bbe2b6..4926068e583e7 100644 --- a/src/test/ui/mismatched_types/E0053.stderr +++ b/src/test/ui/mismatched_types/E0053.stderr @@ -20,7 +20,7 @@ LL | fn bar(&mut self) { } | ^^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&Bar)` - found fn pointer `fn(&mut Bar)` + found fn pointer `fn(&'z0 mut Bar)` help: consider change the type to match the mutability in trait | LL | fn bar(&self) { } diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr index b20fddb05acf1..debb371db5104 100644 --- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -20,7 +20,7 @@ LL | fn bar(&mut self, bar: &Bar) { } | ^^^^ types differ in mutability | = note: expected fn pointer `fn(&mut Bar, &mut Bar)` - found fn pointer `fn(&mut Bar, &Bar)` + found fn pointer `fn(&'z0 mut Bar, &'z1 Bar)` help: consider change the type to match the mutability in trait | LL | fn bar(&mut self, bar: &mut Bar) { } diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr index 3317aae83bb08..d029cd23a8b24 100644 --- a/src/test/ui/nll/type-alias-free-regions.stderr +++ b/src/test/ui/nll/type-alias-free-regions.stderr @@ -16,7 +16,7 @@ note: ...so that the expression is assignable | LL | C { f: b } | ^ - = note: expected `std::boxed::Box>` + = note: expected `std::boxed::Box>` found `std::boxed::Box>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6... --> $DIR/type-alias-free-regions.rs:15:6 @@ -49,7 +49,7 @@ note: ...so that the expression is assignable | LL | C { f: Box::new(b.0) } | ^^^ - = note: expected `std::boxed::Box<&isize>` + = note: expected `std::boxed::Box<&'z1 isize>` found `std::boxed::Box<&isize>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6... --> $DIR/type-alias-free-regions.rs:25:6 diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr index 27704b3e0a8c7..074f78027c3b8 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr @@ -5,7 +5,7 @@ LL | want_F(bar); | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S` - found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}` + found fn item `for<'a> fn(&'a S) -> &'z2 S {bar::<'_>}` error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 069b897603cb9..cbe8d01f97729 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -39,7 +39,7 @@ note: ...so that the expression is assignable | LL | Box::new(v) | ^ - = note: expected `&[u8]` + = note: expected `&'z1 [u8]` found `&'a [u8]` note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9... --> $DIR/region-object-lifetime-in-coercion.rs:25:9 diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr index a8a7e97e6acf6..b26891a678980 100644 --- a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr +++ b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr @@ -5,7 +5,7 @@ LL | want_F(bar); | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S` - found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}` + found fn item `for<'a> fn(&'a S) -> &'z2 S {bar::<'_>}` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr index 9e405d83140d8..40e9146d6894a 100644 --- a/src/test/ui/regions/regions-nested-fns.stderr +++ b/src/test/ui/regions/regions-nested-fns.stderr @@ -40,7 +40,7 @@ LL | | return z; LL | | })); | |_____^ = note: expected `&isize` - found `&isize` + found `&'z13 isize` error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/regions-nested-fns.rs:14:27 diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr index 2c4769d8e3751..b489290d9f71d 100644 --- a/src/test/ui/regions/regions-ret-borrowed-1.stderr +++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr @@ -14,7 +14,7 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&isize` + = note: expected `&'z0 isize` found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14... --> $DIR/regions-ret-borrowed-1.rs:9:14 diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr index da560107cea99..6b2a041b95bc3 100644 --- a/src/test/ui/regions/regions-ret-borrowed.stderr +++ b/src/test/ui/regions/regions-ret-borrowed.stderr @@ -14,7 +14,7 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&isize` + = note: expected `&'z0 isize` found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14... --> $DIR/regions-ret-borrowed.rs:12:14 diff --git a/src/test/ui/regions/regions-trait-1.stderr b/src/test/ui/regions/regions-trait-1.stderr index 60ac7c09f0414..6b3c40658a73d 100644 --- a/src/test/ui/regions/regions-trait-1.stderr +++ b/src/test/ui/regions/regions-trait-1.stderr @@ -5,7 +5,7 @@ LL | fn get_ctxt(&self) -> &'a Ctxt { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected fn pointer `fn(&HasCtxt<'a>) -> &Ctxt` - found fn pointer `fn(&HasCtxt<'a>) -> &'a Ctxt` + found fn pointer `fn(&'z0 HasCtxt<'a>) -> &'a Ctxt` note: the lifetime `'a` as defined on the impl at 12:6... --> $DIR/regions-trait-1.rs:12:6 | diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr index 7478b53bd3ccc..271849fdef693 100644 --- a/src/test/ui/regions/regions-trait-object-subtyping.stderr +++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr @@ -42,7 +42,7 @@ note: ...so that the expression is assignable LL | x | ^ = note: expected `&'b mut (dyn Dummy + 'b)` - found `&mut (dyn Dummy + 'b)` + found `&'z1 mut (dyn Dummy + 'b)` error[E0308]: mismatched types --> $DIR/regions-trait-object-subtyping.rs:22:5 diff --git a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr index c14dfa3601a8c..0d19ea1ff2507 100644 --- a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr @@ -54,8 +54,8 @@ LL | Opts::A(ref mut i) | Opts::B(ref i) => {} | | | first introduced with type `&mut isize` here | - = note: expected type `&mut isize` - found type `&isize` + = note: expected type `&'z0 mut isize` + found type `&'z1 isize` = note: in the same arm, a binding must have the same type in all alternatives error: aborting due to 6 previous errors diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index d1960a8aab300..8ea45e4191da7 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -22,8 +22,8 @@ error[E0308]: mismatched types LL | test(&y); | ^^ types differ in mutability | - = note: expected mutable reference `&mut std::string::String` - found reference `&std::string::String` + = note: expected mutable reference `&'z2 mut std::string::String` + found reference `&'z3 std::string::String` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:14:11 diff --git a/src/test/ui/traits/trait-impl-method-mismatch.stderr b/src/test/ui/traits/trait-impl-method-mismatch.stderr index 52e4918624168..517da553dc0ee 100644 --- a/src/test/ui/traits/trait-impl-method-mismatch.stderr +++ b/src/test/ui/traits/trait-impl-method-mismatch.stderr @@ -8,7 +8,7 @@ LL | unsafe fn jumbo(&self, x: &usize) { *self + *x; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn | = note: expected fn pointer `fn(&usize, &usize) -> usize` - found fn pointer `unsafe fn(&usize, &usize)` + found fn pointer `unsafe fn(&'z0 usize, &'z1 usize)` error: aborting due to previous error diff --git a/src/test/ui/type/type-mismatch.stderr b/src/test/ui/type/type-mismatch.stderr index 24c71c63103d3..7beffa0e5e493 100644 --- a/src/test/ui/type/type-mismatch.stderr +++ b/src/test/ui/type/type-mismatch.stderr @@ -211,7 +211,7 @@ LL | want::<&Foo>(f); | expected `&Foo`, found struct `Foo` | help: consider borrowing here: `&f` | - = note: expected reference `&Foo` + = note: expected reference `&'z0 Foo` found struct `Foo` error[E0308]: mismatched types @@ -313,7 +313,7 @@ LL | want::<&Foo>(f); | expected `&Foo`, found struct `Foo` | help: consider borrowing here: `&f` | - = note: expected reference `&Foo` + = note: expected reference `&'z1 Foo` found struct `Foo` error[E0308]: mismatched types diff --git a/src/test/ui/unsafe/unsafe-trait-impl.rs b/src/test/ui/unsafe/unsafe-trait-impl.rs index 03a251be1a914..691c751a080f1 100644 --- a/src/test/ui/unsafe/unsafe-trait-impl.rs +++ b/src/test/ui/unsafe/unsafe-trait-impl.rs @@ -8,7 +8,7 @@ impl Foo for u32 { fn len(&self) -> u32 { *self } //~^ ERROR method `len` has an incompatible type for trait //~| expected fn pointer `unsafe fn(&u32) -> _` - //~| found fn pointer `fn(&u32) -> _` + //~| found fn pointer `fn(&'z0 u32) -> _` } fn main() { } diff --git a/src/test/ui/unsafe/unsafe-trait-impl.stderr b/src/test/ui/unsafe/unsafe-trait-impl.stderr index 1c3d057cbc9ce..f163790eb4511 100644 --- a/src/test/ui/unsafe/unsafe-trait-impl.stderr +++ b/src/test/ui/unsafe/unsafe-trait-impl.stderr @@ -8,7 +8,7 @@ LL | fn len(&self) -> u32 { *self } | ^^^^^^^^^^^^^^^^^^^^ expected unsafe fn, found normal fn | = note: expected fn pointer `unsafe fn(&u32) -> _` - found fn pointer `fn(&u32) -> _` + found fn pointer `fn(&'z0 u32) -> _` error: aborting due to previous error diff --git a/src/test/ui/wrong-mul-method-signature.stderr b/src/test/ui/wrong-mul-method-signature.stderr index 4c367fb9e9caf..cb901cdeedf0c 100644 --- a/src/test/ui/wrong-mul-method-signature.stderr +++ b/src/test/ui/wrong-mul-method-signature.stderr @@ -5,7 +5,7 @@ LL | fn mul(self, s: &f64) -> Vec1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found `&f64` | = note: expected fn pointer `fn(Vec1, f64) -> Vec1` - found fn pointer `fn(Vec1, &f64) -> Vec1` + found fn pointer `fn(Vec1, &'z0 f64) -> Vec1` error[E0053]: method `mul` has an incompatible type for trait --> $DIR/wrong-mul-method-signature.rs:33:5 From eb0f4d51df3be5b149ec032d62e9431ba4faf038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 22 Dec 2019 13:53:01 -0800 Subject: [PATCH 33/44] Tweak output for mismatched impl item Detect type parameter that might require lifetime constraint. Do not name `ReVar`s in expected/found output. Reword text suggesting to check the lifetimes. --- .../infer/error_reporting/mod.rs | 5 +- .../trait_impl_difference.rs | 51 +++++++++++++++---- src/test/ui/coercion/coerce-mut.rs | 4 +- src/test/ui/coercion/coerce-mut.stderr | 4 +- .../reordered-type-param.stderr | 2 +- src/test/ui/hrtb/hrtb-exists-forall-fn.stderr | 2 +- .../impl-generic-mismatch-ab.stderr | 2 +- src/test/ui/impl-trait/trait_type.stderr | 2 +- .../mismatched_trait_impl-2.stderr | 4 +- .../mismatched_trait_impl.nll.stderr | 2 + .../mismatched_trait_impl.stderr | 4 +- src/test/ui/issues/issue-13033.rs | 2 +- src/test/ui/issues/issue-13033.stderr | 2 +- src/test/ui/issues/issue-16683.stderr | 2 +- src/test/ui/issues/issue-17758.stderr | 2 +- src/test/ui/issues/issue-20225.stderr | 4 +- src/test/ui/issues/issue-21332.stderr | 2 +- ...ime-mismatch-between-trait-and-impl.stderr | 4 +- src/test/ui/mismatched_types/E0053.stderr | 2 +- .../trait-impl-fn-incompatibility.stderr | 2 +- .../ui/nll/type-alias-free-regions.stderr | 4 +- ...ons-fn-subtyping-return-static-fail.stderr | 2 +- .../region-object-lifetime-in-coercion.stderr | 2 +- .../regions-fn-subtyping-return-static.stderr | 2 +- src/test/ui/regions/regions-nested-fns.stderr | 2 +- .../ui/regions/regions-ret-borrowed-1.stderr | 2 +- .../ui/regions/regions-ret-borrowed.stderr | 2 +- src/test/ui/regions/regions-trait-1.stderr | 2 +- .../regions-trait-object-subtyping.stderr | 2 +- .../resolve-inconsistent-binding-mode.stderr | 4 +- src/test/ui/span/coerce-suggestions.stderr | 4 +- .../traits/trait-impl-method-mismatch.stderr | 2 +- ...trait-param-without-lifetime-constraint.rs | 20 ++++++++ ...t-param-without-lifetime-constraint.stderr | 18 +++++++ src/test/ui/type/type-mismatch.stderr | 4 +- src/test/ui/unsafe/unsafe-trait-impl.rs | 2 +- src/test/ui/unsafe/unsafe-trait-impl.stderr | 2 +- src/test/ui/wrong-mul-method-signature.stderr | 2 +- 38 files changed, 126 insertions(+), 56 deletions(-) create mode 100644 src/test/ui/traits/trait-param-without-lifetime-constraint.rs create mode 100644 src/test/ui/traits/trait-param-without-lifetime-constraint.stderr diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 66e7c87f2c351..ae9019828170f 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -993,10 +993,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { s: &mut DiagnosticStyledString, ) { let mut r = region.to_string(); - if let ty::RegionKind::ReVar(var) = region { - // Show these named, not as `'_` or elide them in "expected/found" notes. - r = format!("'z{} ", var.index()); - } else if r == "'_" { + if r == "'_" { r.clear(); } else { r.push(' '); diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 2e54a4e28e98c..5aa55d253aa1e 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -1,5 +1,6 @@ //! Error Reporting for `impl` items that do not match the obligations from their `trait`. +use crate::hir; use crate::hir::def_id::DefId; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; @@ -40,7 +41,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { var_origin.span(), sub_expected_found.expected, sub_expected_found.found, - self.tcx().def_span(*trait_item_def_id), + *trait_item_def_id, ); return Some(ErrorReported); } @@ -51,23 +52,56 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { None } - fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, impl_sp: Span) { + fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id: DefId) { + let tcx = self.tcx(); + let trait_sp = self.tcx().def_span(trait_def_id); let mut err = self .tcx() .sess .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); err.span_label(sp, &format!("found {:?}", found)); - err.span_label(impl_sp, &format!("expected {:?}", expected)); + err.span_label(trait_sp, &format!("expected {:?}", expected)); + let trait_fn_sig = tcx.fn_sig(trait_def_id); + + struct AssocTypeFinder(FxHashSet); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for AssocTypeFinder { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + debug!("assoc type finder ty {:?} {:?}", ty, ty.kind); + match ty.kind { + ty::Param(param) => { + self.0.insert(param); + } + _ => {} + } + ty.super_visit_with(self) + } + } + let mut visitor = AssocTypeFinder(FxHashSet::default()); + trait_fn_sig.output().visit_with(&mut visitor); + + if let Some(id) = tcx.hir().as_local_hir_id(trait_def_id) { + let parent_id = tcx.hir().get_parent_item(id); + let trait_item = tcx.hir().expect_item(parent_id); + if let hir::ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { + for param_ty in visitor.0 { + if let Some(generic) = generics.get_named(param_ty.name) { + err.span_label(generic.span, &format!( + "in order for `impl` items to be able to implement the method, this \ + type parameter might need a lifetime restriction like `{}: 'a`", + param_ty.name, + )); + } + } + } + } struct EarlyBoundRegionHighlighter(FxHashSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for EarlyBoundRegionHighlighter { fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - debug!("LateBoundRegionNameCollector visit_region {:?}", r); match *r { ty::ReFree(free) => { self.0.insert(free.scope); } - ty::ReEarlyBound(bound) => { self.0.insert(bound.def_id); } @@ -94,12 +128,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if note { err.note( - "the lifetime requirements from the `trait` could not be fulfilled by the \ - `impl`", + "the lifetime requirements from the `trait` could not be fulfilled by the `impl`", ); err.help( - "consider adding a named lifetime to the `trait` that constrains the item's \ - `self` argument, its inputs and its output with it", + "verify the lifetime relationships in the `trait` and `impl` between the \ + `self` argument, the other inputs and its output", ); } err.emit(); diff --git a/src/test/ui/coercion/coerce-mut.rs b/src/test/ui/coercion/coerce-mut.rs index 3ccfe1cede7ac..43f0b55856d3c 100644 --- a/src/test/ui/coercion/coerce-mut.rs +++ b/src/test/ui/coercion/coerce-mut.rs @@ -4,7 +4,7 @@ fn main() { let x = 0; f(&x); //~^ ERROR mismatched types - //~| expected mutable reference `&'z1 mut i32` - //~| found reference `&'z2 {integer}` + //~| expected mutable reference `&mut i32` + //~| found reference `&{integer}` //~| types differ in mutability } diff --git a/src/test/ui/coercion/coerce-mut.stderr b/src/test/ui/coercion/coerce-mut.stderr index f5b13f6c59099..2601ca5e91e5b 100644 --- a/src/test/ui/coercion/coerce-mut.stderr +++ b/src/test/ui/coercion/coerce-mut.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | f(&x); | ^^ types differ in mutability | - = note: expected mutable reference `&'z1 mut i32` - found reference `&'z2 {integer}` + = note: expected mutable reference `&mut i32` + found reference `&{integer}` error: aborting due to previous error diff --git a/src/test/ui/compare-method/reordered-type-param.stderr b/src/test/ui/compare-method/reordered-type-param.stderr index 9eed16fa994e3..f1f8a663f2120 100644 --- a/src/test/ui/compare-method/reordered-type-param.stderr +++ b/src/test/ui/compare-method/reordered-type-param.stderr @@ -11,7 +11,7 @@ LL | fn b(&self, _x: G) -> G { panic!() } | expected type parameter | = note: expected fn pointer `fn(&E, F) -> F` - found fn pointer `fn(&'z0 E, G) -> G` + found fn pointer `fn(&E, G) -> G` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr index 4d09fe74e16fc..328e98657effb 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -7,7 +7,7 @@ LL | let _: for<'b> fn(&'b u32) = foo(); | expected due to this | = note: expected fn pointer `for<'b> fn(&'b u32)` - found fn pointer `fn(&'z0 u32)` + found fn pointer `fn(&u32)` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr index d5725efbac3c6..638a0093fb21d 100644 --- a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr +++ b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr @@ -10,7 +10,7 @@ LL | fn foo(&self, a: &impl Debug, b: &B) { } | expected type parameter | = note: expected fn pointer `fn(&(), &B, &impl Debug)` - found fn pointer `fn(&'z0 (), &impl Debug, &B)` + found fn pointer `fn(&(), &impl Debug, &B)` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr index 3cc9c1a7fb054..748bc639a03c2 100644 --- a/src/test/ui/impl-trait/trait_type.stderr +++ b/src/test/ui/impl-trait/trait_type.stderr @@ -5,7 +5,7 @@ LL | fn fmt(&self, x: &str) -> () { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` - found fn pointer `fn(&'z0 MyType, &str)` + found fn pointer `fn(&MyType, &str)` error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2 --> $DIR/trait_type.rs:12:11 diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index 349f813b20d50..d8a2fa14333ea 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -10,9 +10,9 @@ LL | fn deref(&self) -> &Self::Target; | --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static) | = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` - found `fn(&'z0 Struct) -> &dyn Trait` + found `fn(&Struct) -> &dyn Trait` = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` - = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr index c245d78ae828f..88edf10a66f0c 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr @@ -9,6 +9,8 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` + = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index 72960a41f93df..dcdc6d330c0e7 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -8,9 +8,9 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32 | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` - found `fn(&'z0 i32, &'z1 u32, &'z2 u32) -> &'z2 u32` + found `fn(&i32, &u32, &u32) -> &u32` = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` - = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error[E0623]: lifetime mismatch --> $DIR/mismatched_trait_impl.rs:10:9 diff --git a/src/test/ui/issues/issue-13033.rs b/src/test/ui/issues/issue-13033.rs index 3fa94fac23759..7631831a81a5b 100644 --- a/src/test/ui/issues/issue-13033.rs +++ b/src/test/ui/issues/issue-13033.rs @@ -8,7 +8,7 @@ impl Foo for Baz { fn bar(&mut self, other: &dyn Foo) {} //~^ ERROR method `bar` has an incompatible type for trait //~| expected fn pointer `fn(&mut Baz, &mut dyn Foo)` - //~| found fn pointer `fn(&'z0 mut Baz, &dyn Foo)` + //~| found fn pointer `fn(&mut Baz, &dyn Foo)` } fn main() {} diff --git a/src/test/ui/issues/issue-13033.stderr b/src/test/ui/issues/issue-13033.stderr index 238f41782ba5a..a8473c8a52413 100644 --- a/src/test/ui/issues/issue-13033.stderr +++ b/src/test/ui/issues/issue-13033.stderr @@ -8,7 +8,7 @@ LL | fn bar(&mut self, other: &dyn Foo) {} | ^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)` - found fn pointer `fn(&'z0 mut Baz, &dyn Foo)` + found fn pointer `fn(&mut Baz, &dyn Foo)` help: consider change the type to match the mutability in trait | LL | fn bar(&mut self, other: &mut dyn Foo) {} diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr index fa782d043312d..4f65833075814 100644 --- a/src/test/ui/issues/issue-16683.stderr +++ b/src/test/ui/issues/issue-16683.stderr @@ -27,7 +27,7 @@ note: ...so that the types are compatible LL | self.a(); | ^ = note: expected `&'a Self` - found `&'z0 Self` + found `&Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr index 7c382b95ae9af..31788cfa61c4c 100644 --- a/src/test/ui/issues/issue-17758.stderr +++ b/src/test/ui/issues/issue-17758.stderr @@ -28,7 +28,7 @@ note: ...so that the types are compatible LL | self.foo(); | ^^^ = note: expected `&'a Self` - found `&'z0 Self` + found `&Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20225.stderr b/src/test/ui/issues/issue-20225.stderr index 351973d444b05..133dbc554c089 100644 --- a/src/test/ui/issues/issue-20225.stderr +++ b/src/test/ui/issues/issue-20225.stderr @@ -7,7 +7,7 @@ LL | extern "rust-call" fn call(&self, (_,): (T,)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T` | = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))` - found fn pointer `extern "rust-call" fn(&'z0 Foo, (T,))` + found fn pointer `extern "rust-call" fn(&Foo, (T,))` = help: type parameters must be constrained to match other types = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters @@ -20,7 +20,7 @@ LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T` | = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))` - found fn pointer `extern "rust-call" fn(&'z0 mut Foo, (T,))` + found fn pointer `extern "rust-call" fn(&mut Foo, (T,))` = help: type parameters must be constrained to match other types = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/src/test/ui/issues/issue-21332.stderr b/src/test/ui/issues/issue-21332.stderr index cc95b31acb7a7..ace3e014647c9 100644 --- a/src/test/ui/issues/issue-21332.stderr +++ b/src/test/ui/issues/issue-21332.stderr @@ -5,7 +5,7 @@ LL | fn next(&mut self) -> Result { Ok(7) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | = note: expected fn pointer `fn(&mut S) -> std::option::Option` - found fn pointer `fn(&'z0 mut S) -> std::result::Result` + found fn pointer `fn(&mut S) -> std::result::Result` error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr index 57d145dcc20a0..fa2ea83deefb7 100644 --- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -8,9 +8,9 @@ LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32 | = note: expected `fn(&i32, &'a i32) -> &'a i32` - found `fn(&'z0 i32, &'z0 i32) -> &'z0 i32` + found `fn(&i32, &i32) -> &i32` = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` - = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/E0053.stderr b/src/test/ui/mismatched_types/E0053.stderr index 4926068e583e7..fef83e6bbe2b6 100644 --- a/src/test/ui/mismatched_types/E0053.stderr +++ b/src/test/ui/mismatched_types/E0053.stderr @@ -20,7 +20,7 @@ LL | fn bar(&mut self) { } | ^^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&Bar)` - found fn pointer `fn(&'z0 mut Bar)` + found fn pointer `fn(&mut Bar)` help: consider change the type to match the mutability in trait | LL | fn bar(&self) { } diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr index debb371db5104..b20fddb05acf1 100644 --- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -20,7 +20,7 @@ LL | fn bar(&mut self, bar: &Bar) { } | ^^^^ types differ in mutability | = note: expected fn pointer `fn(&mut Bar, &mut Bar)` - found fn pointer `fn(&'z0 mut Bar, &'z1 Bar)` + found fn pointer `fn(&mut Bar, &Bar)` help: consider change the type to match the mutability in trait | LL | fn bar(&mut self, bar: &mut Bar) { } diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr index d029cd23a8b24..3317aae83bb08 100644 --- a/src/test/ui/nll/type-alias-free-regions.stderr +++ b/src/test/ui/nll/type-alias-free-regions.stderr @@ -16,7 +16,7 @@ note: ...so that the expression is assignable | LL | C { f: b } | ^ - = note: expected `std::boxed::Box>` + = note: expected `std::boxed::Box>` found `std::boxed::Box>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6... --> $DIR/type-alias-free-regions.rs:15:6 @@ -49,7 +49,7 @@ note: ...so that the expression is assignable | LL | C { f: Box::new(b.0) } | ^^^ - = note: expected `std::boxed::Box<&'z1 isize>` + = note: expected `std::boxed::Box<&isize>` found `std::boxed::Box<&isize>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6... --> $DIR/type-alias-free-regions.rs:25:6 diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr index 074f78027c3b8..27704b3e0a8c7 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr @@ -5,7 +5,7 @@ LL | want_F(bar); | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S` - found fn item `for<'a> fn(&'a S) -> &'z2 S {bar::<'_>}` + found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}` error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index cbe8d01f97729..069b897603cb9 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -39,7 +39,7 @@ note: ...so that the expression is assignable | LL | Box::new(v) | ^ - = note: expected `&'z1 [u8]` + = note: expected `&[u8]` found `&'a [u8]` note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9... --> $DIR/region-object-lifetime-in-coercion.rs:25:9 diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr index b26891a678980..a8a7e97e6acf6 100644 --- a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr +++ b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr @@ -5,7 +5,7 @@ LL | want_F(bar); | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S` - found fn item `for<'a> fn(&'a S) -> &'z2 S {bar::<'_>}` + found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr index 40e9146d6894a..9e405d83140d8 100644 --- a/src/test/ui/regions/regions-nested-fns.stderr +++ b/src/test/ui/regions/regions-nested-fns.stderr @@ -40,7 +40,7 @@ LL | | return z; LL | | })); | |_____^ = note: expected `&isize` - found `&'z13 isize` + found `&isize` error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/regions-nested-fns.rs:14:27 diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr index b489290d9f71d..2c4769d8e3751 100644 --- a/src/test/ui/regions/regions-ret-borrowed-1.stderr +++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr @@ -14,7 +14,7 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&'z0 isize` + = note: expected `&isize` found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14... --> $DIR/regions-ret-borrowed-1.rs:9:14 diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr index 6b2a041b95bc3..da560107cea99 100644 --- a/src/test/ui/regions/regions-ret-borrowed.stderr +++ b/src/test/ui/regions/regions-ret-borrowed.stderr @@ -14,7 +14,7 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&'z0 isize` + = note: expected `&isize` found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14... --> $DIR/regions-ret-borrowed.rs:12:14 diff --git a/src/test/ui/regions/regions-trait-1.stderr b/src/test/ui/regions/regions-trait-1.stderr index 6b3c40658a73d..60ac7c09f0414 100644 --- a/src/test/ui/regions/regions-trait-1.stderr +++ b/src/test/ui/regions/regions-trait-1.stderr @@ -5,7 +5,7 @@ LL | fn get_ctxt(&self) -> &'a Ctxt { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected fn pointer `fn(&HasCtxt<'a>) -> &Ctxt` - found fn pointer `fn(&'z0 HasCtxt<'a>) -> &'a Ctxt` + found fn pointer `fn(&HasCtxt<'a>) -> &'a Ctxt` note: the lifetime `'a` as defined on the impl at 12:6... --> $DIR/regions-trait-1.rs:12:6 | diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr index 271849fdef693..7478b53bd3ccc 100644 --- a/src/test/ui/regions/regions-trait-object-subtyping.stderr +++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr @@ -42,7 +42,7 @@ note: ...so that the expression is assignable LL | x | ^ = note: expected `&'b mut (dyn Dummy + 'b)` - found `&'z1 mut (dyn Dummy + 'b)` + found `&mut (dyn Dummy + 'b)` error[E0308]: mismatched types --> $DIR/regions-trait-object-subtyping.rs:22:5 diff --git a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr index 0d19ea1ff2507..c14dfa3601a8c 100644 --- a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr @@ -54,8 +54,8 @@ LL | Opts::A(ref mut i) | Opts::B(ref i) => {} | | | first introduced with type `&mut isize` here | - = note: expected type `&'z0 mut isize` - found type `&'z1 isize` + = note: expected type `&mut isize` + found type `&isize` = note: in the same arm, a binding must have the same type in all alternatives error: aborting due to 6 previous errors diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index 8ea45e4191da7..d1960a8aab300 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -22,8 +22,8 @@ error[E0308]: mismatched types LL | test(&y); | ^^ types differ in mutability | - = note: expected mutable reference `&'z2 mut std::string::String` - found reference `&'z3 std::string::String` + = note: expected mutable reference `&mut std::string::String` + found reference `&std::string::String` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:14:11 diff --git a/src/test/ui/traits/trait-impl-method-mismatch.stderr b/src/test/ui/traits/trait-impl-method-mismatch.stderr index 517da553dc0ee..52e4918624168 100644 --- a/src/test/ui/traits/trait-impl-method-mismatch.stderr +++ b/src/test/ui/traits/trait-impl-method-mismatch.stderr @@ -8,7 +8,7 @@ LL | unsafe fn jumbo(&self, x: &usize) { *self + *x; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn | = note: expected fn pointer `fn(&usize, &usize) -> usize` - found fn pointer `unsafe fn(&'z0 usize, &'z1 usize)` + found fn pointer `unsafe fn(&usize, &usize)` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.rs b/src/test/ui/traits/trait-param-without-lifetime-constraint.rs new file mode 100644 index 0000000000000..a79b74dcddead --- /dev/null +++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.rs @@ -0,0 +1,20 @@ +struct Article { + proof_reader: ProofReader, +} + +struct ProofReader { + name: String, +} + +pub trait HaveRelationship { + fn get_relation(&self) -> To; +} + +impl HaveRelationship<&ProofReader> for Article { + fn get_relation(&self) -> &ProofReader { + //~^ ERROR `impl` item signature doesn't match `trait` item signature + &self.proof_reader + } +} + +fn main() {} diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr new file mode 100644 index 0000000000000..912d3a8d28de1 --- /dev/null +++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr @@ -0,0 +1,18 @@ +error: `impl` item signature doesn't match `trait` item signature + --> $DIR/trait-param-without-lifetime-constraint.rs:14:5 + | +LL | pub trait HaveRelationship { + | -- in order for `impl` items to be able to implement the method, this type parameter might need a lifetime restriction like `To: 'a` +LL | fn get_relation(&self) -> To; + | ----------------------------- expected fn(&Article) -> &ProofReader +... +LL | fn get_relation(&self) -> &ProofReader { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Article) -> &ProofReader + | + = note: expected `fn(&Article) -> &ProofReader` + found `fn(&Article) -> &ProofReader` + = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output + +error: aborting due to previous error + diff --git a/src/test/ui/type/type-mismatch.stderr b/src/test/ui/type/type-mismatch.stderr index 7beffa0e5e493..24c71c63103d3 100644 --- a/src/test/ui/type/type-mismatch.stderr +++ b/src/test/ui/type/type-mismatch.stderr @@ -211,7 +211,7 @@ LL | want::<&Foo>(f); | expected `&Foo`, found struct `Foo` | help: consider borrowing here: `&f` | - = note: expected reference `&'z0 Foo` + = note: expected reference `&Foo` found struct `Foo` error[E0308]: mismatched types @@ -313,7 +313,7 @@ LL | want::<&Foo>(f); | expected `&Foo`, found struct `Foo` | help: consider borrowing here: `&f` | - = note: expected reference `&'z1 Foo` + = note: expected reference `&Foo` found struct `Foo` error[E0308]: mismatched types diff --git a/src/test/ui/unsafe/unsafe-trait-impl.rs b/src/test/ui/unsafe/unsafe-trait-impl.rs index 691c751a080f1..03a251be1a914 100644 --- a/src/test/ui/unsafe/unsafe-trait-impl.rs +++ b/src/test/ui/unsafe/unsafe-trait-impl.rs @@ -8,7 +8,7 @@ impl Foo for u32 { fn len(&self) -> u32 { *self } //~^ ERROR method `len` has an incompatible type for trait //~| expected fn pointer `unsafe fn(&u32) -> _` - //~| found fn pointer `fn(&'z0 u32) -> _` + //~| found fn pointer `fn(&u32) -> _` } fn main() { } diff --git a/src/test/ui/unsafe/unsafe-trait-impl.stderr b/src/test/ui/unsafe/unsafe-trait-impl.stderr index f163790eb4511..1c3d057cbc9ce 100644 --- a/src/test/ui/unsafe/unsafe-trait-impl.stderr +++ b/src/test/ui/unsafe/unsafe-trait-impl.stderr @@ -8,7 +8,7 @@ LL | fn len(&self) -> u32 { *self } | ^^^^^^^^^^^^^^^^^^^^ expected unsafe fn, found normal fn | = note: expected fn pointer `unsafe fn(&u32) -> _` - found fn pointer `fn(&'z0 u32) -> _` + found fn pointer `fn(&u32) -> _` error: aborting due to previous error diff --git a/src/test/ui/wrong-mul-method-signature.stderr b/src/test/ui/wrong-mul-method-signature.stderr index cb901cdeedf0c..4c367fb9e9caf 100644 --- a/src/test/ui/wrong-mul-method-signature.stderr +++ b/src/test/ui/wrong-mul-method-signature.stderr @@ -5,7 +5,7 @@ LL | fn mul(self, s: &f64) -> Vec1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found `&f64` | = note: expected fn pointer `fn(Vec1, f64) -> Vec1` - found fn pointer `fn(Vec1, &'z0 f64) -> Vec1` + found fn pointer `fn(Vec1, &f64) -> Vec1` error[E0053]: method `mul` has an incompatible type for trait --> $DIR/wrong-mul-method-signature.rs:33:5 From 38112321908e824a56943f8e2a461510206e2409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 22 Dec 2019 17:53:50 -0800 Subject: [PATCH 34/44] review comments --- .../trait_impl_difference.rs | 58 ++++++------------- .../mismatched_trait_impl-2.stderr | 2 +- .../mismatched_trait_impl.nll.stderr | 2 +- .../mismatched_trait_impl.stderr | 2 +- ...ime-mismatch-between-trait-and-impl.stderr | 2 +- ...t-param-without-lifetime-constraint.stderr | 4 +- 6 files changed, 24 insertions(+), 46 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 5aa55d253aa1e..7ad7e8897df38 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -63,22 +63,25 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.span_label(trait_sp, &format!("expected {:?}", expected)); let trait_fn_sig = tcx.fn_sig(trait_def_id); + // Check the `trait`'s method's output to look for type parameters that might have + // unconstrained lifetimes. If the method returns a type parameter and the `impl` has a + // borrow as the type parameter being implemented, the lifetimes will not match because + // a new lifetime is being introduced in the `impl` that is not present in the `trait`. + // Because this is confusing as hell the first time you see it, we give a short message + // explaining the situation and proposing constraining the type param with a named lifetime + // so that the `impl` will have one to tie them together. struct AssocTypeFinder(FxHashSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for AssocTypeFinder { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { debug!("assoc type finder ty {:?} {:?}", ty, ty.kind); - match ty.kind { - ty::Param(param) => { - self.0.insert(param); - } - _ => {} + if let ty::Param(param) = ty.kind { + self.0.insert(param); } ty.super_visit_with(self) } } let mut visitor = AssocTypeFinder(FxHashSet::default()); trait_fn_sig.output().visit_with(&mut visitor); - if let Some(id) = tcx.hir().as_local_hir_id(trait_def_id) { let parent_id = tcx.hir().get_parent_item(id); let trait_item = tcx.hir().expect_item(parent_id); @@ -86,8 +89,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { for param_ty in visitor.0 { if let Some(generic) = generics.get_named(param_ty.name) { err.span_label(generic.span, &format!( - "in order for `impl` items to be able to implement the method, this \ - type parameter might need a lifetime restriction like `{}: 'a`", + "for `impl` items to implement the method, this type parameter might \ + need a lifetime restriction like `{}: 'a`", param_ty.name, )); } @@ -95,46 +98,21 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } - struct EarlyBoundRegionHighlighter(FxHashSet); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for EarlyBoundRegionHighlighter { - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - match *r { - ty::ReFree(free) => { - self.0.insert(free.scope); - } - ty::ReEarlyBound(bound) => { - self.0.insert(bound.def_id); - } - _ => {} - } - r.super_visit_with(self) - } - } - - let mut visitor = EarlyBoundRegionHighlighter(FxHashSet::default()); - expected.visit_with(&mut visitor); - - let note = !visitor.0.is_empty(); - - if let Some((expected, found)) = self - .tcx() + if let Some((expected, found)) = tcx .infer_ctxt() .enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found })) { + // Highlighted the differences when showing the "expected/found" note. err.note_expected_found(&"", expected, &"", found); } else { // This fallback shouldn't be necessary, but let's keep it in just in case. err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); } - if note { - err.note( - "the lifetime requirements from the `trait` could not be fulfilled by the `impl`", - ); - err.help( - "verify the lifetime relationships in the `trait` and `impl` between the \ - `self` argument, the other inputs and its output", - ); - } + err.note("the lifetime requirements from the `trait` could not be satisfied by the `impl`"); + err.help( + "verify the lifetime relationships in the `trait` and `impl` between the `self` \ + argument, the other inputs and its output", + ); err.emit(); } } diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index d8a2fa14333ea..05413c3a2923a 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -11,7 +11,7 @@ LL | fn deref(&self) -> &Self::Target; | = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` found `fn(&Struct) -> &dyn Trait` - = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr index 88edf10a66f0c..c58f78b6719a1 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr @@ -9,7 +9,7 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` - = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index dcdc6d330c0e7..4dbd4ac6a852b 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -9,7 +9,7 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` - = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error[E0623]: lifetime mismatch diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr index fa2ea83deefb7..0e56473c5b6ac 100644 --- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -9,7 +9,7 @@ LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { | = note: expected `fn(&i32, &'a i32) -> &'a i32` found `fn(&i32, &i32) -> &i32` - = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr index 912d3a8d28de1..724062b1a589f 100644 --- a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr +++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr @@ -2,7 +2,7 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/trait-param-without-lifetime-constraint.rs:14:5 | LL | pub trait HaveRelationship { - | -- in order for `impl` items to be able to implement the method, this type parameter might need a lifetime restriction like `To: 'a` + | -- for `impl` items to implement the method, this type parameter might need a lifetime restriction like `To: 'a` LL | fn get_relation(&self) -> To; | ----------------------------- expected fn(&Article) -> &ProofReader ... @@ -11,7 +11,7 @@ LL | fn get_relation(&self) -> &ProofReader { | = note: expected `fn(&Article) -> &ProofReader` found `fn(&Article) -> &ProofReader` - = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error From 2e2f82053ffbf23997b736cde720ca4db4207504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 27 Dec 2019 13:52:20 -0800 Subject: [PATCH 35/44] review comment: use FxIndexSet --- .../nice_region_error/trait_impl_difference.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 7ad7e8897df38..039671b982849 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -6,7 +6,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{Subtype, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorReported; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFoldable; @@ -70,7 +70,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Because this is confusing as hell the first time you see it, we give a short message // explaining the situation and proposing constraining the type param with a named lifetime // so that the `impl` will have one to tie them together. - struct AssocTypeFinder(FxHashSet); + struct AssocTypeFinder(FxIndexSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for AssocTypeFinder { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { debug!("assoc type finder ty {:?} {:?}", ty, ty.kind); @@ -80,7 +80,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ty.super_visit_with(self) } } - let mut visitor = AssocTypeFinder(FxHashSet::default()); + let mut visitor = AssocTypeFinder(FxIndexSet::default()); trait_fn_sig.output().visit_with(&mut visitor); if let Some(id) = tcx.hir().as_local_hir_id(trait_def_id) { let parent_id = tcx.hir().get_parent_item(id); From d0d30b0a3ea6b715e275aa17ced2f7bc8d5207d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 7 Jan 2020 12:05:34 -0800 Subject: [PATCH 36/44] fix rebase --- .../nice_region_error/trait_impl_difference.rs | 6 +++--- src/test/ui/issues/issue-20831-debruijn.stderr | 4 ++-- .../regions/regions-normalize-in-where-clause-list.stderr | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 039671b982849..4019708df9828 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -1,13 +1,13 @@ //! Error Reporting for `impl` items that do not match the obligations from their `trait`. -use crate::hir; -use crate::hir::def_id::DefId; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{Subtype, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorReported; +use rustc_hir::def_id::DefId; +use rustc_hir::ItemKind; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty}; @@ -85,7 +85,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if let Some(id) = tcx.hir().as_local_hir_id(trait_def_id) { let parent_id = tcx.hir().get_parent_item(id); let trait_item = tcx.hir().expect_item(parent_id); - if let hir::ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { + if let ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { for param_ty in visitor.0 { if let Some(generic) = generics.get_named(param_ty.name) { err.span_label(generic.span, &format!( diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr index 160a4213a4043..e7c1dcc5d698c 100644 --- a/src/test/ui/issues/issue-20831-debruijn.stderr +++ b/src/test/ui/issues/issue-20831-debruijn.stderr @@ -87,8 +87,8 @@ note: ...so that the types are compatible | LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `Publisher<'_>` - found `Publisher<'_>` + = note: expected `Publisher<'_>` + found `Publisher<'_>` error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/issue-20831-debruijn.rs:28:33 diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr index a274fd9d658a9..dc93d620ca637 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -63,8 +63,8 @@ LL | | where <() as Project<'a, 'b>>::Item : Eq LL | | { LL | | } | |_^ - = note: expected `Project<'a, 'b>` - found `Project<'_, '_>` + = note: expected `Project<'a, 'b>` + found `Project<'_, '_>` error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/regions-normalize-in-where-clause-list.rs:22:4 @@ -87,8 +87,8 @@ note: ...so that the types are compatible | LL | fn bar<'a, 'b>() | ^^^ - = note: expected `Project<'a, 'b>` - found `Project<'_, '_>` + = note: expected `Project<'a, 'b>` + found `Project<'_, '_>` error: aborting due to 3 previous errors From 2b35247d7a80e689dee6363730807687fdf42b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 16 Feb 2020 17:59:29 -0800 Subject: [PATCH 37/44] Modify wording --- .../trait_impl_difference.rs | 83 ++++++++++++++++--- .../mismatched_trait_impl-2.stderr | 4 +- .../mismatched_trait_impl.stderr | 4 +- ...ime-mismatch-between-trait-and-impl.stderr | 4 +- ...t-param-without-lifetime-constraint.stderr | 9 +- 5 files changed, 84 insertions(+), 20 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 4019708df9828..ca925233333c1 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -2,15 +2,17 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::{Subtype, ValuePairs}; +use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorReported; +use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor; use rustc_hir::ItemKind; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -59,8 +61,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .tcx() .sess .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); - err.span_label(sp, &format!("found {:?}", found)); - err.span_label(trait_sp, &format!("expected {:?}", expected)); + err.span_label(sp, &format!("found `{:?}`", found)); + err.span_label(trait_sp, &format!("expected `{:?}`", expected)); let trait_fn_sig = tcx.fn_sig(trait_def_id); // Check the `trait`'s method's output to look for type parameters that might have @@ -73,7 +75,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { struct AssocTypeFinder(FxIndexSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for AssocTypeFinder { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - debug!("assoc type finder ty {:?} {:?}", ty, ty.kind); if let ty::Param(param) = ty.kind { self.0.insert(param); } @@ -86,18 +87,40 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let parent_id = tcx.hir().get_parent_item(id); let trait_item = tcx.hir().expect_item(parent_id); if let ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { - for param_ty in visitor.0 { + for param_ty in &visitor.0 { if let Some(generic) = generics.get_named(param_ty.name) { - err.span_label(generic.span, &format!( - "for `impl` items to implement the method, this type parameter might \ - need a lifetime restriction like `{}: 'a`", - param_ty.name, - )); + err.span_label( + generic.span, + "this type parameter might not have a lifetime compatible with the \ + `impl`", + ); } } } } + // Get the span of all the used type parameters in the method. + let assoc_item = self.tcx().associated_item(trait_def_id); + let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; + match assoc_item.kind { + ty::AssocKind::Method => { + let hir = self.tcx().hir(); + if let Some(hir_id) = hir.as_local_hir_id(assoc_item.def_id) { + if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) { + visitor.visit_fn_decl(decl); + } + } + } + _ => {} + } + for span in visitor.types { + err.span_label( + span, + "you might want to borrow this type parameter in the trait to make it match the \ + `impl`", + ); + } + if let Some((expected, found)) = tcx .infer_ctxt() .enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found })) @@ -116,3 +139,41 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.emit(); } } + +struct TypeParamSpanVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + types: Vec, +} + +impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { + type Map = hir::intravisit::Map<'tcx>; + + fn nested_visit_map<'this>( + &'this mut self, + ) -> hir::intravisit::NestedVisitorMap<'this, Self::Map> { + hir::intravisit::NestedVisitorMap::OnlyBodies(&self.tcx.hir()) + } + + fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { + match arg.kind { + hir::TyKind::Slice(_) | hir::TyKind::Tup(_) | hir::TyKind::Array(..) => { + hir::intravisit::walk_ty(self, arg); + } + hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { + [segment] + if segment + .res + .map(|res| match res { + hir::def::Res::Def(hir::def::DefKind::TyParam, _) => true, + _ => false, + }) + .unwrap_or(false) => + { + self.types.push(path.span); + } + _ => {} + }, + _ => {} + } + } +} diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index 05413c3a2923a..61a8674a2310e 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -2,12 +2,12 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/mismatched_trait_impl-2.rs:8:5 | LL | fn deref(&self) -> &dyn Trait { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Struct) -> &dyn Trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait` | ::: $SRC_DIR/libcore/ops/deref.rs:LL:COL | LL | fn deref(&self) -> &Self::Target; - | --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static) + | --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)` | = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` found `fn(&Struct) -> &dyn Trait` diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index 4dbd4ac6a852b..ca61029145530 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -2,10 +2,10 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/mismatched_trait_impl.rs:9:5 | LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32; - | ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32 + | ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32` ... LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32` | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr index 0e56473c5b6ac..53f6aae5ff6e0 100644 --- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -2,10 +2,10 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5 | LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32; - | ------------------------------------------- expected fn(&i32, &'a i32) -> &'a i32 + | ------------------------------------------- expected `fn(&i32, &'a i32) -> &'a i32` ... LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32` | = note: expected `fn(&i32, &'a i32) -> &'a i32` found `fn(&i32, &i32) -> &i32` diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr index 724062b1a589f..a7be2d3365c1a 100644 --- a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr +++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr @@ -2,12 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/trait-param-without-lifetime-constraint.rs:14:5 | LL | pub trait HaveRelationship { - | -- for `impl` items to implement the method, this type parameter might need a lifetime restriction like `To: 'a` + | -- this type parameter might not have a lifetime compatible with the `impl` LL | fn get_relation(&self) -> To; - | ----------------------------- expected fn(&Article) -> &ProofReader + | ----------------------------- + | | | + | | you might want to borrow this type parameter in the trait to make it match the `impl` + | expected `fn(&Article) -> &ProofReader` ... LL | fn get_relation(&self) -> &ProofReader { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Article) -> &ProofReader + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader` | = note: expected `fn(&Article) -> &ProofReader` found `fn(&Article) -> &ProofReader` From 500504c0bd79996784496d4ffa7a153ed5d10dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 29 Mar 2020 19:53:58 -0700 Subject: [PATCH 38/44] fix rebase --- .../nice_region_error/trait_impl_difference.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index ca925233333c1..c0046758b07f7 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -148,10 +148,8 @@ struct TypeParamSpanVisitor<'tcx> { impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { type Map = hir::intravisit::Map<'tcx>; - fn nested_visit_map<'this>( - &'this mut self, - ) -> hir::intravisit::NestedVisitorMap<'this, Self::Map> { - hir::intravisit::NestedVisitorMap::OnlyBodies(&self.tcx.hir()) + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { + hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir()) } fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { From c52dbbc64354942c244c9f497e73d2e0814deaf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 13 Apr 2020 21:31:21 -0700 Subject: [PATCH 39/44] fix rebase --- .../error_reporting/nice_region_error/trait_impl_difference.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index c0046758b07f7..120594df6719b 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -146,7 +146,7 @@ struct TypeParamSpanVisitor<'tcx> { } impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { - type Map = hir::intravisit::Map<'tcx>; + type Map = rustc_middle::hir::map::Map<'tcx>; fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir()) From 7d5415b5a2faf5b8f76156eedfd66f94b91660a0 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 26 May 2020 23:14:55 -0700 Subject: [PATCH 40/44] Add additional checks for isize overflow We now perform the correct checks even if the pointer size differs between the host and target. Signed-off-by: Joe Richey --- src/librustc_middle/mir/interpret/pointer.rs | 15 +++++++++++++-- src/librustc_mir/interpret/intrinsics.rs | 5 ++--- src/test/ui/consts/offset_ub.stderr | 4 ++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/librustc_middle/mir/interpret/pointer.rs b/src/librustc_middle/mir/interpret/pointer.rs index 019c96bc511eb..ccad4f0a135a1 100644 --- a/src/librustc_middle/mir/interpret/pointer.rs +++ b/src/librustc_middle/mir/interpret/pointer.rs @@ -24,6 +24,12 @@ pub trait PointerArithmetic: HasDataLayout { u64::try_from(max_usize_plus_1 - 1).unwrap() } + #[inline] + fn machine_isize_min(&self) -> i64 { + let max_isize_plus_1 = 1i128 << (self.pointer_size().bits() - 1); + i64::try_from(-max_isize_plus_1).unwrap() + } + #[inline] fn machine_isize_max(&self) -> i64 { let max_isize_plus_1 = 1u128 << (self.pointer_size().bits() - 1); @@ -42,18 +48,23 @@ pub trait PointerArithmetic: HasDataLayout { #[inline] fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) { + // We do not need to check if i fits in a machine usize. If it doesn't, + // either the wrapping_add will wrap or res will not fit in a pointer. let res = val.overflowing_add(i); self.truncate_to_ptr(res) } #[inline] fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) { + // We need to make sure that i fits in a machine isize. let n = uabs(i); if i >= 0 { - self.overflowing_offset(val, n) + let (val, over) = self.overflowing_offset(val, n); + (val, over || i > self.machine_isize_max()) } else { let res = val.overflowing_sub(n); - self.truncate_to_ptr(res) + let (val, over) = self.truncate_to_ptr(res); + (val, over || i < self.machine_isize_min()) } } diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 239115076bc4b..55f254f573261 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -441,9 +441,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // We cannot overflow i64 as a type's size must be <= isize::MAX. let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); // The computed offset, in bytes, cannot overflow an isize. - let offset_bytes = offset_count - .checked_mul(pointee_size) - .ok_or(err_ub_format!("inbounds pointer arithmetic: overflow computing offset"))?; + let offset_bytes = + offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?; // The offset being in bounds cannot rely on "wrapping around" the address space. // So, first rule out overflows in the pointer arithmetic. let offset_ptr = ptr.ptr_signed_offset(offset_bytes, self)?; diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr index e808939682f30..0ab81cc0c5b31 100644 --- a/src/test/ui/consts/offset_ub.stderr +++ b/src/test/ui/consts/offset_ub.stderr @@ -51,7 +51,7 @@ error: any use of this value will cause an error LL | intrinsics::offset(self, count) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | inbounds pointer arithmetic: overflow computing offset + | overflowing in-bounds pointer arithmetic | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | inside `OVERFLOW` at $DIR/offset_ub.rs:11:43 | @@ -66,7 +66,7 @@ error: any use of this value will cause an error LL | intrinsics::offset(self, count) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | inbounds pointer arithmetic: overflow computing offset + | overflowing in-bounds pointer arithmetic | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44 | From cb6408afc64cd364ccf3b8144d49b32e8403883c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 27 May 2020 19:24:09 -0700 Subject: [PATCH 41/44] Fix rebase --- .../nice_region_error/trait_impl_difference.rs | 7 ++++--- src/test/ui/error-codes/E0490.stderr | 4 ++-- .../ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr | 4 ++-- src/test/ui/issues/issue-20225.stderr | 4 ---- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 120594df6719b..8180dd5ef34f7 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -83,7 +83,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } let mut visitor = AssocTypeFinder(FxIndexSet::default()); trait_fn_sig.output().visit_with(&mut visitor); - if let Some(id) = tcx.hir().as_local_hir_id(trait_def_id) { + if let Some(id) = trait_def_id.as_local().map(|id| tcx.hir().as_local_hir_id(id)) { let parent_id = tcx.hir().get_parent_item(id); let trait_item = tcx.hir().expect_item(parent_id); if let ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { @@ -103,9 +103,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let assoc_item = self.tcx().associated_item(trait_def_id); let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; match assoc_item.kind { - ty::AssocKind::Method => { + ty::AssocKind::Fn => { let hir = self.tcx().hir(); - if let Some(hir_id) = hir.as_local_hir_id(assoc_item.def_id) { + if let Some(hir_id) = assoc_item.def_id.as_local().map(|id| hir.as_local_hir_id(id)) + { if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) { visitor.visit_fn_decl(decl); } diff --git a/src/test/ui/error-codes/E0490.stderr b/src/test/ui/error-codes/E0490.stderr index 03fce213605e3..9ba5bc330ea93 100644 --- a/src/test/ui/error-codes/E0490.stderr +++ b/src/test/ui/error-codes/E0490.stderr @@ -58,8 +58,8 @@ note: ...so that the expression is assignable | LL | let x: &'a _ = &y; | ^^ - = note: expected `&'a &()` - found `&'a &'b ()` + = note: expected `&'a &()` + found `&'a &'b ()` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6... --> $DIR/E0490.rs:1:6 | diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr index c58f78b6719a1..908a81bedb0ca 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr @@ -2,10 +2,10 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/mismatched_trait_impl.rs:9:5 | LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32; - | ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32 + | ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32` ... LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32` | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` diff --git a/src/test/ui/issues/issue-20225.stderr b/src/test/ui/issues/issue-20225.stderr index 133dbc554c089..3bcc50ded8425 100644 --- a/src/test/ui/issues/issue-20225.stderr +++ b/src/test/ui/issues/issue-20225.stderr @@ -8,8 +8,6 @@ LL | extern "rust-call" fn call(&self, (_,): (T,)) {} | = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))` found fn pointer `extern "rust-call" fn(&Foo, (T,))` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0053]: method `call_mut` has an incompatible type for trait --> $DIR/issue-20225.rs:11:3 @@ -21,8 +19,6 @@ LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} | = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))` found fn pointer `extern "rust-call" fn(&mut Foo, (T,))` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0053]: method `call_once` has an incompatible type for trait --> $DIR/issue-20225.rs:18:3 From f213acf4db81a33308ab2d53b5927108d63a2d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 27 May 2020 20:58:05 -0700 Subject: [PATCH 42/44] review comments: change wording and visual output --- .../trait_impl_difference.rs | 63 +++++-------------- .../mismatched_trait_impl-2.stderr | 2 +- .../mismatched_trait_impl.nll.stderr | 2 +- .../mismatched_trait_impl.stderr | 2 +- ...ime-mismatch-between-trait-and-impl.stderr | 2 +- ...t-param-without-lifetime-constraint.stderr | 14 ++--- 6 files changed, 26 insertions(+), 59 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 8180dd5ef34f7..1b6e5c2116b39 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -4,16 +4,13 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; -use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::ItemKind; use rustc_middle::ty::error::ExpectedFound; -use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::Span; +use rustc_span::{MultiSpan, Span}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`. @@ -63,41 +60,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); err.span_label(sp, &format!("found `{:?}`", found)); err.span_label(trait_sp, &format!("expected `{:?}`", expected)); - let trait_fn_sig = tcx.fn_sig(trait_def_id); - - // Check the `trait`'s method's output to look for type parameters that might have - // unconstrained lifetimes. If the method returns a type parameter and the `impl` has a - // borrow as the type parameter being implemented, the lifetimes will not match because - // a new lifetime is being introduced in the `impl` that is not present in the `trait`. - // Because this is confusing as hell the first time you see it, we give a short message - // explaining the situation and proposing constraining the type param with a named lifetime - // so that the `impl` will have one to tie them together. - struct AssocTypeFinder(FxIndexSet); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for AssocTypeFinder { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - if let ty::Param(param) = ty.kind { - self.0.insert(param); - } - ty.super_visit_with(self) - } - } - let mut visitor = AssocTypeFinder(FxIndexSet::default()); - trait_fn_sig.output().visit_with(&mut visitor); - if let Some(id) = trait_def_id.as_local().map(|id| tcx.hir().as_local_hir_id(id)) { - let parent_id = tcx.hir().get_parent_item(id); - let trait_item = tcx.hir().expect_item(parent_id); - if let ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { - for param_ty in &visitor.0 { - if let Some(generic) = generics.get_named(param_ty.name) { - err.span_label( - generic.span, - "this type parameter might not have a lifetime compatible with the \ - `impl`", - ); - } - } - } - } // Get the span of all the used type parameters in the method. let assoc_item = self.tcx().associated_item(trait_def_id); @@ -114,11 +76,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } _ => {} } - for span in visitor.types { - err.span_label( + let mut type_param_span: MultiSpan = + visitor.types.iter().cloned().collect::>().into(); + for &span in &visitor.types { + type_param_span.push_span_label( span, - "you might want to borrow this type parameter in the trait to make it match the \ - `impl`", + "consider borrowing this type parameter in the trait".to_string(), ); } @@ -132,11 +95,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // This fallback shouldn't be necessary, but let's keep it in just in case. err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); } - err.note("the lifetime requirements from the `trait` could not be satisfied by the `impl`"); - err.help( - "verify the lifetime relationships in the `trait` and `impl` between the `self` \ - argument, the other inputs and its output", + err.span_help( + type_param_span, + "the lifetime requirements from the `impl` do not correspond to the requirements in \ + the `trait`", ); + if visitor.types.is_empty() { + err.help( + "verify the lifetime relationships in the `trait` and `impl` between the `self` \ + argument, the other inputs and its output", + ); + } err.emit(); } } diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index 61a8674a2310e..b93d98ca39f47 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -11,7 +11,7 @@ LL | fn deref(&self) -> &Self::Target; | = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` found `fn(&Struct) -> &dyn Trait` - = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr index 908a81bedb0ca..149c2aeb958c0 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr @@ -9,7 +9,7 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` - = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index ca61029145530..9a0bd827850cf 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -9,7 +9,7 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` - = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error[E0623]: lifetime mismatch diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr index 53f6aae5ff6e0..060e6954403c0 100644 --- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -9,7 +9,7 @@ LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { | = note: expected `fn(&i32, &'a i32) -> &'a i32` found `fn(&i32, &i32) -> &i32` - = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr index a7be2d3365c1a..4942dbe480ba3 100644 --- a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr +++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr @@ -1,21 +1,19 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/trait-param-without-lifetime-constraint.rs:14:5 | -LL | pub trait HaveRelationship { - | -- this type parameter might not have a lifetime compatible with the `impl` LL | fn get_relation(&self) -> To; - | ----------------------------- - | | | - | | you might want to borrow this type parameter in the trait to make it match the `impl` - | expected `fn(&Article) -> &ProofReader` + | ----------------------------- expected `fn(&Article) -> &ProofReader` ... LL | fn get_relation(&self) -> &ProofReader { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader` | = note: expected `fn(&Article) -> &ProofReader` found `fn(&Article) -> &ProofReader` - = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` - = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output +help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + --> $DIR/trait-param-without-lifetime-constraint.rs:10:31 + | +LL | fn get_relation(&self) -> To; + | ^^ consider borrowing this type parameter in the trait error: aborting due to previous error From 0e3b31c641217542f02b40527b0d299d9534b920 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 28 May 2020 13:23:33 -0400 Subject: [PATCH 43/44] Update src/librustdoc/core.rs --- src/librustdoc/core.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 331ce1453e139..99ca7084c30dd 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -228,7 +228,7 @@ where // Whitelist feature-gated lints to avoid feature errors when trying to // allow all lints. - // FIXME(LeSeulArtichaut): handle feature-gated lints properly. + // FIXME(#72694): handle feature-gated lints properly. let unsafe_op_in_unsafe_fn_name = rustc_lint::builtin::UNSAFE_OP_IN_UNSAFE_FN.name; whitelisted_lints.push(warnings_lint_name.to_owned()); From 1bd69702de07858ad9c7ae7ed89c3c99aea64550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 28 May 2020 10:35:48 -0700 Subject: [PATCH 44/44] Account for `Self` as a type param --- .../trait_impl_difference.rs | 10 ++-- .../self-without-lifetime-constraint.rs | 53 +++++++++++++++++++ .../self-without-lifetime-constraint.stderr | 19 +++++++ 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/traits/self-without-lifetime-constraint.rs create mode 100644 src/test/ui/traits/self-without-lifetime-constraint.stderr diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 1b6e5c2116b39..5f14f799fc7aa 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -6,6 +6,7 @@ use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; use rustc_errors::ErrorReported; use rustc_hir as hir; +use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_middle::ty::error::ExpectedFound; @@ -124,15 +125,17 @@ impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { match arg.kind { - hir::TyKind::Slice(_) | hir::TyKind::Tup(_) | hir::TyKind::Array(..) => { - hir::intravisit::walk_ty(self, arg); + hir::TyKind::Rptr(_, ref mut_ty) => { + // We don't want to suggest looking into borrowing `&T` or `&Self`. + hir::intravisit::walk_ty(self, mut_ty.ty); + return; } hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { [segment] if segment .res .map(|res| match res { - hir::def::Res::Def(hir::def::DefKind::TyParam, _) => true, + Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true, _ => false, }) .unwrap_or(false) => @@ -143,5 +146,6 @@ impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { }, _ => {} } + hir::intravisit::walk_ty(self, arg); } } diff --git a/src/test/ui/traits/self-without-lifetime-constraint.rs b/src/test/ui/traits/self-without-lifetime-constraint.rs new file mode 100644 index 0000000000000..99013d32ab8d0 --- /dev/null +++ b/src/test/ui/traits/self-without-lifetime-constraint.rs @@ -0,0 +1,53 @@ +use std::error::Error; +use std::fmt; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum ValueRef<'a> { + Null, + Integer(i64), + Real(f64), + Text(&'a [u8]), + Blob(&'a [u8]), +} + +impl<'a> ValueRef<'a> { + pub fn as_str(&self) -> FromSqlResult<&'a str, &'a &'a str> { + match *self { + ValueRef::Text(t) => { + std::str::from_utf8(t).map_err(|_| FromSqlError::InvalidType).map(|x| (x, &x)) + } + _ => Err(FromSqlError::InvalidType), + } + } +} + +#[derive(Debug)] +#[non_exhaustive] +pub enum FromSqlError { + InvalidType +} + +impl fmt::Display for FromSqlError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "InvalidType") + } +} + +impl Error for FromSqlError {} + +pub type FromSqlResult = Result<(T, K), FromSqlError>; + +pub trait FromSql: Sized { + fn column_result(value: ValueRef<'_>) -> FromSqlResult; +} + +impl FromSql for &str { + fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> { + //~^ ERROR `impl` item signature doesn't match `trait` item signature + value.as_str() + } +} + +pub fn main() { + println!("{}", "Hello World"); +} diff --git a/src/test/ui/traits/self-without-lifetime-constraint.stderr b/src/test/ui/traits/self-without-lifetime-constraint.stderr new file mode 100644 index 0000000000000..6c7abe753e2bf --- /dev/null +++ b/src/test/ui/traits/self-without-lifetime-constraint.stderr @@ -0,0 +1,19 @@ +error: `impl` item signature doesn't match `trait` item signature + --> $DIR/self-without-lifetime-constraint.rs:45:5 + | +LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult; + | -------------------------------------------------------------------- expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>` +... +LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>` + | + = note: expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>` + found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>` +help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + --> $DIR/self-without-lifetime-constraint.rs:41:60 + | +LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult; + | ^^^^ consider borrowing this type parameter in the trait + +error: aborting due to previous error +