diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 76765c8a0aa38..b0c0ee942ea8f 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1176,7 +1176,7 @@ impl FieldsShape { /// Gets source indices of the fields by increasing offsets. #[inline] - pub fn index_by_increasing_offset<'a>(&'a self) -> impl Iterator + 'a { + pub fn index_by_increasing_offset(&self) -> impl Iterator + '_ { let mut inverse_small = [0u8; 64]; let mut inverse_big = IndexVec::new(); let use_small = self.count() <= inverse_small.len(); diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 4fae5ef845f7d..345e058e1134a 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -22,6 +22,7 @@ #![feature(strict_provenance)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine. use smallvec::SmallVec; @@ -568,7 +569,9 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { } pub trait ArenaAllocatable<'tcx, C = rustc_arena::IsNotCopy>: Sized { + #[allow(clippy::mut_from_ref)] fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self; + #[allow(clippy::mut_from_ref)] fn allocate_from_iter<'a>( arena: &'a Arena<'tcx>, iter: impl ::std::iter::IntoIterator, @@ -578,10 +581,12 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`. impl<'tcx, T: Copy> ArenaAllocatable<'tcx, rustc_arena::IsCopy> for T { #[inline] + #[allow(clippy::mut_from_ref)] fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { arena.dropless.alloc(self) } #[inline] + #[allow(clippy::mut_from_ref)] fn allocate_from_iter<'a>( arena: &'a Arena<'tcx>, iter: impl ::std::iter::IntoIterator, @@ -601,6 +606,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { } #[inline] + #[allow(clippy::mut_from_ref)] fn allocate_from_iter<'a>( arena: &'a Arena<'tcx>, iter: impl ::std::iter::IntoIterator, @@ -616,12 +622,14 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { impl<'tcx> Arena<'tcx> { #[inline] + #[allow(clippy::mut_from_ref)] pub fn alloc, C>(&self, value: T) -> &mut T { value.allocate_on(self) } // Any type that impls `Copy` can have slices be arena-allocated in the `DroplessArena`. #[inline] + #[allow(clippy::mut_from_ref)] pub fn alloc_slice(&self, value: &[T]) -> &mut [T] { if value.is_empty() { return &mut []; @@ -629,6 +637,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { self.dropless.alloc_slice(value) } + #[allow(clippy::mut_from_ref)] pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, C>, C>( &'a self, iter: impl ::std::iter::IntoIterator, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 236ebd04ae88d..1389acabfcbd5 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -691,7 +691,7 @@ fn validate_generic_param_order( GenericParamKind::Lifetime => (), GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => { ordered_params += " = "; - ordered_params += &pprust::expr_to_string(&*default.value); + ordered_params += &pprust::expr_to_string(&default.value); } GenericParamKind::Const { ty: _, kw_span: _, default: None } => (), } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index b3923b651eb3b..007d64f681f76 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -404,11 +404,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } else { // And if it isn't, cancel the early-pass warning. - self.sess + if let Some(err) = self + .sess .parse_sess .span_diagnostic .steal_diagnostic(e.span, StashKey::EarlySyntaxWarning) - .map(|err| err.cancel()); + { + err.cancel() + } } } ast::ExprKind::TryBlock(_) => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 80c451d675355..1f6838a027844 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -686,7 +686,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool) { let has_comment = self.maybe_print_comment(span.hi()); if !empty || has_comment { - self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize)); + self.break_offset_if_not_bol(1, -INDENT_UNIT); } self.word("}"); if close_box { @@ -988,7 +988,9 @@ impl<'a> State<'a> { pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) { self.print_ident(constraint.ident); - constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false)); + if let Some(args) = constraint.gen_args.as_ref() { + self.print_generic_args(args, false) + } self.space(); match &constraint.kind { ast::AssocConstraintKind::Equality { term } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index ddef4aaee3bab..b37797fef4ce3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -259,6 +259,31 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } impl<'a, 'tcx, V: CodegenObject> OperandValue { + /// Returns an `OperandValue` that's generally UB to use in any way. + /// + /// Depending on the `layout`, returns an `Immediate` or `Pair` containing + /// poison value(s), or a `Ref` containing a poison pointer. + /// + /// Supports sized types only. + pub fn poison>( + bx: &mut Bx, + layout: TyAndLayout<'tcx>, + ) -> OperandValue { + assert!(layout.is_sized()); + if bx.cx().is_backend_immediate(layout) { + let ibty = bx.cx().immediate_backend_type(layout); + OperandValue::Immediate(bx.const_poison(ibty)) + } else if bx.cx().is_backend_scalar_pair(layout) { + let ibty0 = bx.cx().scalar_pair_element_backend_type(layout, 0, true); + let ibty1 = bx.cx().scalar_pair_element_backend_type(layout, 1, true); + OperandValue::Pair(bx.const_poison(ibty0), bx.const_poison(ibty1)) + } else { + let bty = bx.cx().backend_type(layout); + let ptr_bty = bx.cx().type_ptr_to(bty); + OperandValue::Ref(bx.const_poison(ptr_bty), None, layout.align.abi) + } + } + pub fn store>( self, bx: &mut Bx, diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 400512fe4e9ad..d88226f5db053 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -158,17 +158,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { debug_assert!(src.layout.is_sized()); debug_assert!(dst.layout.is_sized()); - if src.layout.size != dst.layout.size - || src.layout.abi.is_uninhabited() - || dst.layout.abi.is_uninhabited() - { - // In all of these cases it's UB to run this transmute, but that's - // known statically so might as well trap for it, rather than just - // making it unreachable. - bx.abort(); - return; - } - if let Some(val) = self.codegen_transmute_operand(bx, src, dst.layout) { val.store(bx, dst); return; @@ -202,8 +191,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { operand: OperandRef<'tcx, Bx::Value>, cast: TyAndLayout<'tcx>, ) -> Option> { - // Callers already checked that the layout sizes match - debug_assert_eq!(operand.layout.size, cast.size); + // Check for transmutes that are always UB. + if operand.layout.size != cast.size + || operand.layout.abi.is_uninhabited() + || cast.abi.is_uninhabited() + { + if !operand.layout.abi.is_uninhabited() { + // Since this is known statically and the input could have existed + // without already having hit UB, might as well trap for it. + bx.abort(); + } + + // Because this transmute is UB, return something easy to generate, + // since it's fine that later uses of the value are probably UB. + return Some(OperandValue::poison(bx, cast)); + } let operand_kind = self.value_kind(operand.layout); let cast_kind = self.value_kind(cast); @@ -222,10 +224,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("Found {operand_kind:?} for operand {operand:?}"); }; if let OperandValueKind::Immediate(out_scalar) = cast_kind { - let cast_bty = bx.backend_type(cast); - Some(OperandValue::Immediate(Self::transmute_immediate( - bx, imm, in_scalar, out_scalar, cast_bty, - ))) + match (in_scalar, out_scalar) { + (ScalarOrZst::Zst, ScalarOrZst::Zst) => { + Some(OperandRef::new_zst(bx, cast).val) + } + (ScalarOrZst::Scalar(in_scalar), ScalarOrZst::Scalar(out_scalar)) + if in_scalar.size(self.cx) == out_scalar.size(self.cx) => + { + let cast_bty = bx.backend_type(cast); + Some(OperandValue::Immediate( + self.transmute_immediate(bx, imm, in_scalar, out_scalar, cast_bty), + )) + } + _ => None, + } } else { None } @@ -234,12 +246,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let OperandValueKind::Pair(in_a, in_b) = operand_kind else { bug!("Found {operand_kind:?} for operand {operand:?}"); }; - if let OperandValueKind::Pair(out_a, out_b) = cast_kind { + if let OperandValueKind::Pair(out_a, out_b) = cast_kind + && in_a.size(self.cx) == out_a.size(self.cx) + && in_b.size(self.cx) == out_b.size(self.cx) + { let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false); let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false); Some(OperandValue::Pair( - Self::transmute_immediate(bx, imm_a, in_a, out_a, out_a_ibty), - Self::transmute_immediate(bx, imm_b, in_b, out_b, out_b_ibty), + self.transmute_immediate(bx, imm_a, in_a, out_a, out_a_ibty), + self.transmute_immediate(bx, imm_b, in_b, out_b, out_b_ibty), )) } else { None @@ -254,12 +269,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// `to_backend_ty` must be the *non*-immediate backend type (so it will be /// `i8`, not `i1`, for `bool`-like types.) fn transmute_immediate( + &self, bx: &mut Bx, mut imm: Bx::Value, from_scalar: abi::Scalar, to_scalar: abi::Scalar, to_backend_ty: Bx::Type, ) -> Bx::Value { + debug_assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx)); + use abi::Primitive::*; imm = bx.from_immediate(imm); imm = match (from_scalar.primitive(), to_scalar.primitive()) { @@ -831,14 +849,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let operand_ty = operand.ty(self.mir, self.cx.tcx()); let cast_layout = self.cx.layout_of(self.monomorphize(cast_ty)); let operand_layout = self.cx.layout_of(self.monomorphize(operand_ty)); - if operand_layout.size != cast_layout.size - || operand_layout.abi.is_uninhabited() - || cast_layout.abi.is_uninhabited() - { - // Send UB cases to the full form so the operand version can - // `bitcast` without worrying about malformed IR. - return false; - } match (self.value_kind(operand_layout), self.value_kind(cast_layout)) { // Can always load from a pointer as needed @@ -847,9 +857,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Need to generate an `alloc` to get a pointer from an immediate (OperandValueKind::Immediate(..) | OperandValueKind::Pair(..), OperandValueKind::Ref) => false, - // When we have scalar immediates, we can convert them as needed - (OperandValueKind::Immediate(..), OperandValueKind::Immediate(..)) | - (OperandValueKind::Pair(..), OperandValueKind::Pair(..)) => true, + // When we have scalar immediates, we can only convert things + // where the sizes match, to avoid endianness questions. + (OperandValueKind::Immediate(a), OperandValueKind::Immediate(b)) => + a.size(self.cx) == b.size(self.cx), + (OperandValueKind::Pair(a0, a1), OperandValueKind::Pair(b0, b1)) => + a0.size(self.cx) == b0.size(self.cx) && a1.size(self.cx) == b1.size(self.cx), // Send mixings between scalars and pairs through the memory route // FIXME: Maybe this could use insertvalue/extractvalue instead? @@ -887,13 +900,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if self.cx.is_backend_immediate(layout) { debug_assert!(!self.cx.is_backend_scalar_pair(layout)); OperandValueKind::Immediate(match layout.abi { - abi::Abi::Scalar(s) => s, - abi::Abi::Vector { element, .. } => element, - x => bug!("Couldn't translate {x:?} as backend immediate"), + abi::Abi::Scalar(s) => ScalarOrZst::Scalar(s), + abi::Abi::Vector { element, .. } => ScalarOrZst::Scalar(element), + _ if layout.is_zst() => ScalarOrZst::Zst, + x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"), }) } else if self.cx.is_backend_scalar_pair(layout) { let abi::Abi::ScalarPair(s1, s2) = layout.abi else { - bug!("Couldn't translate {:?} as backend scalar pair", layout.abi) + span_bug!( + self.mir.span, + "Couldn't translate {:?} as backend scalar pair", + layout.abi, + ); }; OperandValueKind::Pair(s1, s2) } else { @@ -902,9 +920,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } +/// The variants of this match [`OperandValue`], giving details about the +/// backend values that will be held in that other type. #[derive(Debug, Copy, Clone)] enum OperandValueKind { Ref, - Immediate(abi::Scalar), + Immediate(ScalarOrZst), Pair(abi::Scalar, abi::Scalar), } + +#[derive(Debug, Copy, Clone)] +enum ScalarOrZst { + Zst, + Scalar(abi::Scalar), +} + +impl ScalarOrZst { + pub fn size(self, cx: &impl abi::HasDataLayout) -> abi::Size { + match self { + ScalarOrZst::Zst => abi::Size::ZERO, + ScalarOrZst::Scalar(s) => s.size(cx), + } + } +} diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs index 1aa7ac024d94e..9ff401c3c7aad 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs @@ -206,17 +206,11 @@ impl Graph { AdjacentEdges { graph: self, direction, next: first_edge } } - pub fn successor_nodes<'a>( - &'a self, - source: NodeIndex, - ) -> impl Iterator + 'a { + pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator + '_ { self.outgoing_edges(source).targets() } - pub fn predecessor_nodes<'a>( - &'a self, - target: NodeIndex, - ) -> impl Iterator + 'a { + pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator + '_ { self.incoming_edges(target).sources() } diff --git a/compiler/rustc_data_structures/src/memmap.rs b/compiler/rustc_data_structures/src/memmap.rs index 1556873f59765..ef37a606f313e 100644 --- a/compiler/rustc_data_structures/src/memmap.rs +++ b/compiler/rustc_data_structures/src/memmap.rs @@ -40,7 +40,7 @@ impl Deref for Mmap { impl AsRef<[u8]> for Mmap { fn as_ref(&self) -> &[u8] { - &*self.0 + &self.0 } } diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 58a0609e29655..1ed584eafad30 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -778,7 +778,7 @@ pub fn print_time_passes_entry( "rss_start": start_rss, "rss_end": end_rss, }); - eprintln!("time: {}", json.to_string()); + eprintln!("time: {json}"); return; } TimePassesFormat::Text => (), diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index f88c055a9b569..bd7a86f67800f 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -140,6 +140,7 @@ pub fn make_hash(val: &K) -> u64 { /// `hash` can be computed with any hasher, so long as that hasher is used /// consistently for each `Sharded` instance. #[inline] +#[allow(clippy::modulo_one)] pub fn get_shard_index_by_hash(hash: u64) -> usize { let hash_len = mem::size_of::(); // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits. diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index de9842156d61f..3ed1de1bc3ca1 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -312,14 +312,14 @@ impl HashStable for ::std::num::NonZeroUsize { impl HashStable for f32 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u32 = unsafe { ::std::mem::transmute(*self) }; + let val: u32 = self.to_bits(); val.hash_stable(ctx, hasher); } } impl HashStable for f64 { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - let val: u64 = unsafe { ::std::mem::transmute(*self) }; + let val: u64 = self.to_bits(); val.hash_stable(ctx, hasher); } } diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index 3bdd67512321b..7ff1339c5ab34 100644 --- a/compiler/rustc_data_structures/src/stack.rs +++ b/compiler/rustc_data_structures/src/stack.rs @@ -5,7 +5,7 @@ const RED_ZONE: usize = 100 * 1024; // 100k // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then // on. This flag has performance relevant characteristics. Don't set it too high. -const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB +const STACK_PER_RECURSION: usize = 1024 * 1024; // 1MB /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations /// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit diff --git a/compiler/rustc_data_structures/src/sync/vec.rs b/compiler/rustc_data_structures/src/sync/vec.rs index aefaa8519d536..1783b4b357257 100644 --- a/compiler/rustc_data_structures/src/sync/vec.rs +++ b/compiler/rustc_data_structures/src/sync/vec.rs @@ -84,7 +84,7 @@ impl AppendOnlyVec { } pub fn iter(&self) -> impl Iterator + '_ { - (0..).map(|i| self.get(i)).take_while(|o| o.is_some()).filter_map(|o| o) + (0..).map(|i| self.get(i)).take_while(|o| o.is_some()).flatten() } } diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 5c2435a0122eb..6c8d541463158 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -224,7 +224,7 @@ impl UnordSet { } #[inline] - pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator> { + pub fn items(&self) -> UnordItems<&V, impl Iterator> { UnordItems(self.inner.iter()) } @@ -415,7 +415,7 @@ impl UnordMap { } #[inline] - pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator> { + pub fn items(&self) -> UnordItems<(&K, &V), impl Iterator> { UnordItems(self.inner.iter()) } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 9ed8ab67431c0..e09ef34b93dbc 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -956,7 +956,7 @@ impl Diagnostic { // Exact iteration order of diagnostic arguments shouldn't make a difference to output because // they're only used in interpolation. #[allow(rustc::potential_query_instability)] - pub fn args<'a>(&'a self) -> impl Iterator> { + pub fn args(&self) -> impl Iterator> { self.args.iter() } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 4b1ff0e1df941..81e8bcbf7cd54 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1407,7 +1407,7 @@ impl EmitterWriter { // Account for newlines to align output to its label. for (line, text) in normalize_whitespace(&text).lines().enumerate() { buffer.append( - 0 + line, + line, &format!( "{}{}", if line == 0 { String::new() } else { " ".repeat(label_width) }, @@ -1918,7 +1918,7 @@ impl EmitterWriter { let last_line = unhighlighted_lines.pop(); let first_line = unhighlighted_lines.drain(..).next(); - first_line.map(|(p, l)| { + if let Some((p, l)) = first_line { self.draw_code_line( &mut buffer, &mut row_num, @@ -1930,12 +1930,12 @@ impl EmitterWriter { &file_lines, is_multiline, ) - }); + } buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber); row_num += 1; - last_line.map(|(p, l)| { + if let Some((p, l)) = last_line { self.draw_code_line( &mut buffer, &mut row_num, @@ -1947,7 +1947,7 @@ impl EmitterWriter { &file_lines, is_multiline, ) - }); + } } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index a78dc0678d5da..4ff8e409d88e3 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -466,7 +466,7 @@ impl<'a> StripUnconfigured<'a> { // // N.B., this is intentionally not part of the visit_expr() function // in order for filter_map_expr() to be able to avoid this check - if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(*a)) { + if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { self.sess.emit_err(RemoveExprNotSupported { span: attr.span }); } diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index de34df0114a74..fb3a00d86d4f7 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -41,7 +41,7 @@ impl MetaVarExpr { }; check_trailing_token(&mut tts, sess)?; let mut iter = args.trees(); - let rslt = match &*ident.as_str() { + let rslt = match ident.as_str() { "count" => parse_count(&mut iter, sess, ident.span)?, "ignore" => MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?), "index" => MetaVarExpr::Index(parse_depth(&mut iter, sess, ident.span)?), diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index eac8fd2942931..8f91a96f964ab 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -49,7 +49,7 @@ impl LanguageItems { self.get(it).ok_or_else(|| LangItemError(it)) } - pub fn iter<'a>(&'a self) -> impl Iterator + 'a { + pub fn iter(&self) -> impl Iterator + '_ { self.items .iter() .enumerate() diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 7bca4edcc8c96..ad76e2bed2023 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -302,7 +302,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { .iter() .flatten() .map(|r| r.impl_blocks.len() as isize - avg as isize) - .map(|v| v.abs() as usize) + .map(|v| v.unsigned_abs()) .sum::(); s / connected_regions.len() }, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 4f27c01fad2c9..74f5b359021d2 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -242,7 +242,7 @@ pub fn enum_def_to_string( impl<'a> State<'a> { pub fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) { self.maybe_print_comment(span.hi()); - self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize)); + self.break_offset_if_not_bol(1, -INDENT_UNIT); self.word("}"); if close_box { self.end(); // close the outer-box diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 035ccf30b2462..6c2ce62722a54 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -538,8 +538,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(rpitit): This will need to be fixed when we move to associated types assert!(matches!( *trait_pred.trait_ref.self_ty().kind(), - ty::Alias(_, ty::AliasTy { def_id, substs, .. }) - if def_id == rpit_def_id && substs == substs + ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) + if def_id == rpit_def_id && substs == alias_substs )); ty::PredicateKind::Clause(ty::Clause::Trait( trait_pred.with_self_ty(self.tcx, ty), @@ -548,8 +548,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => { assert!(matches!( *proj_pred.projection_ty.self_ty().kind(), - ty::Alias(_, ty::AliasTy { def_id, substs, .. }) - if def_id == rpit_def_id && substs == substs + ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) + if def_id == rpit_def_id && substs == alias_substs )); proj_pred = proj_pred.with_self_ty(self.tcx, ty); ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred)) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 7534e432f1198..3e0c2bf2a5538 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -242,8 +242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(arg) = segment .args() .args - .iter() - .nth(index) else { return false; }; + .get(index) else { return false; }; error.obligation.cause.span = arg .span() .find_ancestor_in_same_ctxt(error.obligation.cause.span) diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index 1eeb7d984ee04..3e9a9ce1b3114 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs @@ -526,8 +526,9 @@ impl DropRangesBuilder { let mut next = <_>::from(0u32); for value in tracked_values { for_each_consumable(hir, value, |value| { - if !tracked_value_map.contains_key(&value) { - tracked_value_map.insert(value, next); + if let std::collections::hash_map::Entry::Vacant(e) = tracked_value_map.entry(value) + { + e.insert(next); next = next + 1; } }); diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 84ed8f3780e17..5faa6ab13dd7d 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -313,8 +313,7 @@ pub fn resolve_interior<'a, 'tcx>( // Extract type components to build the witness type. let type_list = fcx.tcx.mk_type_list_from_iter(type_causes.iter().map(|cause| cause.ty)); let bound_vars = fcx.tcx.mk_bound_variable_kinds(&bound_vars); - let witness = - fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone())); + let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars)); drop(typeck_results); // Store the generator types and spans into the typeck results for this generator. diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 4258a100d9866..08cd6085d7f30 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1764,7 +1764,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn probe_for_similar_candidate(&mut self) -> Result, MethodError<'tcx>> { debug!("probing for method names similar to {:?}", self.method_name); - let steps = self.steps.clone(); self.probe(|_| { let mut pcx = ProbeContext::new( self.fcx, @@ -1772,8 +1771,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.mode, self.method_name, self.return_type, - &self.orig_steps_var_values, - steps, + self.orig_steps_var_values, + self.steps, self.scope_expr_id, ); pcx.allow_similar_names = true; diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index eba5b3ed882a1..271ab830694bb 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1850,7 +1850,7 @@ impl SparseBitMatrix { /// Iterates through all the columns set to true in a given row of /// the matrix. - pub fn iter<'a>(&'a self, row: R) -> impl Iterator + 'a { + pub fn iter(&self, row: R) -> impl Iterator + '_ { self.row(row).into_iter().flat_map(|r| r.iter()) } diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 009602382dd07..ae2f52c513e9f 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -201,18 +201,15 @@ impl IndexVec { } #[inline] - pub fn drain<'a, R: RangeBounds>( - &'a mut self, - range: R, - ) -> impl Iterator + 'a { + pub fn drain>(&mut self, range: R) -> impl Iterator + '_ { self.raw.drain(range) } #[inline] - pub fn drain_enumerated<'a, R: RangeBounds>( - &'a mut self, + pub fn drain_enumerated>( + &mut self, range: R, - ) -> impl Iterator + 'a { + ) -> impl Iterator + '_ { let begin = match range.start_bound() { std::ops::Bound::Included(i) => *i, std::ops::Bound::Excluded(i) => i.checked_add(1).unwrap(), diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index a76229dd3524b..a2a7c93a7ca95 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -266,12 +266,12 @@ impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> { let LintExpectationId::Stable { attr_id: Some(attr_id), hir_id, attr_index, .. } = id else { bug!("unstable expectation id should already be mapped") }; let key = LintExpectationId::Unstable { attr_id, lint_index: None }; - if !self.unstable_to_stable_ids.contains_key(&key) { - self.unstable_to_stable_ids.insert( - key, - LintExpectationId::Stable { hir_id, attr_index, lint_index: None, attr_id: None }, - ); - } + self.unstable_to_stable_ids.entry(key).or_insert(LintExpectationId::Stable { + hir_id, + attr_index, + lint_index: None, + attr_id: None, + }); self.expectations.push((id.normalize(), expectation)); } diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 8542dcf5bf0fe..ec3cf34d7109f 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -30,7 +30,7 @@ pub unsafe extern "C" fn LLVMRustStringWriteImpl( ptr: *const c_char, size: size_t, ) { - let slice = slice::from_raw_parts(ptr as *const u8, size as usize); + let slice = slice::from_raw_parts(ptr as *const u8, size); sr.bytes.borrow_mut().extend_from_slice(slice); } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 9b91627883a8d..4540ded0f41a3 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -119,7 +119,7 @@ impl DiagnosticDeriveBuilder { impl<'a> DiagnosticDeriveVariantBuilder<'a> { /// Generates calls to `code` and similar functions based on the attributes on the type or /// variant. - pub fn preamble<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream { + pub fn preamble(&mut self, variant: &VariantInfo<'_>) -> TokenStream { let ast = variant.ast(); let attrs = &ast.attrs; let preamble = attrs.iter().map(|attr| { @@ -133,7 +133,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { /// Generates calls to `span_label` and similar functions based on the attributes on fields or /// calls to `set_arg` when no attributes are present. - pub fn body<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream { + pub fn body(&mut self, variant: &VariantInfo<'_>) -> TokenStream { let mut body = quote! {}; // Generate `set_arg` calls first.. for binding in variant.bindings().iter().filter(|bi| should_generate_set_arg(bi.ast())) { diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index 9f96a04148792..607d51f5608d3 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -100,7 +100,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok Diagnostic::spanned( resource_span, Level::Error, - format!("could not open Fluent resource: {}", e.to_string()), + format!("could not open Fluent resource: {e}"), ) .emit(); return failed(&crate_name); diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 2515269ea2ff2..c6af8d6328983 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -762,14 +762,14 @@ impl<'a> CrateLocator<'a> { } pub(crate) fn into_error(self, root: Option) -> CrateError { - CrateError::LocatorCombined(CombinedLocatorError { + CrateError::LocatorCombined(Box::new(CombinedLocatorError { crate_name: self.crate_name, root, triple: self.triple, dll_prefix: self.target.dll_prefix.to_string(), dll_suffix: self.target.dll_suffix.to_string(), crate_rejections: self.crate_rejections, - }) + })) } } @@ -958,7 +958,7 @@ pub(crate) enum CrateError { StableCrateIdCollision(Symbol, Symbol), DlOpen(String), DlSym(String), - LocatorCombined(CombinedLocatorError), + LocatorCombined(Box), NonDylibPlugin(Symbol), } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 89a485b47ca8c..9d97a75a2fa6f 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -74,18 +74,17 @@ impl<'hir> Iterator for ParentHirIterator<'hir> { if self.current_id == CRATE_HIR_ID { return None; } - loop { - // There are nodes that do not have entries, so we need to skip them. - let parent_id = self.map.parent_id(self.current_id); - if parent_id == self.current_id { - self.current_id = CRATE_HIR_ID; - return None; - } + // There are nodes that do not have entries, so we need to skip them. + let parent_id = self.map.parent_id(self.current_id); - self.current_id = parent_id; - return Some(parent_id); + if parent_id == self.current_id { + self.current_id = CRATE_HIR_ID; + return None; } + + self.current_id = parent_id; + return Some(parent_id); } } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index f668c4e77beae..b5b712c367d08 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -80,6 +80,18 @@ impl CanonicalVarValues<'_> { } }) } + + pub fn is_identity_modulo_regions(&self) -> bool { + self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() { + ty::GenericArgKind::Lifetime(_) => true, + ty::GenericArgKind::Type(ty) => { + matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv) + } + ty::GenericArgKind::Const(ct) => { + matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv) + } + }) + } } /// When we canonicalize a value to form a query, we wind up replacing diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 2f2c7b154165a..1a8e48264471c 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -109,26 +109,34 @@ const MAX_HASHED_BUFFER_LEN: usize = 2 * MAX_BYTES_TO_HASH; // large. impl hash::Hash for Allocation { fn hash(&self, state: &mut H) { + let Self { + bytes, + provenance, + init_mask, + align, + mutability, + extra: (), // don't bother hashing () + } = self; + // Partially hash the `bytes` buffer when it is large. To limit collisions with common // prefixes and suffixes, we hash the length and some slices of the buffer. - let byte_count = self.bytes.len(); + let byte_count = bytes.len(); if byte_count > MAX_HASHED_BUFFER_LEN { // Hash the buffer's length. byte_count.hash(state); // And its head and tail. - self.bytes[..MAX_BYTES_TO_HASH].hash(state); - self.bytes[byte_count - MAX_BYTES_TO_HASH..].hash(state); + bytes[..MAX_BYTES_TO_HASH].hash(state); + bytes[byte_count - MAX_BYTES_TO_HASH..].hash(state); } else { - self.bytes.hash(state); + bytes.hash(state); } // Hash the other fields as usual. - self.provenance.hash(state); - self.init_mask.hash(state); - self.align.hash(state); - self.mutability.hash(state); - self.extra.hash(state); + provenance.hash(state); + init_mask.hash(state); + align.hash(state); + mutability.hash(state); } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0fad30973db71..56755e588cb45 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -915,7 +915,7 @@ pub enum LocalInfo<'tcx> { impl<'tcx> LocalDecl<'tcx> { pub fn local_info(&self) -> &LocalInfo<'tcx> { - &**self.local_info.as_ref().assert_crate_local() + &self.local_info.as_ref().assert_crate_local() } /// Returns `true` only if local is a binding that can itself be diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index b898e85fa71b9..f62853c3e7403 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -133,21 +133,21 @@ impl<'tcx> MirPatch<'tcx> { let mut new_decl = LocalDecl::new(ty, span).internal(); **new_decl.local_info.as_mut().assert_crate_local() = local_info; self.new_locals.push(new_decl); - Local::new(index as usize) + Local::new(index) } pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; self.new_locals.push(LocalDecl::new(ty, span)); - Local::new(index as usize) + Local::new(index) } pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; self.new_locals.push(LocalDecl::new(ty, span).internal()); - Local::new(index as usize) + Local::new(index) } pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 0092401470f56..4f00abf7fabc1 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -98,7 +98,7 @@ impl<'tcx> PlaceTy<'tcx> { ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64), ty::Array(inner, size) if from_end => { let size = size.eval_target_usize(tcx, param_env); - let len = size - (from as u64) - (to as u64); + let len = size - from - to; tcx.mk_array(*inner, len) } _ => bug!("cannot subslice non-array type: `{:?}`", self), diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 62cdf794b1e91..7d247eeb656c2 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -178,17 +178,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // When we yield `B` and call `traverse_successor`, we push `C` to the stack, but // since we've already visited `E`, that child isn't added to the stack. The last // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A] - loop { - let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() { - if let Some(bb) = iter.next() { - bb - } else { - break; - } - } else { - break; - }; - + while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next() { if self.visited.insert(bb) { if let Some(term) = &self.basic_blocks[bb].terminator { self.visit_stack.push((bb, term.successors())); diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 833402abfc479..6a8ae525069c0 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -923,7 +923,7 @@ impl ObjectSafetyViolation { } } ObjectSafetyViolation::SupertraitNonLifetimeBinder(_) => { - format!("where clause cannot reference non-lifetime `for<...>` variables").into() + "where clause cannot reference non-lifetime `for<...>` variables".into() } ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { format!("associated function `{}` has no `self` parameter", name).into() diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 0d6f9813e7673..fef2be133e81f 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -56,9 +56,19 @@ pub enum Certainty { impl Certainty { pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity); - /// When proving multiple goals using **AND**, e.g. nested obligations for an impl, - /// use this function to unify the certainty of these goals - pub fn unify_and(self, other: Certainty) -> Certainty { + /// Use this function to merge the certainty of multiple nested subgoals. + /// + /// Given an impl like `impl Baz for T {}`, we have 2 nested + /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`. + /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in + /// success, we merge these two responses. This results in ambiguity. + /// + /// If we unify ambiguity with overflow, we return overflow. This doesn't matter + /// inside of the solver as we distinguish ambiguity from overflow. It does + /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar` + /// in ambiguity without changing the inference state, we still want to tell the + /// user that `T: Baz` results in overflow. + pub fn unify_with(self, other: Certainty) -> Certainty { match (self, other) { (Certainty::Yes, Certainty::Yes) => Certainty::Yes, (Certainty::Yes, Certainty::Maybe(_)) => other, @@ -105,7 +115,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { type Target = ExternalConstraintsData<'tcx>; fn deref(&self) -> &Self::Target { - &*self.0 + &self.0 } } diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index a7f38884ebcc4..c0e557d480d3d 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -337,7 +337,7 @@ impl ScalarInt { /// Fails if the size of the `ScalarInt` is not equal to `Size { raw: 16 }` /// and returns the `ScalarInt`s size in that case. pub fn try_to_i128(self) -> Result { - self.try_to_int(Size::from_bits(128)).map(|v| i128::try_from(v).unwrap()) + self.try_to_int(Size::from_bits(128)) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2ef6180c4cbd2..c312aaf6819aa 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -924,7 +924,7 @@ impl<'tcx> TyCtxt<'tcx> { crate_name, // Don't print the whole stable crate id. That's just // annoying in debug output. - stable_crate_id.to_u64() >> 8 * 6, + stable_crate_id.to_u64() >> (8 * 6), self.def_path(def_id).to_string_no_crate_verbose() ) } @@ -2379,7 +2379,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> { let map = self.in_scope_traits_map(id.owner)?; let candidates = map.get(&id.local_id)?; - Some(&*candidates) + Some(candidates) } pub fn named_bound_var(self, id: HirId) -> Option { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 0e2e2a956ec7b..5bbd396d6f3b0 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1891,7 +1891,7 @@ impl<'tcx> Ty<'tcx> { // The way we evaluate the `N` in `[T; N]` here only works since we use // `simd_size_and_type` post-monomorphization. It will probably start to ICE // if we use it in generic code. See the `simd-array-trait` ui test. - (f0_len.eval_target_usize(tcx, ParamEnv::empty()) as u64, *f0_elem_ty) + (f0_len.eval_target_usize(tcx, ParamEnv::empty()), *f0_elem_ty) } // Otherwise, the fields of this Adt are the SIMD components (and we assume they // all have the same type). diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 4a7da11a09784..e41d0f7047b3b 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -558,8 +558,8 @@ impl<'a> StringReader<'a> { } if let Some(possible_offset) = possible_offset { - let lo = start + BytePos(possible_offset as u32); - let hi = lo + BytePos(found_terminators as u32); + let lo = start + BytePos(possible_offset); + let hi = lo + BytePos(found_terminators); let span = self.mk_sp(lo, hi); err.span_suggestion( span, diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index d4f971d5bc84f..1f027c08fc3b5 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -336,8 +336,8 @@ const ASCII_ARRAY: &[(&str, &str, Option)] = &[ ("\"", "Quotation Mark", None), ]; -pub(super) fn check_for_substitution<'a>( - reader: &StringReader<'a>, +pub(super) fn check_for_substitution( + reader: &StringReader<'_>, pos: BytePos, ch: char, count: usize, diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 8d0f168e09d7e..f8ef1307c988e 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -53,7 +53,7 @@ impl<'a> Parser<'a> { let snapshot = self.create_snapshot_for_diagnostic(); match self.parse_ty() { Ok(p) => { - if let TyKind::ImplTrait(_, bounds) = &(*p).kind { + if let TyKind::ImplTrait(_, bounds) = &p.kind { let span = impl_span.to(self.token.span.shrink_to_lo()); let mut err = self.struct_span_err( span, diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index 3ac8a852a4e77..29f6a07e81beb 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -136,7 +136,9 @@ where } fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - self.cache.lock().as_ref().map(|value| f(&(), &value.0, value.1)); + if let Some(value) = self.cache.lock().as_ref() { + f(&(), &value.0, value.1) + } } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b3f66c4ba3354..31ac3f1c151ee 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1224,7 +1224,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { lifetime_ribs: Vec::new(), lifetime_elision_candidates: None, current_trait_ref: None, - diagnostic_metadata: Box::new(DiagnosticMetadata::default()), + diagnostic_metadata: Default::default(), // errors at module scope should always be reported in_func_body: false, lifetime_uses: Default::default(), diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 613abaa8e3cd1..acfb36c97d0c6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1426,7 +1426,7 @@ pub fn rustc_short_optgroups() -> Vec { opt::opt_s( "", "edition", - &*EDITION_STRING, + &EDITION_STRING, EDITION_NAME_LIST, ), opt::multi_s( diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 002ae1e3165ac..15e27952cf50f 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -84,12 +84,12 @@ impl SymbolGallery { /// Construct a diagnostic for a language feature error due to the given `span`. /// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`. -pub fn feature_err<'a>( - sess: &'a ParseSess, +pub fn feature_err( + sess: &ParseSess, feature: Symbol, span: impl Into, explain: impl Into, -) -> DiagnosticBuilder<'a, ErrorGuaranteed> { +) -> DiagnosticBuilder<'_, ErrorGuaranteed> { feature_err_issue(sess, feature, span, GateIssue::Language, explain) } @@ -98,20 +98,21 @@ pub fn feature_err<'a>( /// This variant allows you to control whether it is a library or language feature. /// Almost always, you want to use this for a language feature. If so, prefer `feature_err`. #[track_caller] -pub fn feature_err_issue<'a>( - sess: &'a ParseSess, +pub fn feature_err_issue( + sess: &ParseSess, feature: Symbol, span: impl Into, issue: GateIssue, explain: impl Into, -) -> DiagnosticBuilder<'a, ErrorGuaranteed> { +) -> DiagnosticBuilder<'_, ErrorGuaranteed> { let span = span.into(); // Cancel an earlier warning for this same error, if it exists. if let Some(span) = span.primary_span() { - sess.span_diagnostic - .steal_diagnostic(span, StashKey::EarlySyntaxWarning) - .map(|err| err.cancel()); + if let Some(err) = sess.span_diagnostic.steal_diagnostic(span, StashKey::EarlySyntaxWarning) + { + err.cancel() + } } let mut err = sess.create_err(FeatureGateError { span, explain: explain.into() }); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 11cd5811be8b9..aa8859ed1a358 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1353,16 +1353,16 @@ impl Clone for SourceFile { Self { name: self.name.clone(), src: self.src.clone(), - src_hash: self.src_hash.clone(), + src_hash: self.src_hash, external_src: Lock::new(self.external_src.borrow().clone()), - start_pos: self.start_pos.clone(), - end_pos: self.end_pos.clone(), + start_pos: self.start_pos, + end_pos: self.end_pos, lines: Lock::new(self.lines.borrow().clone()), multibyte_chars: self.multibyte_chars.clone(), non_narrow_chars: self.non_narrow_chars.clone(), normalized_pos: self.normalized_pos.clone(), - name_hash: self.name_hash.clone(), - cnum: self.cnum.clone(), + name_hash: self.name_hash, + cnum: self.cnum, } } } @@ -2051,13 +2051,13 @@ pub type FileLinesResult = Result; #[derive(Clone, PartialEq, Eq, Debug)] pub enum SpanLinesError { - DistinctSources(DistinctSources), + DistinctSources(Box), } #[derive(Clone, PartialEq, Eq, Debug)] pub enum SpanSnippetError { IllFormedSpan(Span), - DistinctSources(DistinctSources), + DistinctSources(Box), MalformedForSourcemap(MalformedSourceMapPositions), SourceNotAvailable { filename: FileName }, } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index ee895f53eba9b..88e3674f89943 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -542,10 +542,10 @@ impl SourceMap { let hi = self.lookup_char_pos(sp.hi()); trace!(?hi); if lo.file.start_pos != hi.file.start_pos { - return Err(SpanLinesError::DistinctSources(DistinctSources { + return Err(SpanLinesError::DistinctSources(Box::new(DistinctSources { begin: (lo.file.name.clone(), lo.file.start_pos), end: (hi.file.name.clone(), hi.file.start_pos), - })); + }))); } Ok((lo, hi)) } @@ -603,10 +603,10 @@ impl SourceMap { let local_end = self.lookup_byte_offset(sp.hi()); if local_begin.sf.start_pos != local_end.sf.start_pos { - Err(SpanSnippetError::DistinctSources(DistinctSources { + Err(SpanSnippetError::DistinctSources(Box::new(DistinctSources { begin: (local_begin.sf.name.clone(), local_begin.sf.start_pos), end: (local_end.sf.name.clone(), local_end.sf.start_pos), - })) + }))) } else { self.ensure_source_file_source_present(local_begin.sf.clone()); diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index d4f7ed31b895c..5582d909f6b10 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -324,8 +324,6 @@ impl Abi { impl fmt::Display for Abi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - abi => write!(f, "\"{}\"", abi.name()), - } + write!(f, "\"{}\"", self.name()) } } diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs similarity index 91% rename from compiler/rustc_trait_selection/src/solve/assembly.rs rename to compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 6476da7ba489c..12ee80b6722b1 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -1,11 +1,9 @@ //! Code shared by trait and projection goals for candidate assembly. use super::search_graph::OverflowHandler; -#[cfg(doc)] -use super::trait_goals::structural_traits::*; use super::{EvalCtxt, SolverMode}; +use crate::solve::CanonicalResponseExt; use crate::traits::coherence; -use itertools::Itertools; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; @@ -16,6 +14,8 @@ use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use std::fmt::Debug; +pub(super) mod structural_traits; + /// A candidate is a possible way to prove a goal. /// /// It consists of both the `source`, which describes how that goal would be proven, @@ -547,61 +547,41 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + /// If there are multiple ways to prove a trait or projection goal, we have + /// to somehow try to merge the candidates into one. If that fails, we return + /// ambiguity. #[instrument(level = "debug", skip(self), ret)] pub(super) fn merge_candidates( &mut self, mut candidates: Vec>, ) -> QueryResult<'tcx> { - match candidates.len() { - 0 => return Err(NoSolution), - 1 => return Ok(candidates.pop().unwrap().result), - _ => {} + // First try merging all candidates. This is complete and fully sound. + let responses = candidates.iter().map(|c| c.result).collect::>(); + if let Some(result) = self.try_merge_responses(&responses) { + return Ok(result); } - if candidates.len() > 1 { - let mut i = 0; - 'outer: while i < candidates.len() { - for j in (0..candidates.len()).filter(|&j| i != j) { - if self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j]) - { - debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len()); - candidates.swap_remove(i); - continue 'outer; + // We then check whether we should prioritize `ParamEnv` candidates. + // + // Doing so is incomplete and would therefore be unsound during coherence. + match self.solver_mode() { + SolverMode::Coherence => (), + // Prioritize `ParamEnv` candidates only if they do not guide inference. + // + // This is still incomplete as we may add incorrect region bounds. + SolverMode::Normal => { + let param_env_responses = candidates + .iter() + .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) + .map(|c| c.result) + .collect::>(); + if let Some(result) = self.try_merge_responses(¶m_env_responses) { + if result.has_only_region_constraints() { + return Ok(result); } } - - debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len()); - i += 1; } - - // If there are *STILL* multiple candidates that have *different* response - // results, give up and report ambiguity. - if candidates.len() > 1 && !candidates.iter().map(|cand| cand.result).all_equal() { - let certainty = if candidates.iter().all(|x| { - matches!(x.result.value.certainty, Certainty::Maybe(MaybeCause::Overflow)) - }) { - Certainty::Maybe(MaybeCause::Overflow) - } else { - Certainty::AMBIGUOUS - }; - return self.evaluate_added_goals_and_make_canonical_response(certainty); - } - } - - Ok(candidates.pop().unwrap().result) - } - - fn candidate_should_be_dropped_in_favor_of( - &self, - candidate: &Candidate<'tcx>, - other: &Candidate<'tcx>, - ) -> bool { - // FIXME: implement this - match (candidate.source, other.source) { - (CandidateSource::Impl(_), _) - | (CandidateSource::ParamEnv(_), _) - | (CandidateSource::AliasBound, _) - | (CandidateSource::BuiltinImpl, _) => false, } + self.flounder(&responses) } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs similarity index 94% rename from compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs rename to compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 9e851b788a543..cbec39d82856e 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -11,7 +11,7 @@ use crate::solve::EvalCtxt; // // For types with an "existential" binder, i.e. generator witnesses, we also // instantiate the binder with placeholders eagerly. -pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( +pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, ) -> Result>, NoSolution> { @@ -87,7 +87,7 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( } } -fn replace_erased_lifetimes_with_bound_vars<'tcx>( +pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, ) -> ty::Binder<'tcx, Ty<'tcx>> { @@ -108,7 +108,7 @@ fn replace_erased_lifetimes_with_bound_vars<'tcx>( ty::Binder::bind_with_vars(ty, bound_vars) } -pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( +pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, ) -> Result>, NoSolution> { @@ -158,7 +158,7 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( } } -pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( +pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, ) -> Result>, NoSolution> { @@ -224,7 +224,7 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( } // Returns a binder of the tupled inputs types and output type from a builtin callable type. -pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( +pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>, goal_kind: ty::ClosureKind, @@ -337,7 +337,13 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( /// additional step of eagerly folding the associated types in the where /// clauses of the impl. In this example, that means replacing /// `::Bar` with `Ty` in the first impl. -pub(crate) fn predicates_for_object_candidate<'tcx>( +/// +// FIXME: This is only necessary as `::Assoc: ItemBound` +// bounds in impls are trivially proven using the item bound candidates. +// This is unsound in general and once that is fixed, we don't need to +// normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9 +// for more details. +pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, trait_ref: ty::TraitRef<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index cdbab5bd8d27c..28aca76cceb66 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -357,7 +357,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // deal with `has_changed` in the next iteration. new_goals.normalizes_to_hack_goal = Some(this.resolve_vars_if_possible(goal)); - has_changed = has_changed.map_err(|c| c.unify_and(certainty)); + has_changed = has_changed.map_err(|c| c.unify_with(certainty)); } } } @@ -378,7 +378,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { Certainty::Yes => {} Certainty::Maybe(_) => { new_goals.goals.push(goal); - has_changed = has_changed.map_err(|c| c.unify_and(certainty)); + has_changed = has_changed.map_err(|c| c.unify_with(certainty)); } } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 714b6dfb71761..861fa0a305ac0 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -50,7 +50,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { certainty: Certainty, ) -> QueryResult<'tcx> { let goals_certainty = self.try_evaluate_added_goals()?; - let certainty = certainty.unify_and(goals_certainty); + let certainty = certainty.unify_with(goals_certainty); let external_constraints = self.compute_external_query_constraints()?; diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 9ddae8f8dcd47..19bcbd461447d 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -46,6 +46,8 @@ enum SolverMode { trait CanonicalResponseExt { fn has_no_inference_or_external_constraints(&self) -> bool; + + fn has_only_region_constraints(&self) -> bool; } impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { @@ -54,6 +56,11 @@ impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { && self.value.var_values.is_identity() && self.value.external_constraints.opaque_types.is_empty() } + + fn has_only_region_constraints(&self) -> bool { + self.value.var_values.is_identity_modulo_regions() + && self.value.external_constraints.opaque_types.is_empty() + } } impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { @@ -221,12 +228,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { (Some(alias_lhs), Some(alias_rhs)) => { debug!("both sides are aliases"); - let candidates = vec![ - // LHS normalizes-to RHS - evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No), - // RHS normalizes-to RHS - evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes), - // Relate via substs + let mut candidates = Vec::new(); + // LHS normalizes-to RHS + candidates.extend( + evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No).ok(), + ); + // RHS normalizes-to RHS + candidates.extend( + evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes).ok(), + ); + // Relate via substs + candidates.extend( self.probe(|ecx| { let span = tracing::span!( tracing::Level::DEBUG, @@ -247,11 +259,16 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }), - ]; + }) + .ok(), + ); debug!(?candidates); - self.try_merge_responses(candidates.into_iter()) + if let Some(merged) = self.try_merge_responses(&candidates) { + Ok(merged) + } else { + self.flounder(&candidates) + } } } } @@ -289,43 +306,51 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { debug!("added_goals={:?}", &self.nested_goals.goals[current_len..]); } - #[instrument(level = "debug", skip(self, responses))] + /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`. + /// + /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`. + #[instrument(level = "debug", skip(self), ret)] fn try_merge_responses( &mut self, - responses: impl Iterator>, - ) -> QueryResult<'tcx> { - let candidates = responses.into_iter().flatten().collect::>(); - - if candidates.is_empty() { - return Err(NoSolution); + responses: &[CanonicalResponse<'tcx>], + ) -> Option> { + if responses.is_empty() { + return None; } // FIXME(-Ztrait-solver=next): We should instead try to find a `Certainty::Yes` response with // a subset of the constraints that all the other responses have. - let one = candidates[0]; - if candidates[1..].iter().all(|resp| resp == &one) { - return Ok(one); + let one = responses[0]; + if responses[1..].iter().all(|&resp| resp == one) { + return Some(one); } - if let Some(response) = candidates.iter().find(|response| { - response.value.certainty == Certainty::Yes - && response.has_no_inference_or_external_constraints() - }) { - return Ok(*response); - } + responses + .iter() + .find(|response| { + response.value.certainty == Certainty::Yes + && response.has_no_inference_or_external_constraints() + }) + .copied() + } - let certainty = candidates.iter().fold(Certainty::AMBIGUOUS, |certainty, response| { - certainty.unify_and(response.value.certainty) + /// If we fail to merge responses we flounder and return overflow or ambiguity. + #[instrument(level = "debug", skip(self), ret)] + fn flounder(&mut self, responses: &[CanonicalResponse<'tcx>]) -> QueryResult<'tcx> { + if responses.is_empty() { + return Err(NoSolution); + } + let certainty = responses.iter().fold(Certainty::AMBIGUOUS, |certainty, response| { + certainty.unify_with(response.value.certainty) }); - // FIXME(-Ztrait-solver=next): We should take the intersection of the constraints on all the - // responses and use that for the constraints of this ambiguous response. - debug!(">1 response, bailing with {certainty:?}"); + let response = self.evaluate_added_goals_and_make_canonical_response(certainty); - if let Ok(response) = &response { + if let Ok(response) = response { assert!(response.has_no_inference_or_external_constraints()); + Ok(response) + } else { + bug!("failed to make floundered response: {responses:?}"); } - - response } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index e0a69438dec0e..2a47da81ec760 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -1,7 +1,6 @@ use crate::traits::specialization_graph; -use super::assembly; -use super::trait_goals::structural_traits; +use super::assembly::{self, structural_traits}; use super::EvalCtxt; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index a2203473ca970..81f89fd950c8d 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -1,6 +1,7 @@ //! Dealing with trait goals, i.e. `T: Trait<'a, U>`. -use super::{assembly, EvalCtxt, SolverMode}; +use super::assembly::{self, structural_traits}; +use super::{EvalCtxt, SolverMode}; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; use rustc_infer::traits::query::NoSolution; @@ -11,8 +12,6 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; use rustc_span::DUMMY_SP; -pub mod structural_traits; - impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn self_ty(self) -> Ty<'tcx> { self.self_ty() diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 4b4a8ebd079fc..a93a42987ed53 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -149,7 +149,7 @@ mod rustc { .iter() .enumerate() .find(|(_, field_def)| name == field_def.name) - .expect(&format!("There were no fields named `{name}`.")); + .unwrap_or_else(|| panic!("There were no fields named `{name}`.")); fields[field_idx].unwrap_leaf() == ScalarInt::TRUE }; diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 3f491836551dc..9c6d48675a6b1 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1241,13 +1241,9 @@ impl MaybeUninit { /// ``` #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] pub fn slice_as_bytes(this: &[MaybeUninit]) -> &[MaybeUninit] { + let bytes = mem::size_of_val(this); // SAFETY: MaybeUninit is always valid, even for padding bytes - unsafe { - slice::from_raw_parts( - this.as_ptr() as *const MaybeUninit, - this.len() * mem::size_of::(), - ) - } + unsafe { slice::from_raw_parts(this.as_ptr() as *const MaybeUninit, bytes) } } /// Returns the contents of this mutable slice of `MaybeUninit` as a mutable slice of @@ -1274,13 +1270,9 @@ impl MaybeUninit { /// ``` #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")] pub fn slice_as_bytes_mut(this: &mut [MaybeUninit]) -> &mut [MaybeUninit] { + let bytes = mem::size_of_val(this); // SAFETY: MaybeUninit is always valid, even for padding bytes - unsafe { - slice::from_raw_parts_mut( - this.as_mut_ptr() as *mut MaybeUninit, - this.len() * mem::size_of::(), - ) - } + unsafe { slice::from_raw_parts_mut(this.as_mut_ptr() as *mut MaybeUninit, bytes) } } } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index cd19667139ab6..f9387a0fc80bf 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -271,9 +271,17 @@ impl Step for Rustc { false, ); - let libdir = builder.sysroot_libdir(compiler, target); - let hostdir = builder.sysroot_libdir(compiler, compiler.host); - add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target)); + // HACK: This avoids putting the newly built artifacts in the sysroot if we're using + // `download-rustc`, to avoid "multiple candidates for `rmeta`" errors. Technically, that's + // not quite right: people can set `download-rustc = true` to download even if there are + // changes to the compiler, and in that case ideally we would put the *new* artifacts in the + // sysroot, in case there are API changes that should be used by tools. In practice, + // though, that should be very uncommon, and people can still disable download-rustc. + if !builder.download_rustc() { + let libdir = builder.sysroot_libdir(compiler, target); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target)); + } } } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 735351fbf605f..a7efe16150eae 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -6,6 +6,7 @@ use std::io::BufReader; use std::path::{Path, PathBuf}; use std::process::Command; +use build_helper::ci::CiEnv; use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; @@ -276,8 +277,12 @@ impl TestProps { /// `//[foo]`), then the property is ignored unless `cfg` is /// `Some("foo")`. fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) { - // Mode-dependent defaults. - self.remap_src_base = config.mode == Mode::Ui && !config.suite.contains("rustdoc"); + // In CI, we've sometimes encountered non-determinism related to truncating very long paths. + // Set a consistent (short) prefix to avoid issues, but only in CI to avoid regressing the + // contributor experience. + if CiEnv::is_ci() { + self.remap_src_base = config.mode == Mode::Ui && !config.suite.contains("rustdoc"); + } let mut has_edition = false; if !testfile.is_dir() { diff --git a/tests/codegen/intrinsics/transmute-x64.rs b/tests/codegen/intrinsics/transmute-x64.rs new file mode 100644 index 0000000000000..99d258c62040f --- /dev/null +++ b/tests/codegen/intrinsics/transmute-x64.rs @@ -0,0 +1,35 @@ +// compile-flags: -O -C no-prepopulate-passes +// only-x86_64 (it's using arch-specific types) +// min-llvm-version: 15.0 # this test assumes `ptr`s + +#![crate_type = "lib"] + +use std::arch::x86_64::{__m128, __m128i, __m256i}; +use std::mem::transmute; + +// CHECK-LABEL: @check_sse_float_to_int( +#[no_mangle] +pub unsafe fn check_sse_float_to_int(x: __m128) -> __m128i { + // CHECK-NOT: alloca + // CHECK: %1 = load <4 x float>, ptr %x, align 16 + // CHECK: store <4 x float> %1, ptr %0, align 16 + transmute(x) +} + +// CHECK-LABEL: @check_sse_pair_to_avx( +#[no_mangle] +pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i { + // CHECK-NOT: alloca + // CHECK: %1 = load <4 x i64>, ptr %x, align 16 + // CHECK: store <4 x i64> %1, ptr %0, align 32 + transmute(x) +} + +// CHECK-LABEL: @check_sse_pair_from_avx( +#[no_mangle] +pub unsafe fn check_sse_pair_from_avx(x: __m256i) -> (__m128i, __m128i) { + // CHECK-NOT: alloca + // CHECK: %1 = load <4 x i64>, ptr %x, align 32 + // CHECK: store <4 x i64> %1, ptr %0, align 16 + transmute(x) +} diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index 7ad0e62213cb2..57f901c671992 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -8,7 +8,7 @@ #![feature(inline_const)] #![allow(unreachable_code)] -use std::mem::transmute; +use std::mem::{transmute, MaybeUninit}; // Some of the cases here are statically rejected by `mem::transmute`, so // we need to generate custom MIR for those cases to get to codegen. @@ -54,6 +54,32 @@ pub unsafe fn check_smaller_size(x: u32) -> u16 { } } +// CHECK-LABEL: @check_smaller_array( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_bigger_array( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + // CHECK-LABEL: @check_to_uninhabited( #[no_mangle] #[custom_mir(dialect = "runtime", phase = "initial")] @@ -71,7 +97,7 @@ pub unsafe fn check_to_uninhabited(x: u16) -> BigNever { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "initial")] pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { - // CHECK: call void @llvm.trap + // CHECK: ret i16 poison mir!{ { RET = CastTransmute(x); @@ -301,3 +327,105 @@ pub unsafe fn check_pair_to_array(x: (i64, u64)) -> [u8; 16] { // CHECK: store i64 %x.1, ptr %{{.+}}, align 1 transmute(x) } + +// CHECK-LABEL: @check_heterogeneous_integer_pair( +#[no_mangle] +pub unsafe fn check_heterogeneous_integer_pair(x: (i32, bool)) -> (bool, u32) { + // CHECK: store i32 %x.0 + // CHECK: %[[WIDER:.+]] = zext i1 %x.1 to i8 + // CHECK: store i8 %[[WIDER]] + + // CHECK: %[[BYTE:.+]] = load i8 + // CHECK: trunc i8 %[[BYTE:.+]] to i1 + // CHECK: load i32 + transmute(x) +} + +// CHECK-LABEL: @check_heterogeneous_float_pair( +#[no_mangle] +pub unsafe fn check_heterogeneous_float_pair(x: (f64, f32)) -> (f32, f64) { + // CHECK: store double %x.0 + // CHECK: store float %x.1 + // CHECK: %[[A:.+]] = load float + // CHECK: %[[B:.+]] = load double + // CHECK: %[[P:.+]] = insertvalue { float, double } poison, float %[[A]], 0 + // CHECK: insertvalue { float, double } %[[P]], double %[[B]], 1 + transmute(x) +} + +// CHECK-LABEL: @check_issue_110005( +#[no_mangle] +pub unsafe fn check_issue_110005(x: (usize, bool)) -> Option> { + // CHECK: store i64 %x.0 + // CHECK: %[[WIDER:.+]] = zext i1 %x.1 to i8 + // CHECK: store i8 %[[WIDER]] + // CHECK: load ptr + // CHECK: load i64 + transmute(x) +} + +// CHECK-LABEL: @check_pair_to_dst_ref( +#[no_mangle] +pub unsafe fn check_pair_to_dst_ref<'a>(x: (usize, usize)) -> &'a [u8] { + // CHECK: %0 = inttoptr i64 %x.0 to ptr + // CHECK: %1 = insertvalue { ptr, i64 } poison, ptr %0, 0 + // CHECK: %2 = insertvalue { ptr, i64 } %1, i64 %x.1, 1 + // CHECK: ret { ptr, i64 } %2 + transmute(x) +} + +// CHECK-LABEL: @check_issue_109992( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub unsafe fn check_issue_109992(x: ()) -> [(); 1] { + // This uses custom MIR to avoid MIR optimizations having removed ZST ops. + + // CHECK: start + // CHECK-NEXT: ret void + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_maybe_uninit_pair(i16 %x.0, i64 %x.1) +#[no_mangle] +pub unsafe fn check_maybe_uninit_pair( + x: (MaybeUninit, MaybeUninit), +) -> (MaybeUninit, MaybeUninit) { + // Thanks to `MaybeUninit` this is actually defined behaviour, + // unlike the examples above with pairs of primitives. + + // CHECK: store i16 %x.0 + // CHECK: store i64 %x.1 + // CHECK: load i64 + // CHECK-NOT: noundef + // CHECK: load i16 + // CHECK-NOT: noundef + // CHECK: ret { i64, i16 } + transmute(x) +} + +#[repr(align(8))] +pub struct HighAlignScalar(u8); + +// CHECK-LABEL: @check_to_overalign( +#[no_mangle] +pub unsafe fn check_to_overalign(x: u64) -> HighAlignScalar { + // CHECK: %0 = alloca %HighAlignScalar, align 8 + // CHECK: store i64 %x, ptr %0, align 8 + // CHECK: %1 = load i64, ptr %0, align 8 + // CHECK: ret i64 %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_overalign( +#[no_mangle] +pub unsafe fn check_from_overalign(x: HighAlignScalar) -> u64 { + // CHECK: %x = alloca %HighAlignScalar, align 8 + // CHECK: %[[VAL:.+]] = load i64, ptr %x, align 8 + // CHECK: ret i64 %[[VAL]] + transmute(x) +} diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr b/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr new file mode 100644 index 0000000000000..bcb201bf0c379 --- /dev/null +++ b/tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr @@ -0,0 +1,18 @@ +error[E0282]: type annotations needed + --> $DIR/issue-95230.rs:9:13 + | +LL | for<'a> &'a mut Self:; + | ^^^^^^^^^^^^ cannot infer type for mutable reference `&'a mut Bar` + | +note: required by a bound in `Bar` + --> $DIR/issue-95230.rs:9:13 + | +LL | pub struct Bar + | --- required by a bound in this struct +LL | where +LL | for<'a> &'a mut Self:; + | ^^^^^^^^^^^^ required by this bound in `Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.rs b/tests/ui/higher-rank-trait-bounds/issue-95230.rs index 92c506eabb7f4..769b6a9253769 100644 --- a/tests/ui/higher-rank-trait-bounds/issue-95230.rs +++ b/tests/ui/higher-rank-trait-bounds/issue-95230.rs @@ -1,4 +1,8 @@ -// check-pass +// revisions: old new +//[new] compile-flags: -Ztrait-solver=next +//[old] check-pass +//[new] known-bug: #109764 + pub struct Bar where diff --git a/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs b/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs index fd5d0e3b1946e..531203d9c64f7 100644 --- a/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs +++ b/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs @@ -1,7 +1,7 @@ // compile-flags: -Ztrait-solver=next // check that when computing `alias-eq(<() as Foo>::Assoc, <() as Foo>::Assoc)` -// we do not infer `?0 = u8` via the `for (): Foo` impl or `?0 = u16` by +// we do not infer `?0 = u8` via the `for (): Foo` impl or `?0 = u16` by // relating substs as either could be a valid solution. trait Foo { diff --git a/tests/ui/traits/new-solver/prefer-candidate-no-constraints.rs b/tests/ui/traits/new-solver/prefer-candidate-no-constraints.rs new file mode 100644 index 0000000000000..6f8164f3a40f0 --- /dev/null +++ b/tests/ui/traits/new-solver/prefer-candidate-no-constraints.rs @@ -0,0 +1,22 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +trait Foo {} + +impl Foo for T {} + +trait Bar {} + +struct Wrapper<'a, T>(&'a T); + +impl<'a, T> Bar for Wrapper<'a, T> where &'a T: Foo {} +// We need to satisfy `&'a T: Foo` when checking that this impl is WF +// that can either be satisfied via the param-env, or via an impl. +// +// When satisfied via the param-env, since each lifetime is canonicalized +// separately, we end up getting extra region constraints. +// +// However, when satisfied via the impl, there are no region constraints, +// and we can short-circuit a response with no external constraints. + +fn main() {} diff --git a/tests/ui/traits/new-solver/prefer-param-env-on-ambiguity.rs b/tests/ui/traits/new-solver/prefer-param-env-on-ambiguity.rs new file mode 100644 index 0000000000000..909b33ec3d5a5 --- /dev/null +++ b/tests/ui/traits/new-solver/prefer-param-env-on-ambiguity.rs @@ -0,0 +1,10 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +trait Foo<'a> {} +trait Bar<'a> {} + +impl<'a, T: Bar<'a>> Foo<'a> for T {} +impl Bar<'static> for T {} + +fn main() {} diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr index 29cfa47a1050a..e3a92e85e17e4 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr +++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr @@ -1,9 +1,16 @@ -error[E0282]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `::Assoc1: Bar` --> $DIR/recursive-self-normalization-2.rs:15:5 | LL | needs_bar::(); - | ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `S` declared on the function `needs_bar` + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: cannot satisfy `::Assoc1: Bar` +note: required by a bound in `needs_bar` + --> $DIR/recursive-self-normalization-2.rs:12:17 + | +LL | fn needs_bar() {} + | ^^^ required by this bound in `needs_bar` error: aborting due to previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.stderr b/tests/ui/traits/new-solver/recursive-self-normalization.stderr index ba39981893d44..773007aebaa63 100644 --- a/tests/ui/traits/new-solver/recursive-self-normalization.stderr +++ b/tests/ui/traits/new-solver/recursive-self-normalization.stderr @@ -1,9 +1,16 @@ -error[E0282]: type annotations needed +error[E0283]: type annotations needed: cannot satisfy `::Assoc: Bar` --> $DIR/recursive-self-normalization.rs:11:5 | LL | needs_bar::(); - | ^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `S` declared on the function `needs_bar` + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: cannot satisfy `::Assoc: Bar` +note: required by a bound in `needs_bar` + --> $DIR/recursive-self-normalization.rs:8:17 + | +LL | fn needs_bar() {} + | ^^^ required by this bound in `needs_bar` error: aborting due to previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0283`.