From 406852ae0d92e5dfda890fa75ac522963065f903 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Tue, 19 May 2020 20:00:29 -0400 Subject: [PATCH 01/14] Resolve overflow behavior for RangeFrom --- src/libcore/iter/range.rs | 10 +--------- src/libcore/ops/range.rs | 14 ++++++++++---- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index d74df82bddd9d..75cbda3466210 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -551,15 +551,7 @@ impl Iterator for ops::RangeFrom { #[inline] fn nth(&mut self, n: usize) -> Option { - // If we would jump over the maximum value, panic immediately. - // This is consistent with behavior before the Step redesign, - // even though it's inconsistent with n `next` calls. - // To get consistent behavior, change it to use `forward` instead. - // This change should go through FCP separately to the redesign, so is for now left as a - // FIXME: make this consistent - let plus_n = - Step::forward_checked(self.start.clone(), n).expect("overflow in RangeFrom::nth"); - // The final step should always be debug-checked. + let plus_n = Step::forward(self.start.clone(), n); self.start = Step::forward(plus_n.clone(), 1); Some(plus_n) } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index d4e6048579a56..d86f39c4550c8 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -151,10 +151,16 @@ impl> Range { /// /// The `RangeFrom` `start..` contains all values with `x >= start`. /// -/// *Note*: Currently, no overflow checking is done for the [`Iterator`] -/// implementation; if you use an integer range and the integer overflows, it -/// might panic in debug mode or create an endless loop in release mode. **This -/// overflow behavior might change in the future.** +/// *Note*: Overflow in the [`Iterator`] implementation (when the contained +/// data type reaches its numerical limit) is allowed to panic, wrap, or +/// saturate. This behavior is defined by the implementation of the [`Step`] +/// trait. For primitive integers, this follows the normal rules, and respects +/// the overflow checks profile (panic in debug, wrap in release). Note also +/// that overflow happens earlier than you might assume: the overflow happens +/// in the call to `next` that yields the maximum value, as the range must be +/// set to a state to yield the next value. +/// +/// [`Step`]: crate::iter::Step /// /// # Examples /// From a5734ca41748dfd62904c1b5a1ade7ecd0f9c11e Mon Sep 17 00:00:00 2001 From: mendess Date: Sat, 23 May 2020 14:08:53 +0100 Subject: [PATCH 02/14] Override Box::<[T]>::clone_from --- src/liballoc/boxed.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8ef6090c743a9..bbe68e4222a1f 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -1090,6 +1090,14 @@ impl Clone for Box<[T]> { fn clone(&self) -> Self { self.to_vec().into_boxed_slice() } + + fn clone_from(&mut self, other: &Self) { + if self.len() == other.len() { + self.clone_from_slice(&other); + } else { + *self = other.clone(); + } + } } #[stable(feature = "box_borrow", since = "1.1.0")] From 32eedadee1ed3273a318fa109c5261482e518578 Mon Sep 17 00:00:00 2001 From: mendess Date: Sat, 23 May 2020 16:51:02 +0100 Subject: [PATCH 03/14] Add tests --- src/liballoc/tests/boxed.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/liballoc/tests/boxed.rs b/src/liballoc/tests/boxed.rs index 66782ecbeb7f6..c0b8fa665615e 100644 --- a/src/liballoc/tests/boxed.rs +++ b/src/liballoc/tests/boxed.rs @@ -16,3 +16,39 @@ fn unitialized_zero_size_box() { NonNull::>::dangling().as_ptr(), ); } + +#[derive(Clone, PartialEq, Eq, Debug)] +struct Dummy { + _data: u8, +} + +#[test] +fn box_clone_and_clone_from_equivalence() { + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let clone = control.clone(); + let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); + copy.clone_from(&control); + assert_eq!(control, clone); + assert_eq!(control, copy); + } +} + +#[test] +fn box_clone_from_ptr_stability() { + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); + let copy_raw = copy.as_ptr() as usize; + copy.clone_from(&control); + assert_eq!(copy.as_ptr() as usize, copy_raw); + } + + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let mut copy = vec![Dummy { _data: 84 }; size + 1].into_boxed_slice(); + let copy_raw = copy.as_ptr() as usize; + copy.clone_from(&control); + assert_ne!(copy.as_ptr() as usize, copy_raw); + } +} From 3ed1e79cc40133b6cdb65955c7433cc483a89ca8 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 24 May 2020 02:04:49 +0100 Subject: [PATCH 04/14] Properly handle InlineAsmOperand::SymFn when collecting monomorphized items Fixes #72484 --- src/librustc_codegen_ssa/mir/block.rs | 3 +- src/librustc_mir/monomorphize/collector.rs | 11 +++++-- src/test/ui/asm/sym.rs | 38 ++++++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/asm/sym.rs diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index b487ed8dea8b6..2a6d1abba9e9d 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -908,13 +908,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::InlineAsmOperand::SymFn { ref value } => { let literal = self.monomorphize(&value.literal); if let ty::FnDef(def_id, substs) = literal.ty.kind { - let instance = ty::Instance::resolve( + let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs, ) - .unwrap() .unwrap(); InlineAsmOperandRef::SymFn { instance } } else { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 925b8d329668f..3b05ffa567f86 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -633,14 +633,21 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let ty = self.monomorphize(ty); visit_drop_use(self.tcx, ty, true, self.output); } + mir::TerminatorKind::InlineAsm { ref operands, .. } => { + for op in operands { + if let mir::InlineAsmOperand::SymFn { value } = op { + let fn_ty = self.monomorphize(value.literal.ty); + visit_fn_use(self.tcx, fn_ty, false, &mut self.output); + } + } + } mir::TerminatorKind::Goto { .. } | mir::TerminatorKind::SwitchInt { .. } | mir::TerminatorKind::Resume | mir::TerminatorKind::Abort | mir::TerminatorKind::Return | mir::TerminatorKind::Unreachable - | mir::TerminatorKind::Assert { .. } - | mir::TerminatorKind::InlineAsm { .. } => {} + | mir::TerminatorKind::Assert { .. } => {} mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Yield { .. } | mir::TerminatorKind::FalseEdges { .. } diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/sym.rs new file mode 100644 index 0000000000000..83a3672af49ce --- /dev/null +++ b/src/test/ui/asm/sym.rs @@ -0,0 +1,38 @@ +// no-system-llvm +// only-x86_64 +// run-pass + +#![feature(asm, track_caller)] + +extern "C" fn f1() -> i32 { + 111 +} + +// The compiler will generate a shim to hide the caller location parameter. +#[track_caller] +fn f2() -> i32 { + 222 +} + +macro_rules! call { + ($func:path) => {{ + let result: i32; + unsafe { + asm!("call {}", sym $func, + out("rax") result, + out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _, + out("r8") _, out("r9") _, out("r10") _, out("r11") _, + out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _, + out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _, + out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _, + out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _, + ); + } + result + }} +} + +fn main() { + assert_eq!(call!(f1), 111); + assert_eq!(call!(f2), 222); +} From 4e2696f54a449a366d2dae23bbc737947ec529ce Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 25 May 2020 15:53:41 -0400 Subject: [PATCH 05/14] Only capture tokens for items with outer attributes Suggested by @petrochenkov in https://github.com/rust-lang/rust/issues/43081#issuecomment-633389225 --- src/librustc_parse/parser/item.rs | 21 ++++++++++++++----- .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 4fe0453e9c87f..6f13d7994d17d 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -106,11 +106,20 @@ impl<'a> Parser<'a> { }); let mut unclosed_delims = vec![]; - let (mut item, tokens) = self.collect_tokens(|this| { + let has_attrs = !attrs.is_empty(); + let parse_item = |this: &mut Self| { let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name); unclosed_delims.append(&mut this.unclosed_delims); item - })?; + }; + + let (mut item, tokens) = if has_attrs { + let (item, tokens) = self.collect_tokens(parse_item)?; + (item, Some(tokens)) + } else { + (parse_item(self)?, None) + }; + self.unclosed_delims.append(&mut unclosed_delims); // Once we've parsed an item and recorded the tokens we got while @@ -127,9 +136,11 @@ impl<'a> Parser<'a> { // it (bad!). To work around this case for now we just avoid recording // `tokens` if we detect any inner attributes. This should help keep // expansion correct, but we should fix this bug one day! - if let Some(item) = &mut item { - if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { - item.tokens = Some(tokens); + if let Some(tokens) = tokens { + if let Some(item) = &mut item { + if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { + item.tokens = Some(tokens); + } } } Ok(item) diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index f60b6a00be129..c7b0fbeb0e39b 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 42e7e78998063..59ed68c2a773f 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} From 6faa82be42df548877315768184f8cfba111772e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 26 May 2020 11:04:34 +0100 Subject: [PATCH 06/14] Eagerly lower asm sub-expressions to HIR even if there is an error Fixes #72570 --- src/librustc_ast_lowering/expr.rs | 68 ++++++++++++++++--------------- src/test/ui/asm/issue-72570.rs | 7 ++++ 2 files changed, 42 insertions(+), 33 deletions(-) create mode 100644 src/test/ui/asm/issue-72570.rs diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index 5bcd111706f35..d8002bd3e19ae 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -974,20 +974,18 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> { - let asm_arch = if let Some(asm_arch) = self.sess.asm_arch { - asm_arch - } else { + if self.sess.asm_arch.is_none() { struct_span_err!(self.sess, sp, E0472, "asm! is unsupported on this target").emit(); - return hir::ExprKind::Err; }; - if asm.options.contains(InlineAsmOptions::ATT_SYNTAX) { - match asm_arch { - asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64 => {} - _ => self - .sess - .struct_span_err(sp, "the `att_syntax` option is only supported on x86") - .emit(), - } + if asm.options.contains(InlineAsmOptions::ATT_SYNTAX) + && !matches!( + self.sess.asm_arch, + Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64) + ) + { + self.sess + .struct_span_err(sp, "the `att_syntax` option is only supported on x86") + .emit(); } // Lower operands to HIR, filter_map skips any operands with invalid @@ -1001,10 +999,8 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(match reg { InlineAsmRegOrRegClass::Reg(s) => asm::InlineAsmRegOrRegClass::Reg( asm::InlineAsmReg::parse( - asm_arch, - |feature| { - self.sess.target_features.contains(&Symbol::intern(feature)) - }, + sess.asm_arch?, + |feature| sess.target_features.contains(&Symbol::intern(feature)), s, ) .map_err(|e| { @@ -1015,7 +1011,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), InlineAsmRegOrRegClass::RegClass(s) => { asm::InlineAsmRegOrRegClass::RegClass( - asm::InlineAsmRegClass::parse(asm_arch, s) + asm::InlineAsmRegClass::parse(sess.asm_arch?, s) .map_err(|e| { let msg = format!( "invalid register class `{}`: {}", @@ -1029,33 +1025,38 @@ impl<'hir> LoweringContext<'_, 'hir> { } }) }; - let op = match op { - InlineAsmOperand::In { reg, expr } => hir::InlineAsmOperand::In { - reg: lower_reg(*reg)?, + + // lower_reg is executed last because we need to lower all + // sub-expressions even if we throw them away later. + let op = match *op { + InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In { expr: self.lower_expr_mut(expr), + reg: lower_reg(reg)?, }, - InlineAsmOperand::Out { reg, late, expr } => hir::InlineAsmOperand::Out { - reg: lower_reg(*reg)?, - late: *late, + InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out { + late, expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)), + reg: lower_reg(reg)?, }, - InlineAsmOperand::InOut { reg, late, expr } => hir::InlineAsmOperand::InOut { - reg: lower_reg(*reg)?, - late: *late, - expr: self.lower_expr_mut(expr), - }, - InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { + InlineAsmOperand::InOut { reg, late, ref expr } => { + hir::InlineAsmOperand::InOut { + late, + expr: self.lower_expr_mut(expr), + reg: lower_reg(reg)?, + } + } + InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => { hir::InlineAsmOperand::SplitInOut { - reg: lower_reg(*reg)?, - late: *late, + late, in_expr: self.lower_expr_mut(in_expr), out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)), + reg: lower_reg(reg)?, } } - InlineAsmOperand::Const { expr } => { + InlineAsmOperand::Const { ref expr } => { hir::InlineAsmOperand::Const { expr: self.lower_expr_mut(expr) } } - InlineAsmOperand::Sym { expr } => { + InlineAsmOperand::Sym { ref expr } => { hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) } } }; @@ -1069,6 +1070,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } // Validate template modifiers against the register classes for the operands + let asm_arch = sess.asm_arch.unwrap(); for p in &asm.template { if let InlineAsmTemplatePiece::Placeholder { operand_idx, diff --git a/src/test/ui/asm/issue-72570.rs b/src/test/ui/asm/issue-72570.rs new file mode 100644 index 0000000000000..df508e9045819 --- /dev/null +++ b/src/test/ui/asm/issue-72570.rs @@ -0,0 +1,7 @@ +#![feature(asm)] + +fn main() { + unsafe { + asm!("", in("invalid") "".len()); + } +} From 7aa8946c7271f7077df537ed8e3e0b544252c466 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 26 May 2020 11:13:04 +0100 Subject: [PATCH 07/14] Update src/librustc_ast_lowering/expr.rs Co-authored-by: Oliver Scherer --- src/librustc_ast_lowering/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index d8002bd3e19ae..b7f2e9a9050df 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -976,7 +976,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> { if self.sess.asm_arch.is_none() { struct_span_err!(self.sess, sp, E0472, "asm! is unsupported on this target").emit(); - }; + } if asm.options.contains(InlineAsmOptions::ATT_SYNTAX) && !matches!( self.sess.asm_arch, From de53276aac3f9cb89fff5d9db3741e8c7852920a Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 26 May 2020 11:27:27 +0100 Subject: [PATCH 08/14] Fix test --- src/test/ui/asm/issue-72570.rs | 3 +++ src/test/ui/asm/issue-72570.stderr | 8 ++++++++ 2 files changed, 11 insertions(+) create mode 100644 src/test/ui/asm/issue-72570.stderr diff --git a/src/test/ui/asm/issue-72570.rs b/src/test/ui/asm/issue-72570.rs index df508e9045819..f34525a664ebe 100644 --- a/src/test/ui/asm/issue-72570.rs +++ b/src/test/ui/asm/issue-72570.rs @@ -1,7 +1,10 @@ +// only-x86_64 + #![feature(asm)] fn main() { unsafe { asm!("", in("invalid") "".len()); + //~^ ERROR: invalid register `invalid`: unknown register } } diff --git a/src/test/ui/asm/issue-72570.stderr b/src/test/ui/asm/issue-72570.stderr new file mode 100644 index 0000000000000..49013a23ced2d --- /dev/null +++ b/src/test/ui/asm/issue-72570.stderr @@ -0,0 +1,8 @@ +error: invalid register `invalid`: unknown register + --> $DIR/issue-72570.rs:7:18 + | +LL | asm!("", in("invalid") "".len()); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 804e9e546dbf246b671542a3813d38ee56e14a28 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 24 May 2020 16:03:11 +0100 Subject: [PATCH 09/14] mir: adjust conditional in recursion limit check This commit adjusts the condition used in the recursion limit check of the monomorphization collector, from `>` to `>=`. In #67552, the test case had infinite indirect recursion, repeating a handful of functions (from the perspective of the monomorphization collector): `rec` -> `identity` -> `Iterator::count` -> `Iterator::fold` -> `Iterator::next` -> `rec`. During this process, `resolve_associated_item` was invoked for `Iterator::fold` (during the construction of an `Instance`), and ICE'd due to substitutions needing inference. However, previous iterations of this recursion would have called this function for `Iterator::fold` - and did! - and succeeded in doing so (trivially checkable from debug logging, `()` is present where `_` is in the substs of the failing execution). The expected outcome of this test case would be a recursion limit error (which is present when the `identity` fn indirection is removed), and the recursion depth of `rec` is increasing (other functions finish collecting their neighbours and thus have their recursion depths reset). When the ICE occurs, the recursion depth of `rec` is 256 (which matches the recursion limit), which suggests perhaps that a different part of the compiler is using a `>=` comparison and returning a different result on this recursion rather than what it returned in every previous recursion, thus stopping the monomorphization collector from reporting an error on the next recursion, where `recursion_depth_of_rec > 256` would have been true. With grep and some educated guesses, we can determine that the recursion limit check at line 818 in `src/librustc_trait_selection/traits/project.rs` is the other check that is using a different comparison. Modifying either comparison to be `>` or `>=` respectively will fix the error, but changing the monomorphization collector produces the nicer error. Signed-off-by: David Wood --- src/librustc_mir/monomorphize/collector.rs | 2 +- .../ui/infinite/infinite-instantiation.stderr | 2 +- src/test/ui/issues/issue-67552.rs | 30 +++++++++++++++++++ src/test/ui/issues/issue-67552.stderr | 14 +++++++++ src/test/ui/issues/issue-8727.stderr | 2 +- ...-38591-non-regular-dropck-recursion.stderr | 2 +- src/test/ui/recursion/recursion.stderr | 2 +- 7 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issues/issue-67552.rs create mode 100644 src/test/ui/issues/issue-67552.stderr diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index c75e8414e8cca..1c5c13f843d7b 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -430,7 +430,7 @@ fn check_recursion_limit<'tcx>( // Code that needs to instantiate the same function recursively // more than the recursion limit is assumed to be causing an // infinite expansion. - if adjusted_recursion_depth > tcx.sess.recursion_limit() { + if adjusted_recursion_depth >= tcx.sess.recursion_limit() { let error = format!("reached the recursion limit while instantiating `{}`", instance); if let Some(def_id) = def_id.as_local() { let hir_id = tcx.hir().as_local_hir_id(def_id); diff --git a/src/test/ui/infinite/infinite-instantiation.stderr b/src/test/ui/infinite/infinite-instantiation.stderr index ae81c680a7b65..f1c04447986b0 100644 --- a/src/test/ui/infinite/infinite-instantiation.stderr +++ b/src/test/ui/infinite/infinite-instantiation.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/infinite-instantiation.rs:25:1 | LL | / fn function(counter: usize, t: T) { diff --git a/src/test/ui/issues/issue-67552.rs b/src/test/ui/issues/issue-67552.rs new file mode 100644 index 0000000000000..1400c6f97b605 --- /dev/null +++ b/src/test/ui/issues/issue-67552.rs @@ -0,0 +1,30 @@ +// build-fail + +fn main() { + rec(Empty); +} + +struct Empty; + +impl Iterator for Empty { + type Item = (); + fn next<'a>(&'a mut self) -> core::option::Option<()> { + None + } +} + +fn identity(x: T) -> T { + x +} + +fn rec(mut it: T) +//~^ ERROR reached the recursion limit while instantiating +where + T: Iterator, +{ + if () == () { + T::count(it); + } else { + rec(identity(&mut it)) + } +} diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr new file mode 100644 index 0000000000000..97ad76e207d04 --- /dev/null +++ b/src/test/ui/issues/issue-67552.stderr @@ -0,0 +1,14 @@ +error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>` + --> $DIR/issue-67552.rs:20:1 + | +LL | / fn rec(mut it: T) +LL | | +LL | | where +LL | | T: Iterator, +... | +LL | | } +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-8727.stderr b/src/test/ui/issues/issue-8727.stderr index ee0672c598d5c..8f581a358e1e9 100644 --- a/src/test/ui/issues/issue-8727.stderr +++ b/src/test/ui/issues/issue-8727.stderr @@ -9,7 +9,7 @@ LL | generic::>(); = note: `#[warn(unconditional_recursion)]` on by default = help: a `loop` may express intention better if this is on purpose -error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-8727.rs:6:1 | LL | / fn generic() { diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index de6df4cd0268c..d64149d1437fe 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::> - shim(Some(S))` +error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::> - shim(Some(S))` error: aborting due to previous error diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr index 1a65b0e84f6a3..ded8b3f87db62 100644 --- a/src/test/ui/recursion/recursion.stderr +++ b/src/test/ui/recursion/recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/recursion.rs:15:1 | LL | / fn test (n:isize, i:isize, first:T, second:T) ->isize { From a54ed872cb79529195f4b02910be823a75f3da22 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 26 May 2020 19:48:08 +0100 Subject: [PATCH 10/14] standardize limit comparisons with `Limit` type This commit introduces a `Limit` type which is used to ensure that all comparisons against limits within the compiler are consistent (which can result in ICEs if they aren't). Signed-off-by: David Wood --- src/librustc_error_codes/error_codes/E0055.md | 2 +- src/librustc_expand/base.rs | 4 +- src/librustc_expand/expand.rs | 7 +-- src/librustc_middle/middle/limits.rs | 8 +-- src/librustc_middle/ty/layout.rs | 3 +- src/librustc_mir/const_eval/machine.rs | 5 +- src/librustc_mir/interpret/eval_context.rs | 2 +- src/librustc_mir/monomorphize/collector.rs | 4 +- src/librustc_session/session.rs | 54 ++++++++++++++++--- .../traits/project.rs | 9 ++-- .../traits/query/normalize.rs | 4 +- src/librustc_trait_selection/traits/select.rs | 2 +- src/librustc_traits/dropck_outlives.rs | 2 +- src/librustc_ty/needs_drop.rs | 5 +- src/librustc_typeck/check/autoderef.rs | 2 +- .../ui/did_you_mean/recursion_limit.stderr | 3 +- .../did_you_mean/recursion_limit_deref.stderr | 2 +- .../dropck_no_diverge_on_nonregular_1.stderr | 4 +- .../dropck_no_diverge_on_nonregular_2.stderr | 4 +- .../dropck_no_diverge_on_nonregular_3.stderr | 6 +-- src/test/ui/error-codes/E0055.rs | 2 +- src/test/ui/error-codes/E0055.stderr | 2 +- src/test/ui/error-codes/E0275.stderr | 3 +- .../ui/infinite/infinite-instantiation.stderr | 2 +- src/test/ui/issues/issue-18400.stderr | 1 + src/test/ui/issues/issue-20413.stderr | 6 ++- src/test/ui/issues/issue-23122-2.stderr | 8 +-- src/test/ui/issues/issue-38940.rs | 2 +- src/test/ui/issues/issue-38940.stderr | 2 +- src/test/ui/issues/issue-67552.stderr | 2 +- src/test/ui/issues/issue-8727.stderr | 2 +- ...-38591-non-regular-dropck-recursion.stderr | 2 +- src/test/ui/recursion/recursion.stderr | 2 +- 33 files changed, 108 insertions(+), 60 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0055.md b/src/librustc_error_codes/error_codes/E0055.md index d5b863081a616..223ba40002986 100644 --- a/src/librustc_error_codes/error_codes/E0055.md +++ b/src/librustc_error_codes/error_codes/E0055.md @@ -6,7 +6,7 @@ recursion limit (which can be set via the `recursion_limit` attribute). For a somewhat artificial example: ```compile_fail,E0055 -#![recursion_limit="5"] +#![recursion_limit="4"] struct Foo; diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 649aac488fcb3..eeb30e2ced99b 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagnosticBuilder, ErrorReported}; use rustc_parse::{self, parser, MACRO_ARGUMENTS}; -use rustc_session::parse::ParseSess; +use rustc_session::{parse::ParseSess, Limit}; use rustc_span::def_id::DefId; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind}; @@ -941,7 +941,7 @@ pub struct ExpansionData { pub struct ExtCtxt<'a> { pub parse_sess: &'a ParseSess, pub ecfg: expand::ExpansionConfig<'a>, - pub reduced_recursion_limit: Option, + pub reduced_recursion_limit: Option, pub root_path: PathBuf, pub resolver: &'a mut dyn Resolver, pub current_expansion: ExpansionData, diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index b505302f62501..09ba64204c5c3 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -24,6 +24,7 @@ use rustc_parse::validate_attr; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; +use rustc_session::Limit; use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{FileName, Span, DUMMY_SP}; @@ -664,7 +665,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ) -> ExpandResult { let recursion_limit = self.cx.reduced_recursion_limit.unwrap_or(self.cx.ecfg.recursion_limit); - if self.cx.current_expansion.depth > recursion_limit { + if !recursion_limit.value_within_limit(self.cx.current_expansion.depth) { if self.cx.reduced_recursion_limit.is_none() { self.error_recursion_limit_reached(); } @@ -1784,7 +1785,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { pub struct ExpansionConfig<'feat> { pub crate_name: String, pub features: Option<&'feat Features>, - pub recursion_limit: usize, + pub recursion_limit: Limit, pub trace_mac: bool, pub should_test: bool, // If false, strip `#[test]` nodes pub keep_macs: bool, @@ -1795,7 +1796,7 @@ impl<'feat> ExpansionConfig<'feat> { ExpansionConfig { crate_name, features: None, - recursion_limit: 1024, + recursion_limit: Limit::new(1024), trace_mac: false, should_test: false, keep_macs: false, diff --git a/src/librustc_middle/middle/limits.rs b/src/librustc_middle/middle/limits.rs index 19c056925cf92..85198482bd380 100644 --- a/src/librustc_middle/middle/limits.rs +++ b/src/librustc_middle/middle/limits.rs @@ -8,7 +8,7 @@ use crate::bug; use rustc_ast::ast; use rustc_data_structures::sync::OnceCell; -use rustc_session::Session; +use rustc_session::{Limit, Session}; use rustc_span::symbol::{sym, Symbol}; use std::num::IntErrorKind; @@ -22,7 +22,7 @@ pub fn update_limits(sess: &Session, krate: &ast::Crate) { fn update_limit( sess: &Session, krate: &ast::Crate, - limit: &OnceCell, + limit: &OnceCell, name: Symbol, default: usize, ) { @@ -34,7 +34,7 @@ fn update_limit( if let Some(s) = attr.value_str() { match s.as_str().parse() { Ok(n) => { - limit.set(n).unwrap(); + limit.set(Limit::new(n)).unwrap(); return; } Err(e) => { @@ -62,5 +62,5 @@ fn update_limit( } } } - limit.set(default).unwrap(); + limit.set(Limit::new(default)).unwrap(); } diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 5566e187c0c5c..e93abd3390a2d 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -187,10 +187,9 @@ fn layout_raw<'tcx>( query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Result<&'tcx Layout, LayoutError<'tcx>> { ty::tls::with_related_context(tcx, move |icx| { - let rec_limit = tcx.sess.recursion_limit.get().copied().unwrap(); let (param_env, ty) = query.into_parts(); - if icx.layout_depth > rec_limit { + if !tcx.sess.recursion_limit().value_within_limit(icx.layout_depth) { tcx.sess.fatal(&format!("overflow representing the type `{}`", ty)); } diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index 7c1ab261eb9c4..dc13126df0e4c 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -10,6 +10,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_ast::ast::Mutability; use rustc_hir::def_id::DefId; use rustc_middle::mir::AssertMessage; +use rustc_session::Limit; use rustc_span::symbol::Symbol; use crate::interpret::{ @@ -109,8 +110,8 @@ pub struct MemoryExtra { } impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { - pub(super) fn new(const_eval_limit: usize) -> Self { - CompileTimeInterpreter { steps_remaining: const_eval_limit, stack: Vec::new() } + pub(super) fn new(const_eval_limit: Limit) -> Self { + CompileTimeInterpreter { steps_remaining: const_eval_limit.0, stack: Vec::new() } } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 4f91257e2ef83..6497e211de316 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -651,7 +651,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { M::after_stack_push(self)?; info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance); - if self.stack().len() > self.tcx.sess.recursion_limit() { + if !self.tcx.sess.recursion_limit().value_within_limit(self.stack().len()) { throw_exhaust!(StackFrameLimitReached) } else { Ok(()) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 1c5c13f843d7b..767eacd2c1ace 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -430,7 +430,7 @@ fn check_recursion_limit<'tcx>( // Code that needs to instantiate the same function recursively // more than the recursion limit is assumed to be causing an // infinite expansion. - if adjusted_recursion_depth >= tcx.sess.recursion_limit() { + if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) { let error = format!("reached the recursion limit while instantiating `{}`", instance); if let Some(def_id) = def_id.as_local() { let hir_id = tcx.hir().as_local_hir_id(def_id); @@ -463,7 +463,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // which means that rustc basically hangs. // // Bail out in these cases to avoid that bad user experience. - if type_length > tcx.sess.type_length_limit() { + if !tcx.sess.type_length_limit().value_within_limit(type_length) { // The instance name is already known to be too long for rustc. // Show only the first and last 32 characters to avoid blasting // the user's terminal with thousands of lines of type-name. diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index f2f02cb649463..a943cf3b67497 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -29,8 +29,10 @@ use rustc_target::spec::{Target, TargetTriple, TlsModel}; use std::cell::{self, RefCell}; use std::env; +use std::fmt; use std::io::Write; use std::num::NonZeroU32; +use std::ops::{Div, Mul}; use std::path::PathBuf; use std::str::FromStr; use std::sync::Arc; @@ -55,6 +57,46 @@ pub enum CtfeBacktrace { Immediate, } +/// New-type wrapper around `usize` for representing limits. Ensures that comparisons against +/// limits are consistent throughout the compiler. +#[derive(Clone, Copy, Debug)] +pub struct Limit(pub usize); + +impl Limit { + /// Create a new limit from a `usize`. + pub fn new(value: usize) -> Self { + Limit(value) + } + + /// Check that `value` is within the limit. Ensures that the same comparisons are used + /// throughout the compiler, as mismatches can cause ICEs, see #72540. + pub fn value_within_limit(&self, value: usize) -> bool { + value <= self.0 + } +} + +impl fmt::Display for Limit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl Div for Limit { + type Output = Limit; + + fn div(self, rhs: usize) -> Self::Output { + Limit::new(self.0 / rhs) + } +} + +impl Mul for Limit { + type Output = Limit; + + fn mul(self, rhs: usize) -> Self::Output { + Limit::new(self.0 * rhs) + } +} + /// Represents the data associated with a compilation /// session for a single crate. pub struct Session { @@ -89,13 +131,13 @@ pub struct Session { /// The maximum recursion limit for potentially infinitely recursive /// operations such as auto-dereference and monomorphization. - pub recursion_limit: OnceCell, + pub recursion_limit: OnceCell, /// The maximum length of types during monomorphization. - pub type_length_limit: OnceCell, + pub type_length_limit: OnceCell, /// The maximum blocks a const expression can evaluate. - pub const_eval_limit: OnceCell, + pub const_eval_limit: OnceCell, incr_comp_session: OneThread>, /// Used for incremental compilation tests. Will only be populated if @@ -255,15 +297,15 @@ impl Session { self.crate_types.set(crate_types).expect("`crate_types` was initialized twice") } - pub fn recursion_limit(&self) -> usize { + pub fn recursion_limit(&self) -> Limit { self.recursion_limit.get().copied().unwrap() } - pub fn type_length_limit(&self) -> usize { + pub fn type_length_limit(&self) -> Limit { self.type_length_limit.get().copied().unwrap() } - pub fn const_eval_limit(&self) -> usize { + pub fn const_eval_limit(&self) -> Limit { self.const_eval_limit.get().copied().unwrap() } diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index cd5d0be003aaf..1126480b02a0d 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -333,10 +333,10 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { Reveal::All => { let recursion_limit = self.tcx().sess.recursion_limit(); - if self.depth >= recursion_limit { + if !recursion_limit.value_within_limit(self.depth) { let obligation = Obligation::with_depth( self.cause.clone(), - recursion_limit, + recursion_limit.0, self.param_env, ty, ); @@ -522,7 +522,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // But for now, let's classify this as an overflow: let recursion_limit = selcx.tcx().sess.recursion_limit(); let obligation = - Obligation::with_depth(cause, recursion_limit, param_env, projection_ty); + Obligation::with_depth(cause, recursion_limit.0, param_env, projection_ty); selcx.infcx().report_overflow_error(&obligation, false); } Err(ProjectionCacheEntry::NormalizedTy(ty)) => { @@ -814,8 +814,7 @@ fn project_type<'cx, 'tcx>( ) -> Result, ProjectionTyError<'tcx>> { debug!("project(obligation={:?})", obligation); - let recursion_limit = selcx.tcx().sess.recursion_limit(); - if obligation.recursion_depth >= recursion_limit { + if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) { debug!("project: overflow!"); return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); } diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs index 008ca8d526dd3..3e7749356d212 100644 --- a/src/librustc_trait_selection/traits/query/normalize.rs +++ b/src/librustc_trait_selection/traits/query/normalize.rs @@ -109,10 +109,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { Reveal::All => { let recursion_limit = self.tcx().sess.recursion_limit(); - if self.anon_depth >= recursion_limit { + if !recursion_limit.value_within_limit(self.anon_depth) { let obligation = Obligation::with_depth( self.cause.clone(), - recursion_limit, + recursion_limit.0, self.param_env, ty, ); diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index b27fba2f82ba5..23e3eea021059 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -919,7 +919,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &Obligation<'tcx, T>, error_obligation: &Obligation<'tcx, V>, ) -> Result<(), OverflowError> { - if obligation.recursion_depth >= self.infcx.tcx.sess.recursion_limit() { + if !self.infcx.tcx.sess.recursion_limit().value_within_limit(obligation.recursion_depth) { match self.query_mode { TraitQueryMode::Standard => { self.infcx().report_overflow_error(error_obligation, true); diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index fb9c0d7f99013..11c48559bd683 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -163,7 +163,7 @@ fn dtorck_constraint_for_ty<'tcx>( ) -> Result<(), NoSolution> { debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty); - if depth >= tcx.sess.recursion_limit() { + if !tcx.sess.recursion_limit().value_within_limit(depth) { constraints.overflows.push(ty); return Ok(()); } diff --git a/src/librustc_ty/needs_drop.rs b/src/librustc_ty/needs_drop.rs index 1b059fa3dbdf0..c54704e7877f1 100644 --- a/src/librustc_ty/needs_drop.rs +++ b/src/librustc_ty/needs_drop.rs @@ -5,6 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop}; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_session::Limit; use rustc_span::DUMMY_SP; type NeedsDropResult = Result; @@ -30,7 +31,7 @@ struct NeedsDropTypes<'tcx, F> { /// if it needs drop. If the result depends on whether some other types /// need drop we push them onto the stack. unchecked_tys: Vec<(Ty<'tcx>, usize)>, - recursion_limit: usize, + recursion_limit: Limit, adt_components: F, } @@ -66,7 +67,7 @@ where let tcx = self.tcx; while let Some((ty, level)) = self.unchecked_tys.pop() { - if level > self.recursion_limit { + if !self.recursion_limit.value_within_limit(level) { // Not having a `Span` isn't great. But there's hopefully some other // recursion limit error as well. tcx.sess.span_err( diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index d4c01a82e0aa5..73d4e2b78206d 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { return Some((self.cur_ty, 0)); } - if self.steps.len() >= tcx.sess.recursion_limit() { + if !tcx.sess.recursion_limit().value_within_limit(self.steps.len()) { if !self.silence_errors { report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty); } diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index 45cb054b80c91..c9a6d42b5cc22 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `J: std::marker::Send` +error[E0275]: overflow evaluating the requirement `K: std::marker::Send` --> $DIR/recursion_limit.rs:34:5 | LL | fn is_send() { } @@ -8,6 +8,7 @@ LL | is_send::(); | ^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit`) + = note: required because it appears within the type `J` = note: required because it appears within the type `I` = note: required because it appears within the type `H` = note: required because it appears within the type `G` diff --git a/src/test/ui/did_you_mean/recursion_limit_deref.stderr b/src/test/ui/did_you_mean/recursion_limit_deref.stderr index e8d11530b08aa..8339cc291cf30 100644 --- a/src/test/ui/did_you_mean/recursion_limit_deref.stderr +++ b/src/test/ui/did_you_mean/recursion_limit_deref.stderr @@ -1,4 +1,4 @@ -error[E0055]: reached the recursion limit while auto-dereferencing `I` +error[E0055]: reached the recursion limit while auto-dereferencing `J` --> $DIR/recursion_limit_deref.rs:50:22 | LL | let x: &Bottom = &t; diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr index dd0c438f421c6..5df69e4649df5 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr @@ -4,7 +4,7 @@ error[E0320]: overflow while adding drop-check rules for FingerTree LL | let ft = | ^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for FingerTree --> $DIR/dropck_no_diverge_on_nonregular_1.rs:25:9 @@ -12,7 +12,7 @@ error[E0320]: overflow while adding drop-check rules for FingerTree LL | FingerTree::Single(1); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error: aborting due to 2 previous errors diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr index 769d5aed664f3..d34097d401004 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr @@ -4,7 +4,7 @@ error[E0320]: overflow while adding drop-check rules for FingerTree LL | let ft = | ^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for FingerTree --> $DIR/dropck_no_diverge_on_nonregular_2.rs:24:9 @@ -12,7 +12,7 @@ error[E0320]: overflow while adding drop-check rules for FingerTree LL | FingerTree::Single(1); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error: aborting due to 2 previous errors diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr index de8afdcc7cdab..1c810df242389 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr @@ -4,7 +4,7 @@ error[E0320]: overflow while adding drop-check rules for std::option::Option>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for std::option::Option> --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:9 @@ -12,7 +12,7 @@ error[E0320]: overflow while adding drop-check rules for std::option::Option); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for Wrapper --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:14 @@ -20,7 +20,7 @@ error[E0320]: overflow while adding drop-check rules for Wrapper LL | Some(Wrapper::Simple::); | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0055.rs b/src/test/ui/error-codes/E0055.rs index b525575d98d46..fd5804bbc2a59 100644 --- a/src/test/ui/error-codes/E0055.rs +++ b/src/test/ui/error-codes/E0055.rs @@ -1,4 +1,4 @@ -#![recursion_limit="5"] +#![recursion_limit="4"] struct Foo; impl Foo { diff --git a/src/test/ui/error-codes/E0055.stderr b/src/test/ui/error-codes/E0055.stderr index 01411e585abdd..1b8c5760e65bf 100644 --- a/src/test/ui/error-codes/E0055.stderr +++ b/src/test/ui/error-codes/E0055.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | ref_foo.foo(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="10"]` attribute to your crate (`E0055`) + = help: consider adding a `#![recursion_limit="8"]` attribute to your crate (`E0055`) error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0275.stderr b/src/test/ui/error-codes/E0275.stderr index a9fd0564ff548..2692fe6945e09 100644 --- a/src/test/ui/error-codes/E0275.stderr +++ b/src/test/ui/error-codes/E0275.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` +error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/E0275.rs:5:33 | LL | trait Foo {} @@ -8,6 +8,7 @@ LL | impl Foo for T where Bar: Foo {} | ^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`E0275`) + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` diff --git a/src/test/ui/infinite/infinite-instantiation.stderr b/src/test/ui/infinite/infinite-instantiation.stderr index f1c04447986b0..ae81c680a7b65 100644 --- a/src/test/ui/infinite/infinite-instantiation.stderr +++ b/src/test/ui/infinite/infinite-instantiation.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/infinite-instantiation.rs:25:1 | LL | / fn function(counter: usize, t: T) { diff --git a/src/test/ui/issues/issue-18400.stderr b/src/test/ui/issues/issue-18400.stderr index 57067ad51759a..ed9137ce396cf 100644 --- a/src/test/ui/issues/issue-18400.stderr +++ b/src/test/ui/issues/issue-18400.stderr @@ -133,6 +133,7 @@ LL | 0.contains(bits); = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index ad33eef07cba5..a3eb4fec70f32 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -6,7 +6,7 @@ LL | struct NoData; | = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` -error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` +error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/issue-20413.rs:8:36 | LL | trait Foo { @@ -16,6 +16,7 @@ LL | impl Foo for T where NoData: Foo { | ^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` @@ -144,7 +145,7 @@ LL | impl Foo for T where NoData: Foo { = note: required because of the requirements on the impl of `Foo` for `NoData>` = note: required because of the requirements on the impl of `Foo` for `NoData` -error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` +error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/issue-20413.rs:8:36 | LL | trait Foo { @@ -154,6 +155,7 @@ LL | impl Foo for T where NoData: Foo { | ^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index 7625e30498ac3..c4032b27edcbd 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -1,20 +1,20 @@ -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` --> $DIR/issue-23122-2.rs:7:15 | LL | impl Next for GetNext { | ^^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) - = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` + = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` --> $DIR/issue-23122-2.rs:9:5 | LL | type Next = as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) - = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` + = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-38940.rs b/src/test/ui/issues/issue-38940.rs index 1c785949547e5..3f10fc017a73f 100644 --- a/src/test/ui/issues/issue-38940.rs +++ b/src/test/ui/issues/issue-38940.rs @@ -42,5 +42,5 @@ fn main() { let t = Top::new(); let x: &Bottom = &t; //~^ ERROR mismatched types - //~| ERROR reached the recursion limit while auto-dereferencing `I` + //~| ERROR reached the recursion limit while auto-dereferencing `J` } diff --git a/src/test/ui/issues/issue-38940.stderr b/src/test/ui/issues/issue-38940.stderr index 36117278fd814..0671cede73bbe 100644 --- a/src/test/ui/issues/issue-38940.stderr +++ b/src/test/ui/issues/issue-38940.stderr @@ -1,4 +1,4 @@ -error[E0055]: reached the recursion limit while auto-dereferencing `I` +error[E0055]: reached the recursion limit while auto-dereferencing `J` --> $DIR/issue-38940.rs:43:22 | LL | let x: &Bottom = &t; diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr index 97ad76e207d04..881f9d221d6ae 100644 --- a/src/test/ui/issues/issue-67552.stderr +++ b/src/test/ui/issues/issue-67552.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>` +error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>` --> $DIR/issue-67552.rs:20:1 | LL | / fn rec(mut it: T) diff --git a/src/test/ui/issues/issue-8727.stderr b/src/test/ui/issues/issue-8727.stderr index 8f581a358e1e9..ee0672c598d5c 100644 --- a/src/test/ui/issues/issue-8727.stderr +++ b/src/test/ui/issues/issue-8727.stderr @@ -9,7 +9,7 @@ LL | generic::>(); = note: `#[warn(unconditional_recursion)]` on by default = help: a `loop` may express intention better if this is on purpose -error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-8727.rs:6:1 | LL | / fn generic() { diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index d64149d1437fe..de6df4cd0268c 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::> - shim(Some(S))` +error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::> - shim(Some(S))` error: aborting due to previous error diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr index ded8b3f87db62..1a65b0e84f6a3 100644 --- a/src/test/ui/recursion/recursion.stderr +++ b/src/test/ui/recursion/recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/recursion.rs:15:1 | LL | / fn test (n:isize, i:isize, first:T, second:T) ->isize { From fa351eefa0f547b9263984e71e1297052862a20f Mon Sep 17 00:00:00 2001 From: Nathan Corbyn Date: Thu, 21 May 2020 19:51:39 +0100 Subject: [PATCH 11/14] Fix ICE with explicit late-bound lifetimes --- src/librustc_typeck/astconv.rs | 310 ++++++++++++-------- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/mod.rs | 26 +- src/test/ui/issues/issue-72278.rs | 19 ++ src/test/ui/issues/issue-72278.stderr | 15 + 5 files changed, 241 insertions(+), 131 deletions(-) create mode 100644 src/test/ui/issues/issue-72278.rs create mode 100644 src/test/ui/issues/issue-72278.stderr diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9a5fe9552d35a..12edfed19c07e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -123,7 +123,22 @@ enum ConvertedBindingKind<'a, 'tcx> { Constraint(&'a [hir::GenericBound<'a>]), } -#[derive(PartialEq)] +/// New-typed boolean indicating whether explicit late-bound lifetimes +/// are present in a set of generic arguments. +/// +/// For example if we have some method `fn f<'a>(&'a self)` implemented +/// for some type `T`, although `f` is generic in the lifetime `'a`, `'a` +/// is late-bound so should not be provided explicitly. Thus, if `f` is +/// instantiated with some generic arguments providing `'a` explicitly, +/// we taint those arguments with `ExplicitLateBound::Yes` so that we +/// can provide an appropriate diagnostic later. +#[derive(Copy, Clone, PartialEq)] +pub enum ExplicitLateBound { + Yes, + No, +} + +#[derive(Copy, Clone, PartialEq)] enum GenericArgPosition { Type, Value, // e.g., functions @@ -132,6 +147,7 @@ enum GenericArgPosition { /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. +#[derive(Clone, Default)] pub struct GenericArgCountMismatch { /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`). pub reported: Option, @@ -139,6 +155,14 @@ pub struct GenericArgCountMismatch { pub invalid_args: Vec, } +/// Decorates the result of a generic argument count mismatch +/// check with whether explicit late bounds were provided. +#[derive(Clone)] +pub struct GenericArgCountResult { + pub explicit_late_bound: ExplicitLateBound, + pub correct: Result<(), GenericArgCountMismatch>, +} + impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn ast_region_to_region( &self, @@ -271,7 +295,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def: &ty::Generics, seg: &hir::PathSegment<'_>, is_method_call: bool, - ) -> Result<(), GenericArgCountMismatch> { + ) -> GenericArgCountResult { let empty_args = hir::GenericArgs::none(); let suppress_mismatch = Self::check_impl_trait(tcx, seg, &def); Self::check_generic_arg_count( @@ -295,7 +319,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { position: GenericArgPosition, has_self: bool, infer_args: bool, - ) -> Result<(), GenericArgCountMismatch> { + ) -> GenericArgCountResult { // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. // that lifetimes will proceed types. So it suffices to check the number of each generic // arguments in order to validate them with respect to the generic parameters. @@ -320,105 +344,86 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); } - // Prohibit explicit lifetime arguments if late-bound lifetime parameters are present. - let mut explicit_lifetimes = Ok(()); - if !infer_lifetimes { - if let Some(span_late) = def.has_late_bound_regions { - let msg = "cannot specify lifetime arguments explicitly \ - if late bound lifetime parameters are present"; - let note = "the late bound lifetime parameter is introduced here"; - let span = args.args[0].span(); - if position == GenericArgPosition::Value - && arg_counts.lifetimes != param_counts.lifetimes - { - explicit_lifetimes = Err(true); - let mut err = tcx.sess.struct_span_err(span, msg); - err.span_note(span_late, note); - err.emit(); - } else { - explicit_lifetimes = Err(false); - let mut multispan = MultiSpan::from_span(span); - multispan.push_span_label(span_late, note.to_string()); - tcx.struct_span_lint_hir( - LATE_BOUND_LIFETIME_ARGUMENTS, - args.args[0].id(), - multispan, - |lint| lint.build(msg).emit(), - ); - } + let explicit_late_bound = + Self::prohibit_explicit_late_bound_lifetimes(tcx, def, args, position); + + let check_kind_count = |kind, + required, + permitted, + provided, + offset, + unexpected_spans: &mut Vec, + silent| { + debug!( + "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", + kind, required, permitted, provided, offset + ); + // We enforce the following: `required` <= `provided` <= `permitted`. + // For kinds without defaults (e.g.., lifetimes), `required == permitted`. + // For other kinds (i.e., types), `permitted` may be greater than `required`. + if required <= provided && provided <= permitted { + return Ok(()); } - } - let check_kind_count = - |kind, required, permitted, provided, offset, unexpected_spans: &mut Vec| { - debug!( - "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", - kind, required, permitted, provided, offset - ); - // We enforce the following: `required` <= `provided` <= `permitted`. - // For kinds without defaults (e.g.., lifetimes), `required == permitted`. - // For other kinds (i.e., types), `permitted` may be greater than `required`. - if required <= provided && provided <= permitted { - return Ok(()); - } - - // Unfortunately lifetime and type parameter mismatches are typically styled - // differently in diagnostics, which means we have a few cases to consider here. - let (bound, quantifier) = if required != permitted { - if provided < required { - (required, "at least ") - } else { - // provided > permitted - (permitted, "at most ") - } - } else { - (required, "") - }; + if silent { + return Err(true); + } - let (spans, label) = if required == permitted && provided > permitted { - // In the case when the user has provided too many arguments, - // we want to point to the unexpected arguments. - let spans: Vec = args.args[offset + permitted..offset + provided] - .iter() - .map(|arg| arg.span()) - .collect(); - unexpected_spans.extend(spans.clone()); - (spans, format!("unexpected {} argument", kind)) + // Unfortunately lifetime and type parameter mismatches are typically styled + // differently in diagnostics, which means we have a few cases to consider here. + let (bound, quantifier) = if required != permitted { + if provided < required { + (required, "at least ") } else { - ( - vec![span], - format!( - "expected {}{} {} argument{}", - quantifier, - bound, - kind, - pluralize!(bound), - ), - ) - }; - - let mut err = tcx.sess.struct_span_err_with_code( - spans.clone(), - &format!( - "wrong number of {} arguments: expected {}{}, found {}", - kind, quantifier, bound, provided, - ), - DiagnosticId::Error("E0107".into()), - ); - for span in spans { - err.span_label(span, label.as_str()); + // provided > permitted + (permitted, "at most ") } - err.emit(); + } else { + (required, "") + }; - Err(true) + let (spans, label) = if required == permitted && provided > permitted { + // In the case when the user has provided too many arguments, + // we want to point to the unexpected arguments. + let spans: Vec = args.args[offset + permitted..offset + provided] + .iter() + .map(|arg| arg.span()) + .collect(); + unexpected_spans.extend(spans.clone()); + (spans, format!("unexpected {} argument", kind)) + } else { + ( + vec![span], + format!( + "expected {}{} {} argument{}", + quantifier, + bound, + kind, + pluralize!(bound), + ), + ) }; - let mut arg_count_correct = explicit_lifetimes; + let mut err = tcx.sess.struct_span_err_with_code( + spans.clone(), + &format!( + "wrong number of {} arguments: expected {}{}, found {}", + kind, quantifier, bound, provided, + ), + DiagnosticId::Error("E0107".into()), + ); + for span in spans { + err.span_label(span, label.as_str()); + } + err.emit(); + + Err(true) + }; + + let mut arg_count_correct = Ok(()); let mut unexpected_spans = vec![]; - if arg_count_correct.is_ok() - && (!infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes) - { + if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { arg_count_correct = check_kind_count( "lifetime", param_counts.lifetimes, @@ -426,6 +431,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.lifetimes, 0, &mut unexpected_spans, + explicit_late_bound == ExplicitLateBound::Yes, ) .and(arg_count_correct); } @@ -438,6 +444,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.consts, arg_counts.lifetimes + arg_counts.types, &mut unexpected_spans, + false, ) .and(arg_count_correct); } @@ -451,14 +458,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.types, arg_counts.lifetimes, &mut unexpected_spans, + false, ) .and(arg_count_correct); } - arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { - reported: if reported_err { Some(ErrorReported) } else { None }, - invalid_args: unexpected_spans, - }) + GenericArgCountResult { + explicit_late_bound, + correct: arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { + reported: if reported_err { Some(ErrorReported) } else { None }, + invalid_args: unexpected_spans, + }), + } } /// Report an error that a generic argument did not match the generic parameter that was @@ -512,7 +523,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs: &[subst::GenericArg<'tcx>], has_self: bool, self_ty: Option>, - arg_count_correct: bool, + arg_count: GenericArgCountResult, args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool), mut provided_kind: impl FnMut(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>, mut inferred_kind: impl FnMut( @@ -585,10 +596,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // input. We try to handle both sensibly. match (args.peek(), params.peek()) { (Some(&arg), Some(¶m)) => { - match (arg, ¶m.kind) { - (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime) - | (GenericArg::Type(_), GenericParamDefKind::Type { .. }) - | (GenericArg::Const(_), GenericParamDefKind::Const) => { + match (arg, ¶m.kind, arg_count.explicit_late_bound) { + (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) + | (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _) + | (GenericArg::Const(_), GenericParamDefKind::Const, _) => { substs.push(provided_kind(param, arg)); args.next(); params.next(); @@ -596,6 +607,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ( GenericArg::Type(_) | GenericArg::Const(_), GenericParamDefKind::Lifetime, + _, ) => { // We expected a lifetime argument, but got a type or const // argument. That means we're inferring the lifetimes. @@ -603,12 +615,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { force_infer_lt = Some(arg); params.next(); } - (_, kind) => { + (GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => { + // We've come across a lifetime when we expected something else in + // the presence of explicit late bounds. This is most likely + // due to the presence of the explicit bound so we're just going to + // ignore it. + args.next(); + } + (_, kind, _) => { // We expected one kind of parameter, but the user provided // another. This is an error. However, if we already know that // the arguments don't match up with the parameters, we won't issue // an additional error, as the user already knows what's wrong. - if arg_count_correct { + if arg_count.correct.is_ok() + && arg_count.explicit_late_bound == ExplicitLateBound::No + { Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr()); } @@ -624,17 +645,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (Some(&arg), None) => { // We should never be able to reach this point with well-formed input. - // There are two situations in which we can encounter this issue. + // There are three situations in which we can encounter this issue. // // 1. The number of arguments is incorrect. In this case, an error - // will already have been emitted, and we can ignore it. This case - // also occurs when late-bound lifetime parameters are present, yet - // the lifetime arguments have also been explicitly specified by the + // will already have been emitted, and we can ignore it. + // 2. There are late-bound lifetime parameters present, yet the + // lifetime arguments have also been explicitly specified by the // user. - // 2. We've inferred some lifetimes, which have been provided later (i.e. + // 3. We've inferred some lifetimes, which have been provided later (i.e. // after a type or const). We want to throw an error in this case. - if arg_count_correct { + if arg_count.correct.is_ok() + && arg_count.explicit_late_bound == ExplicitLateBound::No + { let kind = arg.descr(); assert_eq!(kind, "lifetime"); let provided = @@ -699,8 +722,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_args: &'a hir::GenericArgs<'_>, infer_args: bool, self_ty: Option>, - ) -> (SubstsRef<'tcx>, Vec>, Result<(), GenericArgCountMismatch>) - { + ) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). @@ -726,7 +748,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert!(self_ty.is_none() && parent_substs.is_empty()); } - let arg_count_correct = Self::check_generic_arg_count( + let arg_count = Self::check_generic_arg_count( tcx, span, &generic_params, @@ -761,7 +783,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs, self_ty.is_some(), self_ty, - arg_count_correct.is_ok(), + arg_count.clone(), // Provide the generic args, and whether types should be inferred. |did| { if did == def_id { @@ -880,7 +902,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_params, self_ty, substs ); - (substs, assoc_bindings, arg_count_correct) + (substs, assoc_bindings, arg_count) } crate fn create_substs_for_associated_item( @@ -1011,14 +1033,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, speculative: bool, - ) -> Result<(), GenericArgCountMismatch> { + ) -> GenericArgCountResult { let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); - let (substs, assoc_bindings, arg_count_correct) = self.create_substs_for_ast_trait_ref( + let (substs, assoc_bindings, arg_count) = self.create_substs_for_ast_trait_ref( trait_ref.path.span, trait_def_id, self_ty, @@ -1048,7 +1070,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_ref, bounds, poly_trait_ref ); - arg_count_correct + arg_count } /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct @@ -1076,7 +1098,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { constness: Constness, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, - ) -> Result<(), GenericArgCountMismatch> { + ) -> GenericArgCountResult { self.instantiate_poly_trait_ref_inner( &poly_trait_ref.trait_ref, poly_trait_ref.span, @@ -1166,8 +1188,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_def_id: DefId, self_ty: Ty<'tcx>, trait_segment: &'a hir::PathSegment<'a>, - ) -> (SubstsRef<'tcx>, Vec>, Result<(), GenericArgCountMismatch>) - { + ) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); @@ -1515,9 +1536,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; for trait_bound in trait_bounds.iter().rev() { - if let Err(GenericArgCountMismatch { - invalid_args: cur_potential_assoc_types, .. - }) = self.instantiate_poly_trait_ref( + if let GenericArgCountResult { + correct: + Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), + .. + } = self.instantiate_poly_trait_ref( trait_bound, Constness::NotConst, dummy_self, @@ -2473,6 +2496,47 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_label(span, "associated type not allowed here").emit(); } + /// Prohibits explicit lifetime arguments if late-bound lifetime parameters + /// are present. This is used both for datatypes and function calls. + fn prohibit_explicit_late_bound_lifetimes( + tcx: TyCtxt<'_>, + def: &ty::Generics, + args: &hir::GenericArgs<'_>, + position: GenericArgPosition, + ) -> ExplicitLateBound { + let param_counts = def.own_counts(); + let arg_counts = args.own_counts(); + let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; + + if infer_lifetimes { + ExplicitLateBound::No + } else if let Some(span_late) = def.has_late_bound_regions { + let msg = "cannot specify lifetime arguments explicitly \ + if late bound lifetime parameters are present"; + let note = "the late bound lifetime parameter is introduced here"; + let span = args.args[0].span(); + if position == GenericArgPosition::Value + && arg_counts.lifetimes != param_counts.lifetimes + { + let mut err = tcx.sess.struct_span_err(span, msg); + err.span_note(span_late, note); + err.emit(); + } else { + let mut multispan = MultiSpan::from_span(span); + multispan.push_span_label(span_late, note.to_string()); + tcx.struct_span_lint_hir( + LATE_BOUND_LIFETIME_ARGUMENTS, + args.args[0].id(), + multispan, + |lint| lint.build(msg).emit(), + ); + } + ExplicitLateBound::Yes + } else { + ExplicitLateBound::No + } + } + // FIXME(eddyb, varkor) handle type paths here too, not just value ones. pub fn def_ids_for_value_path_segments( &self, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 410c5efdf37d4..35094c69037b6 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -312,7 +312,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { parent_substs, false, None, - arg_count_correct.is_ok(), + arg_count_correct, // Provide the generic args, and whether types should be inferred. |def_id| { // The last component of the returned tuple here is unimportant. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index da711b9d48042..91ebb10303764 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,7 +87,9 @@ mod upvar; mod wfcheck; pub mod writeback; -use crate::astconv::{AstConv, GenericArgCountMismatch, PathSeg}; +use crate::astconv::{ + AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, +}; use rustc_ast::ast; use rustc_ast::util::parser::ExprPrecedence; use rustc_attr as attr; @@ -5495,11 +5497,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parameter internally, but we don't allow users to specify the // parameter's value explicitly, so we have to do some error- // checking here. - if let Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }) = - AstConv::check_generic_arg_count_for_call( - tcx, span, &generics, &seg, false, // `is_method_call` - ) - { + if let GenericArgCountResult { + correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }), + .. + } = AstConv::check_generic_arg_count_for_call( + tcx, span, &generics, &seg, false, // `is_method_call` + ) { infer_args_for_err.insert(index); self.set_tainted_by_errors(); // See issue #53251. } @@ -5555,6 +5558,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // escaping late-bound regions, and nor should the base type scheme. let ty = tcx.type_of(def_id); + let arg_count = GenericArgCountResult { + explicit_late_bound: ExplicitLateBound::No, + correct: if infer_args_for_err.is_empty() { + Ok(()) + } else { + Err(GenericArgCountMismatch::default()) + }, + }; + let substs = self_ctor_substs.unwrap_or_else(|| { AstConv::create_substs_for_generic_args( tcx, @@ -5562,7 +5574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &[][..], has_self, self_ty, - infer_args_for_err.is_empty(), + arg_count, // Provide the generic args, and whether types should be inferred. |def_id| { if let Some(&PathSeg(_, index)) = diff --git a/src/test/ui/issues/issue-72278.rs b/src/test/ui/issues/issue-72278.rs new file mode 100644 index 0000000000000..92fd1f73a937f --- /dev/null +++ b/src/test/ui/issues/issue-72278.rs @@ -0,0 +1,19 @@ +// run-pass + +#![allow(unused)] + +struct S; + +impl S { + fn func<'a, U>(&'a self) -> U { + todo!() + } +} + +fn dont_crash<'a, U>() -> U { + S.func::<'a, U>() + //~^ WARN cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted +} + +fn main() {} diff --git a/src/test/ui/issues/issue-72278.stderr b/src/test/ui/issues/issue-72278.stderr new file mode 100644 index 0000000000000..41dff686bc4ae --- /dev/null +++ b/src/test/ui/issues/issue-72278.stderr @@ -0,0 +1,15 @@ +warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/issue-72278.rs:14:14 + | +LL | fn func<'a, U>(&'a self) -> U { + | -- the late bound lifetime parameter is introduced here +... +LL | S.func::<'a, U>() + | ^^ + | + = note: `#[warn(late_bound_lifetime_arguments)]` on by default + = 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 #42868 + +warning: 1 warning emitted + From dbf32e2270f82601bd2816da270ce70269cc59ba Mon Sep 17 00:00:00 2001 From: mendess Date: Fri, 29 May 2020 11:18:15 +0100 Subject: [PATCH 12/14] Remove flaky test and document the other's flakiness --- src/liballoc/tests/boxed.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/liballoc/tests/boxed.rs b/src/liballoc/tests/boxed.rs index c0b8fa665615e..5377485da8f3b 100644 --- a/src/liballoc/tests/boxed.rs +++ b/src/liballoc/tests/boxed.rs @@ -34,6 +34,11 @@ fn box_clone_and_clone_from_equivalence() { } } +/// This test might give a false positive in case the box realocates, but the alocator keeps the +/// original pointer. +/// +/// On the other hand it won't give a false negative, if it fails than the memory was definitly not +/// reused #[test] fn box_clone_from_ptr_stability() { for size in (0..8).map(|i| 2usize.pow(i)) { @@ -43,12 +48,4 @@ fn box_clone_from_ptr_stability() { copy.clone_from(&control); assert_eq!(copy.as_ptr() as usize, copy_raw); } - - for size in (0..8).map(|i| 2usize.pow(i)) { - let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); - let mut copy = vec![Dummy { _data: 84 }; size + 1].into_boxed_slice(); - let copy_raw = copy.as_ptr() as usize; - copy.clone_from(&control); - assert_ne!(copy.as_ptr() as usize, copy_raw); - } } From 8ef93928282c939554b9b7b518665fcde06c6ba6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 11:41:58 +0200 Subject: [PATCH 13/14] multiple Return terminators are possible --- src/librustc_middle/mir/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 20c64d40fabbd..0e9c133e2c322 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -1072,7 +1072,8 @@ pub enum TerminatorKind<'tcx> { Abort, /// Indicates a normal return. The return place should have - /// been filled in by now. This should occur at most once. + /// been filled in before this executes. This can occur multiple times + /// in different basic blocks. Return, /// Indicates a terminator that can never be reached. From 49b1b4c438a87f54ebbae90b9b21ccce7622f8e7 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 17 May 2020 17:02:57 +0200 Subject: [PATCH 14/14] more `LocalDefId`s --- src/librustc_interface/passes.rs | 2 +- src/librustc_middle/query/mod.rs | 10 ++++++++-- src/librustc_mir/transform/check_unsafety.rs | 17 +++++++++-------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 214701db724ec..c06fd91133b5c 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -838,7 +838,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> { sess.time("MIR_effect_checking", || { for def_id in tcx.body_owners() { - mir::transform::check_unsafety::check_unsafety(tcx, def_id.to_def_id()) + mir::transform::check_unsafety::check_unsafety(tcx, def_id) } }); diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 85451bf6538e4..59b6f5e529baa 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -386,8 +386,14 @@ rustc_queries! { storage(ArenaCacheSelector<'tcx>) } - /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error - query unsafe_derive_on_repr_packed(_: DefId) -> () {} + /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error. + /// + /// Unsafety checking is executed for each method separately, but we only want + /// to emit this error once per derive. As there are some impls with multiple + /// methods, we use a query for deduplication. + query unsafe_derive_on_repr_packed(key: LocalDefId) -> () { + desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } + } /// The signature of functions and closures. query fn_sig(_: DefId) -> ty::PolyFnSig<'tcx> {} diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 1f01bc0e19513..e32bccc85ee6f 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -579,8 +579,8 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: LocalDefId) -> UnsafetyCheckRe } } -fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: DefId) { - let lint_hir_id = tcx.hir().as_local_hir_id(def_id.expect_local()); +fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + let lint_hir_id = tcx.hir().as_local_hir_id(def_id); tcx.struct_span_lint_hir(SAFE_PACKED_BORROWS, lint_hir_id, tcx.def_span(def_id), |lint| { // FIXME: when we make this a hard error, this should have its @@ -659,16 +659,15 @@ fn builtin_derive_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option { } } -pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { +pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { debug!("check_unsafety({:?})", def_id); // closures are handled by their parent fn. - if tcx.is_closure(def_id) { + if tcx.is_closure(def_id.to_def_id()) { return; } - let UnsafetyCheckResult { violations, unsafe_blocks } = - tcx.unsafety_check_result(def_id.expect_local()); + let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id); for &UnsafetyViolation { source_info, lint_root, description, details, kind } in violations.iter() @@ -693,8 +692,10 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { .emit(); } 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); + if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id.to_def_id()) { + // If a method is defined in the local crate, + // the impl containing that method should also be. + tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local()); } else { tcx.struct_span_lint_hir( SAFE_PACKED_BORROWS,