diff --git a/src/liballoc/collections/vec_deque/tests.rs b/src/liballoc/collections/vec_deque/tests.rs index 8ef5ec78e056..0a3f33003233 100644 --- a/src/liballoc/collections/vec_deque/tests.rs +++ b/src/liballoc/collections/vec_deque/tests.rs @@ -386,10 +386,8 @@ fn test_vec_from_vecdeque() { assert!(vec.into_iter().eq(vd)); } - #[cfg(not(miri))] // Miri is too slow - let max_pwr = 7; - #[cfg(miri)] - let max_pwr = 5; + // Miri is too slow + let max_pwr = if cfg!(miri) { 5 } else { 7 }; for cap_pwr in 0..max_pwr { // Make capacity as a (2^x)-1, so that the ring size is 2^x diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index be5516f54f37..057afd41824e 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -409,16 +409,14 @@ fn panic_safe() { } let mut rng = thread_rng(); const DATASZ: usize = 32; - #[cfg(not(miri))] // Miri is too slow - const NTEST: usize = 10; - #[cfg(miri)] - const NTEST: usize = 1; + // Miri is too slow + let ntest = if cfg!(miri) { 1 } else { 10 }; // don't use 0 in the data -- we want to catch the zeroed-out case. let data = (1..=DATASZ).collect::>(); // since it's a fuzzy test, run several tries. - for _ in 0..NTEST { + for _ in 0..ntest { for i in 1..=DATASZ { DROP_COUNTER.store(0, Ordering::SeqCst); diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 96b6c32a1fa8..731a1b5f875b 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -28,10 +28,8 @@ const MIN_INSERTS_HEIGHT_2: usize = NODE_CAPACITY + (NODE_CAPACITY + 1) * NODE_C #[test] fn test_basic_large() { let mut map = BTreeMap::new(); - #[cfg(not(miri))] // Miri is too slow - let size = 10000; - #[cfg(miri)] - let size = MIN_INSERTS_HEIGHT_2; + // Miri is too slow + let size = if cfg!(miri) { MIN_INSERTS_HEIGHT_2 } else { 10000 }; assert_eq!(map.len(), 0); for i in 0..size { @@ -155,10 +153,8 @@ fn test_basic_small() { #[test] fn test_iter() { - #[cfg(not(miri))] // Miri is too slow - let size = 10000; - #[cfg(miri)] - let size = 200; + // Miri is too slow + let size = if cfg!(miri) { 200 } else { 10000 }; let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); @@ -180,10 +176,8 @@ fn test_iter() { #[test] fn test_iter_rev() { - #[cfg(not(miri))] // Miri is too slow - let size = 10000; - #[cfg(miri)] - let size = 200; + // Miri is too slow + let size = if cfg!(miri) { 200 } else { 10000 }; let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); @@ -289,10 +283,8 @@ fn test_values_mut() { #[test] fn test_iter_mixed() { - #[cfg(not(miri))] // Miri is too slow - let size = 10000; - #[cfg(miri)] - let size = 200; + // Miri is too slow + let size = if cfg!(miri) { 200 } else { 10000 }; let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); @@ -525,10 +517,8 @@ fn test_range_backwards_4() { #[test] fn test_range_1000() { - #[cfg(not(miri))] // Miri is too slow - let size = 1000; - #[cfg(miri)] - let size = MIN_INSERTS_HEIGHT_2 as u32; + // Miri is too slow + let size = if cfg!(miri) { MIN_INSERTS_HEIGHT_2 as u32 } else { 1000 }; let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); fn test(map: &BTreeMap, size: u32, min: Bound<&u32>, max: Bound<&u32>) { @@ -566,10 +556,8 @@ fn test_range_borrowed_key() { #[test] fn test_range() { let size = 200; - #[cfg(not(miri))] // Miri is too slow - let step = 1; - #[cfg(miri)] - let step = 66; + // Miri is too slow + let step = if cfg!(miri) { 66 } else { 1 }; let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); for i in (0..size).step_by(step) { @@ -589,10 +577,8 @@ fn test_range() { #[test] fn test_range_mut() { let size = 200; - #[cfg(not(miri))] // Miri is too slow - let step = 1; - #[cfg(miri)] - let step = 66; + // Miri is too slow + let step = if cfg!(miri) { 66 } else { 1 }; let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); for i in (0..size).step_by(step) { @@ -1263,10 +1249,8 @@ fn test_split_off_empty_left() { #[test] fn test_split_off_large_random_sorted() { - #[cfg(not(miri))] // Miri is too slow - let mut data = rand_data(1529); - #[cfg(miri)] - let mut data = rand_data(529); + // Miri is too slow + let mut data = if cfg!(miri) { rand_data(529) } else { rand_data(1529) }; // special case with maximum height. data.sort(); diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 136018b9f7df..75251ca0d51e 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -621,10 +621,8 @@ fn test_split_off_empty_left() { #[test] fn test_split_off_large_random_sorted() { - #[cfg(not(miri))] // Miri is too slow - let mut data = rand_data(1529); - #[cfg(miri)] - let mut data = rand_data(529); + // Miri is too slow + let mut data = if cfg!(miri) { rand_data(529) } else { rand_data(1529) }; // special case with maximum height. data.sort(); diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index 8e49e6d8ebad..75b76bb73ed9 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -463,15 +463,9 @@ fn test_sort() { #[test] fn test_sort_stability() { - #[cfg(not(miri))] // Miri is too slow - let large_range = 500..510; - #[cfg(not(miri))] // Miri is too slow - let rounds = 10; - - #[cfg(miri)] - let large_range = 0..0; // empty range - #[cfg(miri)] - let rounds = 1; + // Miri is too slow + let large_range = if cfg!(miri) { 0..0 } else { 500..510 }; + let rounds = if cfg!(miri) { 1 } else { 10 }; for len in (2..25).chain(large_range) { for _ in 0..rounds { @@ -1727,15 +1721,9 @@ fn panic_safe() { let mut rng = thread_rng(); - #[cfg(not(miri))] // Miri is too slow - let lens = (1..20).chain(70..MAX_LEN); - #[cfg(not(miri))] // Miri is too slow - let moduli = &[5, 20, 50]; - - #[cfg(miri)] - let lens = 1..10; - #[cfg(miri)] - let moduli = &[5]; + // Miri is too slow + let lens = if cfg!(miri) { (1..10).chain(20..21) } else { (1..20).chain(70..MAX_LEN) }; + let moduli: &[u32] = if cfg!(miri) { &[5] } else { &[5, 20, 50] }; for len in lens { for &modulus in moduli { diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index c4b6a36bb054..762dc4be44d6 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -954,16 +954,14 @@ fn test_append_permutations() { out } - #[cfg(not(miri))] // Miri is too slow - const MAX: usize = 5; - #[cfg(miri)] - const MAX: usize = 3; + // Miri is too slow + let max = if cfg!(miri) { 3 } else { 5 }; // Many different permutations of both the `VecDeque` getting appended to // and the one getting appended are generated to check `append`. // This ensures all 6 code paths of `append` are tested. - for src_push_back in 0..MAX { - for src_push_front in 0..MAX { + for src_push_back in 0..max { + for src_push_front in 0..max { // doesn't pop more values than are pushed for src_pop_back in 0..(src_push_back + src_push_front) { for src_pop_front in 0..(src_push_back + src_push_front - src_pop_back) { @@ -974,8 +972,8 @@ fn test_append_permutations() { src_pop_front, ); - for dst_push_back in 0..MAX { - for dst_push_front in 0..MAX { + for dst_push_back in 0..max { + for dst_push_front in 0..max { for dst_pop_back in 0..(dst_push_back + dst_push_front) { for dst_pop_front in 0..(dst_push_back + dst_push_front - dst_pop_back) diff --git a/src/libcore/tests/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs index 8ee06d895cae..da203b5f3620 100644 --- a/src/libcore/tests/num/flt2dec/estimator.rs +++ b/src/libcore/tests/num/flt2dec/estimator.rs @@ -52,12 +52,10 @@ fn test_estimate_scaling_factor() { assert_almost_eq!(estimate_scaling_factor(1, -1074), -323); assert_almost_eq!(estimate_scaling_factor(0x1fffffffffffff, 971), 309); - #[cfg(not(miri))] // Miri is too slow - let iter = -1074..972; - #[cfg(miri)] - let iter = (-1074..972).step_by(37); + // Miri is too slow + let step = if cfg!(miri) { 37 } else { 1 }; - for i in iter { + for i in (-1074..972).step_by(step) { let expected = super::ldexp_f64(1.0, i).log10().ceil(); assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16); } diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs index 5b050a2c3563..0ebc0881f522 100644 --- a/src/libcore/tests/num/flt2dec/random.rs +++ b/src/libcore/tests/num/flt2dec/random.rs @@ -138,13 +138,11 @@ where #[test] fn shortest_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - #[cfg(not(miri))] // Miri is too slow - const N: usize = 10_000; - #[cfg(miri)] - const N: usize = 10; + // Miri is too slow + let n = if cfg!(miri) { 10 } else { 10_000 }; - f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N); - f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N); + f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n); + f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n); } #[test] @@ -173,17 +171,15 @@ fn shortest_f64_hard_random_equivalence_test() { #[test] fn exact_f32_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_exact as fallback; - #[cfg(not(miri))] // Miri is too slow - const N: usize = 1_000; - #[cfg(miri)] - const N: usize = 3; + // Miri is too slow + let n = if cfg!(miri) { 3 } else { 1_000 }; for k in 1..21 { f32_random_equivalence_test( |d, buf| format_exact_opt(d, buf, i16::MIN), |d, buf| fallback(d, buf, i16::MIN), k, - N, + n, ); } } @@ -191,17 +187,15 @@ fn exact_f32_random_equivalence_test() { #[test] fn exact_f64_random_equivalence_test() { use core::num::flt2dec::strategy::dragon::format_exact as fallback; - #[cfg(not(miri))] // Miri is too slow - const N: usize = 1_000; - #[cfg(miri)] - const N: usize = 3; + // Miri is too slow + let n = if cfg!(miri) { 3 } else { 1_000 }; for k in 1..21 { f64_random_equivalence_test( |d, buf| format_exact_opt(d, buf, i16::MIN), |d, buf| fallback(d, buf, i16::MIN), k, - N, + n, ); } } diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 9b9420cc13f8..54a585415bce 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -1227,15 +1227,9 @@ fn sort_unstable() { use core::slice::heapsort; use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng}; - #[cfg(not(miri))] // Miri is too slow - let large_range = 500..510; - #[cfg(not(miri))] // Miri is too slow - let rounds = 100; - - #[cfg(miri)] - let large_range = 0..0; // empty range - #[cfg(miri)] - let rounds = 1; + // Miri is too slow + let large_range = if cfg!(miri) { 0..0 } else { 500..510 }; + let rounds = if cfg!(miri) { 1 } else { 100 }; let mut v = [0; 600]; let mut tmp = [0; 600]; diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs index dde734756517..cf6dde813096 100644 --- a/src/librustc_ast_lowering/path.rs +++ b/src/librustc_ast_lowering/path.rs @@ -273,7 +273,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .next(); if !generic_args.parenthesized && !has_lifetimes { generic_args.args = self - .elided_path_lifetimes(path_span, expected_lifetimes) + .elided_path_lifetimes( + first_generic_span.map(|s| s.shrink_to_lo()).unwrap_or(segment.ident.span), + expected_lifetimes, + ) .map(GenericArg::Lifetime) .chain(generic_args.args.into_iter()) .collect(); diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 0e06f5162f8c..45abde434772 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -81,14 +81,9 @@ pub struct Frame<'mir, 'tcx, Tag = (), Extra = ()> { //////////////////////////////////////////////////////////////////////////////// // Current position within the function //////////////////////////////////////////////////////////////////////////////// - /// The block that is currently executed (or will be executed after the above call stacks - /// return). /// If this is `None`, we are unwinding and this function doesn't need any clean-up. /// Just continue the same as with `Resume`. - pub block: Option, - - /// The index of the currently evaluated statement. - pub stmt: usize, + pub loc: Option, } #[derive(Clone, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these @@ -168,8 +163,7 @@ impl<'mir, 'tcx, Tag> Frame<'mir, 'tcx, Tag> { return_to_block: self.return_to_block, return_place: self.return_place, locals: self.locals, - block: self.block, - stmt: self.stmt, + loc: self.loc, extra, } } @@ -178,10 +172,10 @@ impl<'mir, 'tcx, Tag> Frame<'mir, 'tcx, Tag> { impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> { /// Return the `SourceInfo` of the current instruction. pub fn current_source_info(&self) -> Option { - self.block.map(|block| { - let block = &self.body.basic_blocks()[block]; - if self.stmt < block.statements.len() { - block.statements[self.stmt].source_info + self.loc.map(|loc| { + let block = &self.body.basic_blocks()[loc.block]; + if loc.statement_index < block.statements.len() { + block.statements[loc.statement_index].source_info } else { block.terminator().source_info } @@ -615,14 +609,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // first push a stack frame so we have access to the local substs let pre_frame = Frame { body, - block: Some(mir::START_BLOCK), + loc: Some(mir::Location::START), return_to_block, return_place, // empty local array, we fill it in below, after we are inside the stack frame and // all methods actually know about the frame locals: IndexVec::new(), instance, - stmt: 0, extra: (), }; let frame = M::init_frame_extra(self, pre_frame)?; @@ -666,9 +659,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Jump to the given block. #[inline] pub fn go_to_block(&mut self, target: mir::BasicBlock) { - let frame = self.frame_mut(); - frame.block = Some(target); - frame.stmt = 0; + self.frame_mut().loc = Some(mir::Location { block: target, statement_index: 0 }); } /// *Return* to the given `target` basic block. @@ -690,9 +681,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// If `target` is `None`, that indicates the function does not need cleanup during /// unwinding, and we will just keep propagating that upwards. pub fn unwind_to_block(&mut self, target: Option) { - let frame = self.frame_mut(); - frame.block = target; - frame.stmt = 0; + self.frame_mut().loc = target.map(|block| mir::Location { block, statement_index: 0 }); } /// Pops the current frame from the stack, deallocating the @@ -719,9 +708,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Sanity check `unwinding`. assert_eq!( unwinding, - match self.frame().block { + match self.frame().loc { None => true, - Some(block) => self.body().basic_blocks()[block].is_cleanup, + Some(loc) => self.body().basic_blocks()[loc.block].is_cleanup, } ); @@ -973,13 +962,14 @@ where Tag: HashStable>, { fn hash_stable(&self, hcx: &mut StableHashingContext<'ctx>, hasher: &mut StableHasher) { - self.body.hash_stable(hcx, hasher); - self.instance.hash_stable(hcx, hasher); - self.return_to_block.hash_stable(hcx, hasher); - self.return_place.as_ref().map(|r| &**r).hash_stable(hcx, hasher); - self.locals.hash_stable(hcx, hasher); - self.block.hash_stable(hcx, hasher); - self.stmt.hash_stable(hcx, hasher); - self.extra.hash_stable(hcx, hasher); + // Exhaustive match on fields to make sure we forget no field. + let Frame { body, instance, return_to_block, return_place, locals, loc, extra } = self; + body.hash_stable(hcx, hasher); + instance.hash_stable(hcx, hasher); + return_to_block.hash_stable(hcx, hasher); + return_place.as_ref().map(|r| &**r).hash_stable(hcx, hasher); + locals.hash_stable(hcx, hasher); + loc.hash_stable(hcx, hasher); + extra.hash_stable(hcx, hasher); } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index aae708827b95..bb4c0156c88c 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -46,8 +46,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(false); } - let block = match self.frame().block { - Some(block) => block, + let loc = match self.frame().loc { + Some(loc) => loc, None => { // We are unwinding and this fn has no cleanup code. // Just go on unwinding. @@ -56,13 +56,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(true); } }; - let stmt_id = self.frame().stmt; - let body = self.body(); - let basic_block = &body.basic_blocks()[block]; + let basic_block = &self.body().basic_blocks()[loc.block]; let old_frames = self.frame_idx(); - if let Some(stmt) = basic_block.statements.get(stmt_id) { + if let Some(stmt) = basic_block.statements.get(loc.statement_index) { assert_eq!(old_frames, self.frame_idx()); self.statement(stmt)?; return Ok(true); @@ -126,7 +124,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"), } - self.stack_mut()[frame_idx].stmt += 1; + self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1; Ok(()) } @@ -279,8 +277,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.eval_terminator(terminator)?; if !self.stack().is_empty() { - if let Some(block) = self.frame().block { - info!("// executing {:?}", block); + if let Some(loc) = self.frame().loc { + info!("// executing {:?}", loc.block); } } Ok(()) diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 777a4381cda7..9f9ec0f6a783 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -52,7 +52,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Call { ref func, ref args, destination, ref cleanup, .. } => { let old_stack = self.frame_idx(); - let old_bb = self.frame().block; + let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; let (fn_val, abi) = match func.layout.ty.kind { ty::FnPtr(sig) => { @@ -79,7 +79,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?; // Sanity-check that `eval_fn_call` either pushed a new frame or // did a jump to another block. - if self.frame_idx() == old_stack && self.frame().block == old_bb { + if self.frame_idx() == old_stack && self.frame().loc == old_loc { span_bug!(terminator.source_info.span, "evaluating this call made no progress"); } } diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index e7fa88bff97d..c25a3524dc10 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -1034,101 +1034,125 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { lifetime_names: &FxHashSet, params: &[ElisionFailureInfo], ) { - if count > 1 { - err.span_label(span, format!("expected {} lifetime parameters", count)); - } else { - let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok(); - let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { - err.span_suggestion( - span, - "consider using the named lifetime", - sugg, - Applicability::MaybeIncorrect, - ); - }; - let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| { - err.span_label(span, "expected named lifetime parameter"); + let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok(); - for missing in self.missing_named_lifetime_spots.iter().rev() { - let mut introduce_suggestion = vec![]; - let msg; - let should_break; - introduce_suggestion.push(match missing { - MissingLifetimeSpot::Generics(generics) => { - msg = "consider introducing a named lifetime parameter".to_string(); - should_break = true; - if let Some(param) = generics.params.iter().find(|p| match p.kind { - hir::GenericParamKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), - .. - } => false, - _ => true, - }) { - (param.span.shrink_to_lo(), "'a, ".to_string()) - } else { - (generics.span, "<'a>".to_string()) - } - } - MissingLifetimeSpot::HigherRanked { span, span_type } => { - msg = format!( - "consider making the {} lifetime-generic with a new `'a` lifetime", - span_type.descr(), - ); - should_break = false; - err.note( - "for more information on higher-ranked polymorphism, visit \ - https://doc.rust-lang.org/nomicon/hrtb.html", - ); - (*span, span_type.suggestion("'a")) - } - }); - for param in params { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) - { - if snippet.starts_with('&') && !snippet.starts_with("&'") { - introduce_suggestion - .push((param.span, format!("&'a {}", &snippet[1..]))); - } else if snippet.starts_with("&'_ ") { - introduce_suggestion - .push((param.span, format!("&'a {}", &snippet[4..]))); - } + err.span_label( + span, + &format!( + "expected {} lifetime parameter{}", + if count == 1 { "named".to_string() } else { count.to_string() }, + pluralize!(count) + ), + ); + + let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { + err.span_suggestion_verbose( + span, + &format!("consider using the `{}` lifetime", lifetime_names.iter().next().unwrap()), + sugg, + Applicability::MaybeIncorrect, + ); + }; + let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| { + for missing in self.missing_named_lifetime_spots.iter().rev() { + let mut introduce_suggestion = vec![]; + let msg; + let should_break; + introduce_suggestion.push(match missing { + MissingLifetimeSpot::Generics(generics) => { + msg = "consider introducing a named lifetime parameter".to_string(); + should_break = true; + if let Some(param) = generics.params.iter().find(|p| match p.kind { + hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => false, + _ => true, + }) { + (param.span.shrink_to_lo(), "'a, ".to_string()) + } else { + (generics.span, "<'a>".to_string()) } } - introduce_suggestion.push((span, sugg.to_string())); - err.multipart_suggestion( - &msg, - introduce_suggestion, - Applicability::MaybeIncorrect, - ); - if should_break { - break; + MissingLifetimeSpot::HigherRanked { span, span_type } => { + msg = format!( + "consider making the {} lifetime-generic with a new `'a` lifetime", + span_type.descr(), + ); + should_break = false; + err.note( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + (*span, span_type.suggestion("'a")) + } + }); + for param in params { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) { + if snippet.starts_with('&') && !snippet.starts_with("&'") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[1..]))); + } else if snippet.starts_with("&'_ ") { + introduce_suggestion + .push((param.span, format!("&'a {}", &snippet[4..]))); + } } } - }; - - match (lifetime_names.len(), lifetime_names.iter().next(), snippet.as_deref()) { - (1, Some(name), Some("&")) => { - suggest_existing(err, format!("&{} ", name)); - } - (1, Some(name), Some("'_")) => { - suggest_existing(err, name.to_string()); - } - (1, Some(name), Some(snippet)) if !snippet.ends_with('>') => { - suggest_existing(err, format!("{}<{}>", snippet, name)); - } - (0, _, Some("&")) => { - suggest_new(err, "&'a "); - } - (0, _, Some("'_")) => { - suggest_new(err, "'a"); - } - (0, _, Some(snippet)) if !snippet.ends_with('>') => { - suggest_new(err, &format!("{}<'a>", snippet)); + introduce_suggestion.push((span, sugg.to_string())); + err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect); + if should_break { + break; } - _ => { - err.span_label(span, "expected lifetime parameter"); + } + }; + + match (lifetime_names.len(), lifetime_names.iter().next(), snippet.as_deref()) { + (1, Some(name), Some("&")) => { + suggest_existing(err, format!("&{} ", name)); + } + (1, Some(name), Some("'_")) => { + suggest_existing(err, name.to_string()); + } + (1, Some(name), Some("")) => { + suggest_existing(err, format!("{}, ", name).repeat(count)); + } + (1, Some(name), Some(snippet)) if !snippet.ends_with('>') => { + suggest_existing( + err, + format!( + "{}<{}>", + snippet, + std::iter::repeat(name.to_string()) + .take(count) + .collect::>() + .join(", ") + ), + ); + } + (0, _, Some("&")) if count == 1 => { + suggest_new(err, "&'a "); + } + (0, _, Some("'_")) if count == 1 => { + suggest_new(err, "'a"); + } + (0, _, Some(snippet)) if !snippet.ends_with('>') && count == 1 => { + suggest_new(err, &format!("{}<'a>", snippet)); + } + (n, ..) if n > 1 => { + let spans: Vec = lifetime_names.iter().map(|lt| lt.span).collect(); + err.span_note(spans, "these named lifetimes are available to use"); + if Some("") == snippet.as_deref() { + // This happens when we have `Foo` where we point at the space before `T`, + // but this can be confusing so we give a suggestion with placeholders. + err.span_suggestion_verbose( + span, + "consider using one of the available lifetimes here", + "'lifetime, ".repeat(count), + Applicability::HasPlaceholders, + ); } } + _ => {} } } } diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index a988c5829b5e..0deb0af448e7 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -2393,52 +2393,28 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { }; let mut err = self.report_missing_lifetime_specifiers(span, lifetime_refs.len()); - let mut add_label = true; if let Some(params) = error { - if lifetime_refs.len() == 1 { - add_label = add_label && self.report_elision_failure(&mut err, params, span); + // If there's no lifetime available, suggest `'static`. + if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() { + lifetime_names.insert(ast::Ident::from_str("'static")); } } - if add_label { - self.add_missing_lifetime_specifiers_label( - &mut err, - span, - lifetime_refs.len(), - &lifetime_names, - error.map(|p| &p[..]).unwrap_or(&[]), - ); - } - + self.add_missing_lifetime_specifiers_label( + &mut err, + span, + lifetime_refs.len(), + &lifetime_names, + error.map(|p| &p[..]).unwrap_or(&[]), + ); err.emit(); } - fn suggest_lifetime(&self, db: &mut DiagnosticBuilder<'_>, span: Span, msg: &str) -> bool { - match self.tcx.sess.source_map().span_to_snippet(span) { - Ok(ref snippet) => { - let (sugg, applicability) = if snippet == "&" { - ("&'static ".to_owned(), Applicability::MachineApplicable) - } else if snippet == "'_" { - ("'static".to_owned(), Applicability::MachineApplicable) - } else { - (format!("{} + 'static", snippet), Applicability::MaybeIncorrect) - }; - db.span_suggestion(span, msg, sugg, applicability); - false - } - Err(_) => { - db.help(msg); - true - } - } - } - fn report_elision_failure( &mut self, db: &mut DiagnosticBuilder<'_>, params: &[ElisionFailureInfo], - span: Span, - ) -> bool { + ) -> bool /* add `'static` lifetime to lifetime list */ { let mut m = String::new(); let len = params.len(); @@ -2487,29 +2463,28 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { "this function's return type contains a borrowed value, \ but there is no value for it to be borrowed from", ); - self.suggest_lifetime(db, span, "consider giving it a 'static lifetime") + true } else if elided_len == 0 { db.help( "this function's return type contains a borrowed value with \ an elided lifetime, but the lifetime cannot be derived from \ the arguments", ); - let msg = "consider giving it an explicit bounded or 'static lifetime"; - self.suggest_lifetime(db, span, msg) + true } else if elided_len == 1 { db.help(&format!( "this function's return type contains a borrowed value, \ but the signature does not say which {} it is borrowed from", m )); - true + false } else { db.help(&format!( "this function's return type contains a borrowed value, \ but the signature does not say whether it is borrowed from {}", m )); - true + false } } diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 85a870ae34c1..e8252d96350d 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -657,7 +657,8 @@ impl MultiSpan { MultiSpan { primary_spans: vec![primary_span], span_labels: vec![] } } - pub fn from_spans(vec: Vec) -> MultiSpan { + pub fn from_spans(mut vec: Vec) -> MultiSpan { + vec.sort(); MultiSpan { primary_spans: vec, span_labels: vec![] } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 63b8eb224cec..706dca999fa3 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1017,18 +1017,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); - let path_span = if let [segment] = &trait_ref.path.segments[..] { - // FIXME: `trait_ref.path.span` can point to a full path with multiple - // segments, even though `trait_ref.path.segments` is of length `1`. Work - // around that bug here, even though it should be fixed elsewhere. - // This would otherwise cause an invalid suggestion. For an example, look at - // `src/test/ui/issues/issue-28344.rs`. - segment.ident.span - } else { - trait_ref.path.span - }; let (substs, assoc_bindings, arg_count_correct) = self.create_substs_for_ast_trait_ref( - path_span, + trait_ref.path.span, trait_def_id, self_ty, trait_ref.path.segments.last().unwrap(), @@ -1729,6 +1719,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ast_region_to_region(lifetime, None) } else { self.re_infer(None, span).unwrap_or_else(|| { + // FIXME: these can be redundant with E0106, but not always. struct_span_err!( tcx.sess, span, diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr index 2745e44ac0cf..00f44129cc8b 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/bound-lifetime-in-binding-only.rs:52:23 | LL | fn elision &i32>() { - | ^ help: consider giving it a 'static lifetime: `&'static` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | fn elision &'static i32>() { + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr index 96f0cb85c8c4..a5242707c710 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/bound-lifetime-in-return-only.rs:34:23 | LL | fn elision(_: fn() -> &i32) { - | ^ help: consider giving it a 'static lifetime: `&'static` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | fn elision(_: fn() -> &'static i32) { + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr index 6edb9e63d480..ca42263dfed7 100644 --- a/src/test/ui/async-await/issues/issue-63388-2.stderr +++ b/src/test/ui/async-await/issues/issue-63388-2.stderr @@ -4,9 +4,13 @@ error[E0106]: missing lifetime specifier LL | foo: &dyn Foo, bar: &'a dyn Foo | -------- ----------- LL | ) -> &dyn Foo - | ^ help: consider using the named lifetime: `&'a` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `foo` or `bar` +help: consider using the `'a` lifetime + | +LL | ) -> &'a dyn Foo + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/c-variadic/variadic-ffi-6.stderr b/src/test/ui/c-variadic/variadic-ffi-6.stderr index 882e7f89f2a0..4626a4bc2dcf 100644 --- a/src/test/ui/c-variadic/variadic-ffi-6.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-6.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/variadic-ffi-6.rs:7:6 | LL | ) -> &usize { - | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments +help: consider using the `'static` lifetime + | +LL | ) -> &'static usize { + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.rs b/src/test/ui/consts/miri_unleashed/abi-mismatch.rs index d8e63b0bfb24..a99e6327987f 100644 --- a/src/test/ui/consts/miri_unleashed/abi-mismatch.rs +++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.rs @@ -2,15 +2,20 @@ // compile-flags: -Z unleash-the-miri-inside-of-you #![feature(const_extern_fn)] +#![allow(const_err)] const extern "C" fn c_fn() {} const fn call_rust_fn(my_fn: extern "Rust" fn()) { - my_fn(); //~ ERROR any use of this value will cause an error + my_fn(); //~^ WARN skipping const checks + //~| ERROR could not evaluate static initializer + //~| NOTE calling a function with ABI C using caller ABI Rust + //~| NOTE inside `call_rust_fn` } -const VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); +static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); //~^ WARN skipping const checks +//~| NOTE inside `VAL` fn main() {} diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr index dba00d72ef03..674a293d2815 100644 --- a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -1,29 +1,27 @@ warning: skipping const checks - --> $DIR/abi-mismatch.rs:9:5 + --> $DIR/abi-mismatch.rs:10:5 | LL | my_fn(); | ^^^^^^^ warning: skipping const checks - --> $DIR/abi-mismatch.rs:13:39 + --> $DIR/abi-mismatch.rs:17:40 | -LL | const VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: any use of this value will cause an error - --> $DIR/abi-mismatch.rs:9:5 +error[E0080]: could not evaluate static initializer + --> $DIR/abi-mismatch.rs:10:5 | LL | my_fn(); | ^^^^^^^ | | | calling a function with ABI C using caller ABI Rust - | inside `call_rust_fn` at $DIR/abi-mismatch.rs:9:5 - | inside `VAL` at $DIR/abi-mismatch.rs:13:17 + | inside `call_rust_fn` at $DIR/abi-mismatch.rs:10:5 ... -LL | const VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); - | -------------------------------------------------------------------------------------- - | - = note: `#[deny(const_err)]` on by default +LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); + | --------------------------------------------------------------------- inside `VAL` at $DIR/abi-mismatch.rs:17:18 error: aborting due to previous error; 2 warnings emitted +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/miri_unleashed/box.rs b/src/test/ui/consts/miri_unleashed/box.rs index 049727684d0e..1b18470eded4 100644 --- a/src/test/ui/consts/miri_unleashed/box.rs +++ b/src/test/ui/consts/miri_unleashed/box.rs @@ -1,6 +1,6 @@ // compile-flags: -Zunleash-the-miri-inside-of-you #![feature(const_mut_refs, box_syntax)] -#![deny(const_err)] +#![allow(const_err)] use std::mem::ManuallyDrop; diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static.rs b/src/test/ui/consts/miri_unleashed/const_refers_to_static.rs index edbf0e02d8de..11f4a30d1779 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static.rs +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static.rs @@ -1,39 +1,37 @@ +// build-fail // compile-flags: -Zunleash-the-miri-inside-of-you -#![warn(const_err)] +#![allow(const_err)] #![feature(const_raw_ptr_deref)] use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; -const REF_INTERIOR_MUT: &usize = { //~ ERROR undefined behavior to use this value - static FOO: AtomicUsize = AtomicUsize::new(0); - unsafe { &*(&FOO as *const _ as *const usize) } - //~^ WARN skipping const checks -}; +// These tests only cause an error when *using* the const. const MUTATE_INTERIOR_MUT: usize = { static FOO: AtomicUsize = AtomicUsize::new(0); - FOO.fetch_add(1, Ordering::Relaxed) //~ WARN any use of this value will cause an error + FOO.fetch_add(1, Ordering::Relaxed) //~^ WARN skipping const checks //~| WARN skipping const checks }; const READ_INTERIOR_MUT: usize = { static FOO: AtomicUsize = AtomicUsize::new(0); - unsafe { *(&FOO as *const _ as *const usize) } //~ WARN any use of this value will cause an err + unsafe { *(&FOO as *const _ as *const usize) } //~^ WARN skipping const checks }; static mut MUTABLE: u32 = 0; -const READ_MUT: u32 = unsafe { MUTABLE }; //~ WARN any use of this value will cause an error +const READ_MUT: u32 = unsafe { MUTABLE }; //~^ WARN skipping const checks //~| WARN skipping const checks -// ok some day perhaps -const READ_IMMUT: &usize = { //~ ERROR it is undefined behavior to use this value - static FOO: usize = 0; - &FOO - //~^ WARN skipping const checks -}; -fn main() {} +fn main() { + MUTATE_INTERIOR_MUT; + //~^ ERROR: erroneous constant used + READ_INTERIOR_MUT; + //~^ ERROR: erroneous constant used + READ_MUT; + //~^ ERROR: erroneous constant used +} diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr index 92e782612b25..788762808f13 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -1,106 +1,51 @@ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:11:18 - | -LL | unsafe { &*(&FOO as *const _ as *const usize) } - | ^^^ - -warning: skipping const checks - --> $DIR/const_refers_to_static.rs:17:5 + --> $DIR/const_refers_to_static.rs:14:5 | LL | FOO.fetch_add(1, Ordering::Relaxed) | ^^^ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:17:5 + --> $DIR/const_refers_to_static.rs:14:5 | LL | FOO.fetch_add(1, Ordering::Relaxed) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:24:17 + --> $DIR/const_refers_to_static.rs:21:17 | LL | unsafe { *(&FOO as *const _ as *const usize) } | ^^^ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:29:32 + --> $DIR/const_refers_to_static.rs:26:32 | LL | const READ_MUT: u32 = unsafe { MUTABLE }; | ^^^^^^^ warning: skipping const checks - --> $DIR/const_refers_to_static.rs:29:32 + --> $DIR/const_refers_to_static.rs:26:32 | LL | const READ_MUT: u32 = unsafe { MUTABLE }; | ^^^^^^^ -warning: skipping const checks - --> $DIR/const_refers_to_static.rs:36:6 +error[E0080]: erroneous constant used + --> $DIR/const_refers_to_static.rs:31:5 | -LL | &FOO - | ^^^ +LL | MUTATE_INTERIOR_MUT; + | ^^^^^^^^^^^^^^^^^^^ referenced constant has errors -error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static.rs:9:1 +error[E0080]: erroneous constant used + --> $DIR/const_refers_to_static.rs:33:5 | -LL | / const REF_INTERIOR_MUT: &usize = { -LL | | static FOO: AtomicUsize = AtomicUsize::new(0); -LL | | unsafe { &*(&FOO as *const _ as *const usize) } -LL | | -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. +LL | READ_INTERIOR_MUT; + | ^^^^^^^^^^^^^^^^^ referenced constant has errors -warning: any use of this value will cause an error - --> $DIR/const_refers_to_static.rs:17:5 - | -LL | / const MUTATE_INTERIOR_MUT: usize = { -LL | | static FOO: AtomicUsize = AtomicUsize::new(0); -LL | | FOO.fetch_add(1, Ordering::Relaxed) - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `std::sync::atomic::AtomicUsize::fetch_add` -LL | | -LL | | -LL | | }; - | |__- - | -note: the lint level is defined here - --> $DIR/const_refers_to_static.rs:2:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - -warning: any use of this value will cause an error - --> $DIR/const_refers_to_static.rs:24:14 - | -LL | / const READ_INTERIOR_MUT: usize = { -LL | | static FOO: AtomicUsize = AtomicUsize::new(0); -LL | | unsafe { *(&FOO as *const _ as *const usize) } - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static -LL | | -LL | | }; - | |__- - -warning: any use of this value will cause an error - --> $DIR/const_refers_to_static.rs:29:32 - | -LL | const READ_MUT: u32 = unsafe { MUTABLE }; - | -------------------------------^^^^^^^--- - | | - | constant accesses static - -error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static.rs:34:1 - | -LL | / const READ_IMMUT: &usize = { -LL | | static FOO: usize = 0; -LL | | &FOO -LL | | -LL | | }; - | |__^ type validation failed: encountered a reference pointing to a static variable +error[E0080]: erroneous constant used + --> $DIR/const_refers_to_static.rs:35:5 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. +LL | READ_MUT; + | ^^^^^^^^ referenced constant has errors -error: aborting due to 2 previous errors; 10 warnings emitted +error: aborting due to 3 previous errors; 5 warnings emitted For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static2.rs b/src/test/ui/consts/miri_unleashed/const_refers_to_static2.rs new file mode 100644 index 000000000000..2704f2a7d73c --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static2.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +#![allow(const_err)] + +#![feature(const_raw_ptr_deref)] + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +// These tests cause immediate error when *defining* the const. + +const REF_INTERIOR_MUT: &usize = { //~ ERROR undefined behavior to use this value + static FOO: AtomicUsize = AtomicUsize::new(0); + unsafe { &*(&FOO as *const _ as *const usize) } + //~^ WARN skipping const checks +}; + +// ok some day perhaps +const READ_IMMUT: &usize = { //~ ERROR it is undefined behavior to use this value + static FOO: usize = 0; + &FOO + //~^ WARN skipping const checks +}; + +fn main() {} diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static2.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static2.stderr new file mode 100644 index 000000000000..2a233d63efef --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static2.stderr @@ -0,0 +1,39 @@ +warning: skipping const checks + --> $DIR/const_refers_to_static2.rs:13:18 + | +LL | unsafe { &*(&FOO as *const _ as *const usize) } + | ^^^ + +warning: skipping const checks + --> $DIR/const_refers_to_static2.rs:20:6 + | +LL | &FOO + | ^^^ + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static2.rs:11:1 + | +LL | / const REF_INTERIOR_MUT: &usize = { +LL | | static FOO: AtomicUsize = AtomicUsize::new(0); +LL | | unsafe { &*(&FOO as *const _ as *const usize) } +LL | | +LL | | }; + | |__^ type validation failed: encountered a reference pointing to a static variable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/const_refers_to_static2.rs:18:1 + | +LL | / const READ_IMMUT: &usize = { +LL | | static FOO: usize = 0; +LL | | &FOO +LL | | +LL | | }; + | |__^ type validation failed: encountered a reference pointing to a static variable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to 2 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/miri_unleashed/drop.rs b/src/test/ui/consts/miri_unleashed/drop.rs index 2f39148d6972..3b9208dd1260 100644 --- a/src/test/ui/consts/miri_unleashed/drop.rs +++ b/src/test/ui/consts/miri_unleashed/drop.rs @@ -1,6 +1,6 @@ // compile-flags: -Zunleash-the-miri-inside-of-you // error-pattern: calling non-const function ` as std::ops::Drop>::drop` -#![deny(const_err)] +#![allow(const_err)] use std::mem::ManuallyDrop; diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.rs b/src/test/ui/consts/miri_unleashed/mutable_const.rs index 972f59549ea7..5cc8808be5dc 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_const.rs @@ -1,8 +1,13 @@ // compile-flags: -Zunleash-the-miri-inside-of-you +// normalize-stderr-test "alloc[0-9]+" -> "allocN" #![feature(const_raw_ptr_deref)] #![feature(const_mut_refs)] -#![deny(const_err)] +#![deny(const_err)] // The `allow` variant is tested by `mutable_const2`. +//~^ NOTE lint level +// Here we check that even though `MUTABLE_BEHIND_RAW` is created from a mutable +// allocation, we intern that allocation as *immutable* and reject writes to it. +// We avoid the `delay_span_bug` ICE by having compilation fail via the `deny` above. use std::cell::UnsafeCell; @@ -10,10 +15,13 @@ use std::cell::UnsafeCell; const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; //~^ WARN: skipping const checks -const MUTATING_BEHIND_RAW: () = { +const MUTATING_BEHIND_RAW: () = { //~ NOTE // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time. unsafe { *MUTABLE_BEHIND_RAW = 99 //~ ERROR any use of this value will cause an error + //~^ NOTE: which is read-only + // FIXME would be good to match more of the error message here, but looks like we + // normalize *after* checking the annoations here. } }; diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.stderr b/src/test/ui/consts/miri_unleashed/mutable_const.stderr index 54a9eda21466..34993247fca8 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_const.stderr @@ -1,25 +1,26 @@ warning: skipping const checks - --> $DIR/mutable_const.rs:10:38 + --> $DIR/mutable_const.rs:15:38 | LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; | ^^^^^^^^^^^^^^^^^^^^ error: any use of this value will cause an error - --> $DIR/mutable_const.rs:16:9 + --> $DIR/mutable_const.rs:21:9 | LL | / const MUTATING_BEHIND_RAW: () = { LL | | // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time. LL | | unsafe { LL | | *MUTABLE_BEHIND_RAW = 99 - | | ^^^^^^^^^^^^^^^^^^^^^^^^ writing to alloc2 which is read-only + | | ^^^^^^^^^^^^^^^^^^^^^^^^ writing to allocN which is read-only +... | LL | | } LL | | }; | |__- | note: the lint level is defined here - --> $DIR/mutable_const.rs:5:9 + --> $DIR/mutable_const.rs:6:9 | -LL | #![deny(const_err)] +LL | #![deny(const_err)] // The `allow` variant is tested by `mutable_const2`. | ^^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/consts/miri_unleashed/mutable_const2.rs b/src/test/ui/consts/miri_unleashed/mutable_const2.rs index 97af1f2f993c..c2c7fb18e2a6 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const2.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_const2.rs @@ -3,11 +3,11 @@ // rustc-env:RUST_BACKTRACE=0 // normalize-stderr-test "note: rustc 1.* running on .*" -> "note: rustc VERSION running on TARGET" // normalize-stderr-test "note: compiler flags: .*" -> "note: compiler flags: FLAGS" -// normalize-stderr-test "interpret/intern.rs:[0-9]*:[0-9]*" -> "interpret/intern.rs:LL:CC" +// normalize-stderr-test "interpret/intern.rs:[0-9]+:[0-9]+" -> "interpret/intern.rs:LL:CC" #![feature(const_raw_ptr_deref)] #![feature(const_mut_refs)] -#![deny(const_err)] +#![allow(const_err)] use std::cell::UnsafeCell; diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs b/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs index 635cad81c979..9d8d5f513c76 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs +++ b/src/test/ui/consts/miri_unleashed/mutable_references_ice.rs @@ -3,7 +3,7 @@ // rustc-env:RUST_BACKTRACE=0 // normalize-stderr-test "note: rustc 1.* running on .*" -> "note: rustc VERSION running on TARGET" // normalize-stderr-test "note: compiler flags: .*" -> "note: compiler flags: FLAGS" -// normalize-stderr-test "interpret/intern.rs:[0-9]*:[0-9]*" -> "interpret/intern.rs:LL:CC" +// normalize-stderr-test "interpret/intern.rs:[0-9]+:[0-9]+" -> "interpret/intern.rs:LL:CC" #![allow(const_err)] diff --git a/src/test/ui/consts/miri_unleashed/mutating_global.rs b/src/test/ui/consts/miri_unleashed/mutating_global.rs index acc6fb026cd6..902fe0aa1e7e 100644 --- a/src/test/ui/consts/miri_unleashed/mutating_global.rs +++ b/src/test/ui/consts/miri_unleashed/mutating_global.rs @@ -1,14 +1,15 @@ // compile-flags: -Zunleash-the-miri-inside-of-you +#![allow(const_err)] // Make sure we cannot mutate globals. static mut GLOBAL: i32 = 0; -const MUTATING_GLOBAL: () = { +static MUTATING_GLOBAL: () = { unsafe { - GLOBAL = 99 //~ ERROR any use of this value will cause an error - //~^ WARN skipping const checks - //~| WARN skipping const checks + GLOBAL = 99 + //~^ ERROR could not evaluate static initializer + //~| NOTE modifying a static's initial value } }; diff --git a/src/test/ui/consts/miri_unleashed/mutating_global.stderr b/src/test/ui/consts/miri_unleashed/mutating_global.stderr index dd449d5da35e..ba9dd56190ac 100644 --- a/src/test/ui/consts/miri_unleashed/mutating_global.stderr +++ b/src/test/ui/consts/miri_unleashed/mutating_global.stderr @@ -1,29 +1,9 @@ -warning: skipping const checks - --> $DIR/mutating_global.rs:9:9 +error[E0080]: could not evaluate static initializer + --> $DIR/mutating_global.rs:10:9 | LL | GLOBAL = 99 - | ^^^^^^ + | ^^^^^^^^^^^ modifying a static's initial value from another static's initializer -warning: skipping const checks - --> $DIR/mutating_global.rs:9:9 - | -LL | GLOBAL = 99 - | ^^^^^^ - -error: any use of this value will cause an error - --> $DIR/mutating_global.rs:9:9 - | -LL | / const MUTATING_GLOBAL: () = { -LL | | unsafe { -LL | | GLOBAL = 99 - | | ^^^^^^^^^^^ modifying a static's initial value from another static's initializer -LL | | -LL | | -LL | | } -LL | | }; - | |__- - | - = note: `#[deny(const_err)]` on by default - -error: aborting due to previous error; 2 warnings emitted +error: aborting due to previous error +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.rs b/src/test/ui/consts/miri_unleashed/non_const_fn.rs index cfb57d21ceec..b401884139d9 100644 --- a/src/test/ui/consts/miri_unleashed/non_const_fn.rs +++ b/src/test/ui/consts/miri_unleashed/non_const_fn.rs @@ -1,17 +1,13 @@ -// build-fail // compile-flags: -Zunleash-the-miri-inside-of-you -#![warn(const_err)] +#![allow(const_err)] // A test demonstrating that we prevent calling non-const fn during CTFE. fn foo() {} -const C: () = foo(); //~ WARN: skipping const checks -//~^ WARN any use of this value will cause an error +static C: () = foo(); //~ WARN: skipping const checks +//~^ ERROR could not evaluate static initializer +//~| NOTE calling non-const function `foo` -fn main() { - println!("{:?}", C); - //~^ ERROR: evaluation of constant expression failed - //~| WARN: erroneous constant used [const_err] -} +fn main() {} diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr index cc31c41164fe..d20cd6d6f0b9 100644 --- a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr +++ b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr @@ -1,35 +1,15 @@ warning: skipping const checks - --> $DIR/non_const_fn.rs:10:15 + --> $DIR/non_const_fn.rs:9:16 | -LL | const C: () = foo(); - | ^^^^^ +LL | static C: () = foo(); + | ^^^^^ -warning: any use of this value will cause an error - --> $DIR/non_const_fn.rs:10:15 +error[E0080]: could not evaluate static initializer + --> $DIR/non_const_fn.rs:9:16 | -LL | const C: () = foo(); - | --------------^^^^^- - | | - | calling non-const function `foo` - | -note: the lint level is defined here - --> $DIR/non_const_fn.rs:4:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - -error[E0080]: evaluation of constant expression failed - --> $DIR/non_const_fn.rs:14:22 - | -LL | println!("{:?}", C); - | ^ referenced constant has errors - -warning: erroneous constant used - --> $DIR/non_const_fn.rs:14:22 - | -LL | println!("{:?}", C); - | ^ referenced constant has errors +LL | static C: () = foo(); + | ^^^^^ calling non-const function `foo` -error: aborting due to previous error; 3 warnings emitted +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/foreign-fn-return-lifetime.stderr b/src/test/ui/foreign-fn-return-lifetime.stderr index 575da18f2404..feecb6d80e77 100644 --- a/src/test/ui/foreign-fn-return-lifetime.stderr +++ b/src/test/ui/foreign-fn-return-lifetime.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/foreign-fn-return-lifetime.rs:5:19 | LL | pub fn f() -> &u8; - | ^ help: consider giving it a 'static lifetime: `&'static` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | pub fn f() -> &'static u8; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr index 9f410c0dbbbd..1106a0678228 100644 --- a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr +++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr @@ -5,16 +5,33 @@ LL | fn should_error() where T : Into<&u32> {} | ^ explicit lifetime name needed here error[E0106]: missing lifetime specifier - --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:19 + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:21 | LL | fn foo<'b, L: X<&'b Nested>>(); - | ^^^^^^^^^^^^^^^^ expected lifetime parameter + | ^ expected named lifetime parameter + | +note: these named lifetimes are available to use + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:9 + | +LL | trait X<'a, K: 'a> { + | ^^ +LL | fn foo<'b, L: X<&'b Nested>>(); + | ^^ +help: consider using one of the available lifetimes here + | +LL | fn foo<'b, L: X<'lifetime, &'b Nested>>(); + | ^^^^^^^^^^ error[E0106]: missing lifetime specifier - --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:15 + --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:17 | LL | fn bar<'b, L: X<&'b Nested>>(){} - | ^^^^^^^^^^^^^^^^^^ expected lifetime parameter + | ^ expected named lifetime parameter + | +help: consider using the `'b` lifetime + | +LL | fn bar<'b, L: X<'b, &'b Nested>>(){} + | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-13497.stderr b/src/test/ui/issues/issue-13497.stderr index b72f0277052b..a231f73d0672 100644 --- a/src/test/ui/issues/issue-13497.stderr +++ b/src/test/ui/issues/issue-13497.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-13497.rs:2:5 | LL | &str - | ^ help: consider giving it a 'static lifetime: `&'static` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | &'static str + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-26638.stderr b/src/test/ui/issues/issue-26638.stderr index 1d8fbdc63c5e..3df58d66d1f8 100644 --- a/src/test/ui/issues/issue-26638.stderr +++ b/src/test/ui/issues/issue-26638.stderr @@ -14,17 +14,25 @@ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:4:40 | LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } - | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments +help: consider using the `'static` lifetime + | +LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() } + | ^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/issue-26638.rs:7:22 | LL | fn parse_type_3() -> &str { unimplemented!() } - | ^ help: consider giving it a 'static lifetime: `&'static` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | fn parse_type_3() -> &'static str { unimplemented!() } + | ^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr index 461c1832e9af..5809b5bd661e 100644 --- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr +++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr @@ -2,9 +2,13 @@ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:2:11 | LL | fn f() -> &isize { - | ^ help: consider giving it a 'static lifetime: `&'static` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | fn f() -> &'static isize { + | ^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33 @@ -34,25 +38,37 @@ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20 | LL | fn i(_x: isize) -> &isize { - | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments +help: consider using the `'static` lifetime + | +LL | fn i(_x: isize) -> &'static isize { + | ^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:34:24 | LL | fn j(_x: StaticStr) -> &isize { - | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments +help: consider using the `'static` lifetime + | +LL | fn j(_x: StaticStr) -> &'static isize { + | ^^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:40:49 | LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize { - | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static` + | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments +help: consider using the `'a` lifetime + | +LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &'a isize { + | ^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/specialization/defaultimpl/validation.stderr b/src/test/ui/specialization/defaultimpl/validation.stderr index 9bf59bd4f636..254eaf51a646 100644 --- a/src/test/ui/specialization/defaultimpl/validation.stderr +++ b/src/test/ui/specialization/defaultimpl/validation.stderr @@ -25,13 +25,13 @@ LL | default impl !Send for Z {} | default because of this error[E0750]: negative impls cannot be default impls - --> $DIR/validation.rs:10:14 + --> $DIR/validation.rs:10:1 | LL | default impl !Send for Z {} | ^^^^^^^ ^ error[E0750]: negative impls cannot be default impls - --> $DIR/validation.rs:14:14 + --> $DIR/validation.rs:14:1 | LL | default impl !Tr for S {} | ^^^^^^^ ^ diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.rs b/src/test/ui/suggestions/missing-lifetime-specifier.rs new file mode 100644 index 000000000000..b09c1879d701 --- /dev/null +++ b/src/test/ui/suggestions/missing-lifetime-specifier.rs @@ -0,0 +1,65 @@ +#![allow(bare_trait_objects)] +use std::collections::HashMap; +use std::cell::RefCell; + +pub union Foo<'t, 'k> { + i: &'t i64, + f: &'k f64, +} +trait Bar<'t, 'k> {} + +pub union Qux<'t, 'k, I> { + i: &'t I, + f: &'k I, +} +trait Tar<'t, 'k, I> {} + +thread_local! { + static a: RefCell>>> = RefCell::new(HashMap::new()); + //~^ ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier +} +thread_local! { + static b: RefCell>>> = RefCell::new(HashMap::new()); + //~^ ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier + //~| ERROR the lifetime bound for this object type cannot be deduced from context + //~| ERROR the lifetime bound for this object type cannot be deduced from context +} +thread_local! { + static c: RefCell>>>> = RefCell::new(HashMap::new()); + //~^ ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier +} +thread_local! { + static d: RefCell>>>> = RefCell::new(HashMap::new()); + //~^ ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier + //~| ERROR the lifetime bound for this object type cannot be deduced from context + //~| ERROR the lifetime bound for this object type cannot be deduced from context +} + +thread_local! { + static e: RefCell>>>> = RefCell::new(HashMap::new()); + //~^ ERROR wrong number of lifetime arguments: expected 2, found 1 + //~| ERROR wrong number of lifetime arguments: expected 2, found 1 + //~| ERROR wrong number of lifetime arguments: expected 2, found 1 + //~| ERROR wrong number of lifetime arguments: expected 2, found 1 +} +thread_local! { + static f: RefCell>>>> = RefCell::new(HashMap::new()); + //~^ ERROR the lifetime bound for this object type cannot be deduced from context + //~| ERROR the lifetime bound for this object type cannot be deduced from context + //~| ERROR wrong number of lifetime arguments: expected 2, found 1 + //~| ERROR wrong number of lifetime arguments: expected 2, found 1 + //~| ERROR wrong number of lifetime arguments: expected 2, found 1 + //~| ERROR wrong number of lifetime arguments: expected 2, found 1 + //~| ERROR missing lifetime specifier + //~| ERROR missing lifetime specifier +} + +fn main() {} diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.stderr b/src/test/ui/suggestions/missing-lifetime-specifier.stderr new file mode 100644 index 000000000000..f5ff54cc916c --- /dev/null +++ b/src/test/ui/suggestions/missing-lifetime-specifier.stderr @@ -0,0 +1,256 @@ +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:18:44 + | +LL | static a: RefCell>>> = RefCell::new(HashMap::new()); + | ^^^ expected 2 lifetime parameters + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static a: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:18:44 + | +LL | static a: RefCell>>> = RefCell::new(HashMap::new()); + | ^^^ expected 2 lifetime parameters + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static a: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:23:44 + | +LL | static b: RefCell>>> = RefCell::new(HashMap::new()); + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static b: RefCell>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:23:45 + | +LL | static b: RefCell>>> = RefCell::new(HashMap::new()); + | ^^^ expected 2 lifetime parameters + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static b: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:23:44 + | +LL | static b: RefCell>>> = RefCell::new(HashMap::new()); + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static b: RefCell>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:23:45 + | +LL | static b: RefCell>>> = RefCell::new(HashMap::new()); + | ^^^ expected 2 lifetime parameters + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static b: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:32:48 + | +LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected 2 lifetime parameters + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ + +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:32:48 + | +LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected 2 lifetime parameters + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:37:44 + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:37:49 + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected 2 lifetime parameters + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:37:44 + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-specifier.rs:37:49 + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected 2 lifetime parameters + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:54:44 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-specifier.rs:54:44 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + +error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound + --> $DIR/missing-lifetime-specifier.rs:23:45 + | +LL | static b: RefCell>>> = RefCell::new(HashMap::new()); + | ^^^ + +error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound + --> $DIR/missing-lifetime-specifier.rs:23:45 + | +LL | static b: RefCell>>> = RefCell::new(HashMap::new()); + | ^^^ + +error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound + --> $DIR/missing-lifetime-specifier.rs:37:45 + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + +error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound + --> $DIR/missing-lifetime-specifier.rs:37:45 + | +LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^ + +error[E0107]: wrong number of lifetime arguments: expected 2, found 1 + --> $DIR/missing-lifetime-specifier.rs:47:44 + | +LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments + +error[E0107]: wrong number of lifetime arguments: expected 2, found 1 + --> $DIR/missing-lifetime-specifier.rs:47:44 + | +LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments + +error[E0107]: wrong number of lifetime arguments: expected 2, found 1 + --> $DIR/missing-lifetime-specifier.rs:47:44 + | +LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments + +error[E0107]: wrong number of lifetime arguments: expected 2, found 1 + --> $DIR/missing-lifetime-specifier.rs:47:44 + | +LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments + +error[E0107]: wrong number of lifetime arguments: expected 2, found 1 + --> $DIR/missing-lifetime-specifier.rs:54:45 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments + +error[E0107]: wrong number of lifetime arguments: expected 2, found 1 + --> $DIR/missing-lifetime-specifier.rs:54:45 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments + +error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound + --> $DIR/missing-lifetime-specifier.rs:54:45 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ + +error[E0107]: wrong number of lifetime arguments: expected 2, found 1 + --> $DIR/missing-lifetime-specifier.rs:54:45 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments + +error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound + --> $DIR/missing-lifetime-specifier.rs:54:45 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ + +error[E0107]: wrong number of lifetime arguments: expected 2, found 1 + --> $DIR/missing-lifetime-specifier.rs:54:45 + | +LL | static f: RefCell>>>> = RefCell::new(HashMap::new()); + | ^^^^^^^^^^^^^^^^^ expected 2 lifetime arguments + +error: aborting due to 28 previous errors + +Some errors have detailed explanations: E0106, E0107. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr index ce3b1748da43..2a237d61f50f 100644 --- a/src/test/ui/suggestions/return-without-lifetime.stderr +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -2,23 +2,36 @@ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:2:16 | LL | struct Foo<'a>(&usize); - | ^ help: consider using the named lifetime: `&'a` + | ^ expected named lifetime parameter + | +help: consider using the `'a` lifetime + | +LL | struct Foo<'a>(&'a usize); + | ^^^ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:5:34 | LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } - | --------- ^ help: consider using the named lifetime: `&'a` + | --------- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from +help: consider using the `'a` lifetime + | +LL | fn func1<'a>(_arg: &'a Thing) -> &'a () { unimplemented!() } + | ^^^ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:7:35 | LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } - | ---------- ^ help: consider using the named lifetime: `&'a` + | ---------- ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from +help: consider using the `'a` lifetime + | +LL | fn func2<'a>(_arg: &Thing<'a>) -> &'a () { unimplemented!() } + | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/traits/negative-impls/negative-default-impls.stderr b/src/test/ui/traits/negative-impls/negative-default-impls.stderr index d2423d01a9af..a70bbe6b948d 100644 --- a/src/test/ui/traits/negative-impls/negative-default-impls.stderr +++ b/src/test/ui/traits/negative-impls/negative-default-impls.stderr @@ -1,5 +1,5 @@ error[E0750]: negative impls cannot be default impls - --> $DIR/negative-default-impls.rs:8:14 + --> $DIR/negative-default-impls.rs:8:1 | LL | default impl !MyTrait for u32 {} | ^^^^^^^ ^ diff --git a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr index 7af9c57a8300..b824d160d716 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr @@ -2,7 +2,7 @@ error[E0658]: parenthetical notation is only stable when used with `Fn`-family t --> $DIR/unboxed-closure-feature-gate.rs:13:20 | LL | let x: Box; - | ^^^ + | ^^^^^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr index 9a3bdd2bd5ea..9da36906d554 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr @@ -2,7 +2,7 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:3:17 | LL | fn bar1(x: &dyn Fn<(), Output=()>) { - | ^^ help: use parenthetical notation instead: `Fn() -> ()` + | ^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable @@ -11,7 +11,7 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:7:28 | LL | fn bar2(x: &T) where T: Fn<()> { - | ^^ help: use parenthetical notation instead: `Fn() -> ()` + | ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr index b92f054498b6..e9d51983a7a4 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-region.stderr @@ -2,7 +2,7 @@ error[E0107]: wrong number of lifetime arguments: expected 1, found 0 --> $DIR/unboxed-closure-sugar-region.rs:30:51 | LL | fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) { - | ^^^ expected 1 lifetime argument + | ^^^^^^^^^^ expected 1 lifetime argument error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr index f482098cbffc..f42ac38d370d 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr @@ -2,7 +2,7 @@ error[E0107]: wrong number of type arguments: expected 3, found 1 --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16 | LL | fn foo(_: &dyn Three()) - | ^^^^^ expected 3 type arguments + | ^^^^^^^ expected 3 type arguments error[E0220]: associated type `Output` not found for `Three<(), [type error], [type error]>` --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16 diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr index ada4551baeff..594cdd245b3e 100644 --- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr +++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr @@ -14,15 +14,24 @@ error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:2:17 | LL | struct Baz<'a>(&'_ &'a u8); - | ^^ help: consider using the named lifetime: `'a` + | ^^ expected named lifetime parameter + | +help: consider using the `'a` lifetime + | +LL | struct Baz<'a>(&'a &'a u8); + | ^^ error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:10:33 | LL | fn meh() -> Box Meh<'_>> - | ^^ help: consider giving it a 'static lifetime: `'static` + | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | fn meh() -> Box Meh<'static>> + | ^^^^^^^ error[E0106]: missing lifetime specifier --> $DIR/underscore-lifetime-binders.rs:16:35 diff --git a/src/test/ui/unspecified-self-in-trait-ref.stderr b/src/test/ui/unspecified-self-in-trait-ref.stderr index e057a7842b2a..9310b3d7ede0 100644 --- a/src/test/ui/unspecified-self-in-trait-ref.stderr +++ b/src/test/ui/unspecified-self-in-trait-ref.stderr @@ -31,7 +31,7 @@ LL | | } | |_- type parameter `A` must be specified for this ... LL | let e = Bar::::lol(); - | ^^^ missing reference to `A` + | ^^^^^^^^^^^^^^^^^ missing reference to `A` | = note: because of the default `Self` reference, type parameters must be specified on object types diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 028483b7d95b..3a8a5491255a 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -831,12 +831,28 @@ fn extract_gdb_version(full_version_line: &str) -> Option { // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both // of the ? sections being optional - // We will parse up to 3 digits for minor and patch, ignoring the date - // We limit major to 1 digit, otherwise, on openSUSE, we parse the openSUSE version + // We will parse up to 3 digits for each component, ignoring the date + + // We skip text in parentheses. This avoids accidentally parsing + // the openSUSE version, which looks like: + // GNU gdb (GDB; openSUSE Leap 15.0) 8.1 + // This particular form is documented in the GNU coding standards: + // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion // don't start parsing in the middle of a number let mut prev_was_digit = false; + let mut in_parens = false; for (pos, c) in full_version_line.char_indices() { + if in_parens { + if c == ')' { + in_parens = false; + } + continue; + } else if c == '(' { + in_parens = true; + continue; + } + if prev_was_digit || !c.is_digit(10) { prev_was_digit = c.is_digit(10); continue; @@ -876,7 +892,7 @@ fn extract_gdb_version(full_version_line: &str) -> Option { None => (line, None), }; - if major.len() != 1 || minor.is_empty() { + if minor.is_empty() { continue; } diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 388ad75757f6..31c151d29e91 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -7,9 +7,9 @@ fn test_extract_gdb_version() { )*}}} test! { - 7000001: "GNU gdb (GDB) CentOS (7.0.1-45.el5.centos)", + 7000001: "GNU gdb (GDB) CentOS 7.0.1-45.el5.centos", - 7002000: "GNU gdb (GDB) Red Hat Enterprise Linux (7.2-90.el6)", + 7002000: "GNU gdb (GDB) Red Hat Enterprise Linux 7.2-90.el6", 7004000: "GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04", 7004001: "GNU gdb (GDB) 7.4.1-debian",