diff --git a/Cargo.lock b/Cargo.lock index 6c378cd7406e..9d1481ec768d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -638,7 +638,7 @@ dependencies = [ "filetime", "futures", "if_chain", - "itertools 0.12.1", + "itertools", "parking_lot", "quote", "regex", @@ -670,7 +670,7 @@ dependencies = [ "aho-corasick", "clap", "indoc", - "itertools 0.12.1", + "itertools", "opener 0.6.1", "shell-escape", "walkdir", @@ -685,7 +685,7 @@ dependencies = [ "clippy_config", "clippy_utils", "declare_clippy_lint", - "itertools 0.12.1", + "itertools", "quine-mc_cluskey", "regex", "regex-syntax 0.8.4", @@ -707,7 +707,7 @@ version = "0.1.81" dependencies = [ "arrayvec", "clippy_config", - "itertools 0.12.1", + "itertools", "rustc-semver", "rustc_apfloat", ] @@ -1026,7 +1026,7 @@ dependencies = [ name = "declare_clippy_lint" version = "0.1.81" dependencies = [ - "itertools 0.12.1", + "itertools", "quote", "syn 2.0.66", ] @@ -1133,16 +1133,16 @@ version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" dependencies = [ - "dirs-sys 0.4.1", + "dirs-sys", ] [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "dirs-sys 0.3.7", + "dirs-sys", ] [[package]] @@ -1155,17 +1155,6 @@ dependencies = [ "dirs-sys-next", ] -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "dirs-sys" version = "0.4.1" @@ -2076,15 +2065,6 @@ version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.1" @@ -2227,7 +2207,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -3665,7 +3645,7 @@ dependencies = [ name = "rustc_ast_passes" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_ast", "rustc_ast_pretty", "rustc_attr", @@ -3685,7 +3665,7 @@ dependencies = [ name = "rustc_ast_pretty" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_ast", "rustc_lexer", "rustc_span", @@ -3726,7 +3706,7 @@ name = "rustc_borrowck" version = "0.0.0" dependencies = [ "either", - "itertools 0.12.1", + "itertools", "polonius-engine", "rustc_data_structures", "rustc_errors", @@ -3779,7 +3759,7 @@ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ "bitflags 2.5.0", - "itertools 0.12.1", + "itertools", "libc", "measureme", "object 0.32.2", @@ -3818,7 +3798,7 @@ dependencies = [ "bitflags 2.5.0", "cc", "either", - "itertools 0.12.1", + "itertools", "jobserver", "libc", "object 0.32.2", @@ -4098,7 +4078,7 @@ dependencies = [ name = "rustc_hir_analysis" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_arena", "rustc_ast", "rustc_attr", @@ -4137,7 +4117,7 @@ dependencies = [ name = "rustc_hir_typeck" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_ast", "rustc_ast_ir", "rustc_attr", @@ -4421,7 +4401,7 @@ dependencies = [ name = "rustc_mir_build" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_apfloat", "rustc_arena", "rustc_ast", @@ -4468,7 +4448,7 @@ name = "rustc_mir_transform" version = "0.0.0" dependencies = [ "either", - "itertools 0.12.1", + "itertools", "rustc_arena", "rustc_ast", "rustc_attr", @@ -4762,6 +4742,7 @@ dependencies = [ name = "rustc_span" version = "0.0.0" dependencies = [ + "derivative", "indexmap", "itoa", "md-5", @@ -4823,7 +4804,7 @@ version = "0.0.0" dependencies = [ "bitflags 2.5.0", "derivative", - "itertools 0.12.1", + "itertools", "rustc_ast", "rustc_ast_ir", "rustc_attr", @@ -4866,7 +4847,7 @@ dependencies = [ name = "rustc_transmute" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_ast_ir", "rustc_data_structures", "rustc_hir", @@ -4882,7 +4863,7 @@ dependencies = [ name = "rustc_ty_utils" version = "0.0.0" dependencies = [ - "itertools 0.12.1", + "itertools", "rustc_ast_ir", "rustc_data_structures", "rustc_errors", @@ -4946,7 +4927,7 @@ dependencies = [ "base64", "expect-test", "indexmap", - "itertools 0.12.1", + "itertools", "minifier", "regex", "rustdoc-json-types", @@ -5027,20 +5008,19 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.7.0" +version = "1.7.1" dependencies = [ "annotate-snippets 0.9.2", "anyhow", "bytecount", - "cargo_metadata 0.15.4", + "cargo_metadata 0.18.1", "clap", "clap-cargo", "diff", "dirs", "getopts", "ignore", - "itertools 0.11.0", - "lazy_static", + "itertools", "regex", "rustfmt-config_proc_macro", "serde", @@ -5699,6 +5679,7 @@ name = "tidy" version = "0.1.0" dependencies = [ "cargo_metadata 0.15.4", + "fluent-syntax", "ignore", "miropt-test-tools", "regex", diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 7d81e45d314d..52164d6ef164 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -78,7 +78,7 @@ ast_lowering_inline_asm_unsupported_target = ast_lowering_invalid_abi = invalid ABI: found `{$abi}` .label = invalid ABI - .note = invoke `{$command}` for a full list of supported calling conventions. + .note = invoke `{$command}` for a full list of supported calling conventions ast_lowering_invalid_abi_clobber_abi = invalid ABI for `clobber_abi` diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 2626631d8004..fff1bcd72bce 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -30,6 +30,9 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic +ast_passes_bare_fn_invalid_safety = function pointers cannot be declared with `safe` safety qualifier + .suggestion = remove safe from this item + ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block .cannot_have = cannot have a body .invalid = the invalid body @@ -167,6 +170,9 @@ ast_passes_invalid_unnamed_field_ty = unnamed fields can only have struct or union types .label = not a struct or union +ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier + .suggestion = remove safe from this item + ast_passes_item_underscore = `{$kind}` items in this context need a name .label = `_` is not a valid name for this `{$kind}` item diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index cad1fc79d7f4..e89b412687d9 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -456,15 +456,29 @@ impl<'a> AstValidator<'a> { } } - fn check_foreign_item_safety(&self, item_span: Span, safety: Safety) { - if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) - && (self.extern_mod_safety == Some(Safety::Default) - || !self.features.unsafe_extern_blocks) - { - self.dcx().emit_err(errors::InvalidSafetyOnExtern { - item_span, - block: self.current_extern_span(), - }); + fn check_item_safety(&self, span: Span, safety: Safety) { + match self.extern_mod_safety { + Some(extern_safety) => { + if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) + && (extern_safety == Safety::Default || !self.features.unsafe_extern_blocks) + { + self.dcx().emit_err(errors::InvalidSafetyOnExtern { + item_span: span, + block: self.current_extern_span(), + }); + } + } + None => { + if matches!(safety, Safety::Safe(_)) { + self.dcx().emit_err(errors::InvalidSafetyOnItem { span }); + } + } + } + } + + fn check_bare_fn_safety(&self, span: Span, safety: Safety) { + if matches!(safety, Safety::Safe(_)) { + self.dcx().emit_err(errors::InvalidSafetyOnBareFn { span }); } } @@ -746,6 +760,7 @@ impl<'a> AstValidator<'a> { fn visit_ty_common(&mut self, ty: &'a Ty) { match &ty.kind { TyKind::BareFn(bfty) => { + self.check_bare_fn_safety(bfty.decl_span, bfty.safety); self.check_fn_decl(&bfty.decl, SelfSemantic::No); Self::check_decl_no_pat(&bfty.decl, |span, _, _| { self.dcx().emit_err(errors::PatternFnPointer { span }); @@ -1174,11 +1189,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } } - ItemKind::Static(box StaticItem { expr: None, .. }) => { - self.dcx().emit_err(errors::StaticWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - }); + ItemKind::Static(box StaticItem { expr, safety, .. }) => { + self.check_item_safety(item.span, *safety); + + if expr.is_none() { + self.dcx().emit_err(errors::StaticWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } } ItemKind::TyAlias( ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. }, @@ -1212,7 +1231,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { match &fi.kind { ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => { - self.check_foreign_item_safety(fi.span, sig.header.safety); self.check_defaultness(fi.span, *defaultness); self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); self.check_foreign_fn_headerless(sig.header); @@ -1233,7 +1251,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_item_ascii_only(fi.ident); } ForeignItemKind::Static(box StaticItem { expr, safety, .. }) => { - self.check_foreign_item_safety(fi.span, *safety); + self.check_item_safety(fi.span, *safety); self.check_foreign_kind_bodyless(fi.ident, "static", expr.as_ref().map(|b| b.span)); self.check_foreign_item_ascii_only(fi.ident); } @@ -1453,6 +1471,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }; self.check_fn_decl(fk.decl(), self_semantic); + if let Some(&FnHeader { safety, .. }) = fk.header() { + self.check_item_safety(span, safety); + } + self.check_c_variadic_type(fk); // Functions cannot both be `const async` or `const gen` diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 601910ded208..96c476b271c6 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -225,6 +225,20 @@ pub struct InvalidSafetyOnExtern { pub block: Span, } +#[derive(Diagnostic)] +#[diag(ast_passes_item_invalid_safety)] +pub struct InvalidSafetyOnItem { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_bare_fn_invalid_safety)] +pub struct InvalidSafetyOnBareFn { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(ast_passes_bound_in_context)] pub struct BoundInContext<'a> { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 40b585005982..bf1c1b1433ea 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1110,7 +1110,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { tcx: TyCtxt<'tcx>, } impl<'tcx> ty::TypeFolder> for OpaqueFolder<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 60e63b956db6..597ebd973656 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, span_bug, ty::Instance}; -use rustc_span::{Pos, Span}; +use rustc_span::{sym, Pos, Span, Symbol}; use rustc_target::abi::*; use rustc_target::asm::*; use tracing::debug; @@ -64,7 +64,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let mut layout = None; let ty = if let Some(ref place) = place { layout = Some(&place.layout); - llvm_fixup_output_type(self.cx, reg.reg_class(), &place.layout) + llvm_fixup_output_type(self.cx, reg.reg_class(), &place.layout, instance) } else if matches!( reg.reg_class(), InlineAsmRegClass::X86( @@ -112,7 +112,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { // so we just use the type of the input. &in_value.layout }; - let ty = llvm_fixup_output_type(self.cx, reg.reg_class(), layout); + let ty = llvm_fixup_output_type(self.cx, reg.reg_class(), layout, instance); output_types.push(ty); op_idx.insert(idx, constraints.len()); let prefix = if late { "=" } else { "=&" }; @@ -127,8 +127,13 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { for (idx, op) in operands.iter().enumerate() { match *op { InlineAsmOperandRef::In { reg, value } => { - let llval = - llvm_fixup_input(self, value.immediate(), reg.reg_class(), &value.layout); + let llval = llvm_fixup_input( + self, + value.immediate(), + reg.reg_class(), + &value.layout, + instance, + ); inputs.push(llval); op_idx.insert(idx, constraints.len()); constraints.push(reg_to_llvm(reg, Some(&value.layout))); @@ -139,6 +144,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { in_value.immediate(), reg.reg_class(), &in_value.layout, + instance, ); inputs.push(value); @@ -341,7 +347,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } else { self.extract_value(result, op_idx[&idx] as u64) }; - let value = llvm_fixup_output(self, value, reg.reg_class(), &place.layout); + let value = + llvm_fixup_output(self, value, reg.reg_class(), &place.layout, instance); OperandValue::Immediate(value).store(self, place); } } @@ -913,12 +920,22 @@ fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Ty } } +fn any_target_feature_enabled( + cx: &CodegenCx<'_, '_>, + instance: Instance<'_>, + features: &[Symbol], +) -> bool { + let enabled = cx.tcx.asm_target_features(instance.def_id()); + features.iter().any(|feat| enabled.contains(feat)) +} + /// Fix up an input value to work around LLVM bugs. fn llvm_fixup_input<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, mut value: &'ll Value, reg: InlineAsmRegClass, layout: &TyAndLayout<'tcx>, + instance: Instance<'_>, ) -> &'ll Value { let dl = &bx.tcx.data_layout; match (reg, layout.abi) { @@ -1020,6 +1037,19 @@ fn llvm_fixup_input<'ll, 'tcx>( value } } + ( + InlineAsmRegClass::Arm( + ArmInlineAsmRegClass::dreg + | ArmInlineAsmRegClass::dreg_low8 + | ArmInlineAsmRegClass::dreg_low16 + | ArmInlineAsmRegClass::qreg + | ArmInlineAsmRegClass::qreg_low4 + | ArmInlineAsmRegClass::qreg_low8, + ), + Abi::Vector { element, count: count @ (4 | 8) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) + } (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. @@ -1029,6 +1059,16 @@ fn llvm_fixup_input<'ll, 'tcx>( _ => value, } } + (InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) + && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => + { + // Smaller floats are always "NaN-boxed" inside larger floats on RISC-V. + let value = bx.bitcast(value, bx.type_i16()); + let value = bx.zext(value, bx.type_i32()); + let value = bx.or(value, bx.const_u32(0xFFFF_0000)); + bx.bitcast(value, bx.type_f32()) + } _ => value, } } @@ -1039,6 +1079,7 @@ fn llvm_fixup_output<'ll, 'tcx>( mut value: &'ll Value, reg: InlineAsmRegClass, layout: &TyAndLayout<'tcx>, + instance: Instance<'_>, ) -> &'ll Value { match (reg, layout.abi) { (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { @@ -1130,6 +1171,19 @@ fn llvm_fixup_output<'ll, 'tcx>( value } } + ( + InlineAsmRegClass::Arm( + ArmInlineAsmRegClass::dreg + | ArmInlineAsmRegClass::dreg_low8 + | ArmInlineAsmRegClass::dreg_low16 + | ArmInlineAsmRegClass::qreg + | ArmInlineAsmRegClass::qreg_low4 + | ArmInlineAsmRegClass::qreg_low8, + ), + Abi::Vector { element, count: count @ (4 | 8) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) + } (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. @@ -1140,6 +1194,14 @@ fn llvm_fixup_output<'ll, 'tcx>( _ => value, } } + (InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) + && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => + { + let value = bx.bitcast(value, bx.type_i32()); + let value = bx.trunc(value, bx.type_i16()); + bx.bitcast(value, bx.type_f16()) + } _ => value, } } @@ -1149,6 +1211,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass, layout: &TyAndLayout<'tcx>, + instance: Instance<'_>, ) -> &'ll Type { match (reg, layout.abi) { (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { @@ -1233,6 +1296,19 @@ fn llvm_fixup_output_type<'ll, 'tcx>( layout.llvm_type(cx) } } + ( + InlineAsmRegClass::Arm( + ArmInlineAsmRegClass::dreg + | ArmInlineAsmRegClass::dreg_low8 + | ArmInlineAsmRegClass::dreg_low16 + | ArmInlineAsmRegClass::qreg + | ArmInlineAsmRegClass::qreg_low4 + | ArmInlineAsmRegClass::qreg_low8, + ), + Abi::Vector { element, count: count @ (4 | 8) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + cx.type_vector(cx.type_i16(), count) + } (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. @@ -1242,6 +1318,12 @@ fn llvm_fixup_output_type<'ll, 'tcx>( _ => layout.llvm_type(cx), } } + (InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + if s.primitive() == Primitive::Float(Float::F16) + && !any_target_feature_enabled(cx, instance, &[sym::zfhmin, sym::zfh]) => + { + cx.type_f32() + } _ => layout.llvm_type(cx), } } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 1a7e5bd70921..1476fe285ef5 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -341,8 +341,7 @@ const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in const_eval_unallowed_heap_allocations = allocations are not allowed in {const_eval_const_context}s .label = allocation not allowed in {const_eval_const_context}s - .teach_note = - The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. + .teach_note = The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time. const_eval_unallowed_inline_asm = inline assembly is not allowed in {const_eval_const_context}s diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 9a26ac04b85a..9d0c49082256 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -630,6 +630,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + /// Gives raw, immutable access to the `Allocation` address, without bounds or alignment checks. + /// The caller is responsible for calling the access hooks! + pub fn get_alloc_bytes_unchecked_raw(&self, id: AllocId) -> InterpResult<'tcx, *const u8> { + let alloc = self.get_alloc_raw(id)?; + Ok(alloc.get_bytes_unchecked_raw()) + } + /// Bounds-checked *but not align-checked* allocation access. pub fn get_ptr_alloc<'a>( &'a self, @@ -713,6 +720,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok((alloc, &mut self.machine)) } + /// Gives raw, mutable access to the `Allocation` address, without bounds or alignment checks. + /// The caller is responsible for calling the access hooks! + pub fn get_alloc_bytes_unchecked_raw_mut( + &mut self, + id: AllocId, + ) -> InterpResult<'tcx, *mut u8> { + let alloc = self.get_alloc_raw_mut(id)?.0; + Ok(alloc.get_bytes_unchecked_raw_mut()) + } + /// Bounds-checked *but not align-checked* allocation access. pub fn get_ptr_alloc_mut<'a>( &'a mut self, diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 08d3165867c1..baaee67e7871 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -441,7 +441,7 @@ where /// Take an operand, representing a pointer, and dereference it to a place. /// Corresponds to the `*` operator in Rust. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] pub fn deref_pointer( &self, src: &impl Readable<'tcx, M::Provenance>, @@ -533,7 +533,7 @@ where /// Computes a place. You should only use this if you intend to write into this /// place; for reading, a more efficient alternative is `eval_place_to_op`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] pub fn eval_place( &self, mir_place: mir::Place<'tcx>, @@ -570,7 +570,7 @@ where /// Write an immediate to a place #[inline(always)] - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] pub fn write_immediate( &mut self, src: Immediate, @@ -808,7 +808,7 @@ where /// Copies the data from an operand to a place. /// `allow_transmute` indicates whether the layouts may disagree. #[inline(always)] - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] fn copy_op_inner( &mut self, src: &impl Readable<'tcx, M::Provenance>, @@ -837,7 +837,7 @@ where /// `allow_transmute` indicates whether the layouts may disagree. /// Also, if you use this you are responsible for validating that things get copied at the /// right type. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] fn copy_op_no_validate( &mut self, src: &impl Readable<'tcx, M::Provenance>, @@ -914,7 +914,7 @@ where /// If the place currently refers to a local that doesn't yet have a matching allocation, /// create such an allocation. /// This is essentially `force_to_memplace`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] pub fn force_allocation( &mut self, place: &PlaceTy<'tcx, M::Provenance>, diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 245deda50d5c..7405705dd337 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1905,7 +1905,7 @@ impl HumanEmitter { // // LL | this line was highlighted // LL | this line is just for context - // ... + // ... // LL | this line is just for context // LL | this line was highlighted _ => { @@ -1926,7 +1926,7 @@ impl HumanEmitter { ) } - buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber); + buffer.puts(row_num, 0, "...", Style::LineNumber); row_num += 1; if let Some((p, l)) = last_line { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c165620f657b..9e2756f07ede 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1088,6 +1088,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ErrorFollowing, EncodeCrossCrate::No, "the `#[custom_mir]` attribute is just used for the Rust test suite", ), + rustc_attr!( + TEST, rustc_dump_item_bounds, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No + ), + rustc_attr!( + TEST, rustc_dump_predicates, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::No + ), rustc_attr!( TEST, rustc_object_lifetime_default, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 45527bec2f2e..fbd67657e3b4 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -449,7 +449,7 @@ declare_features! ( /// Allows `dyn* Trait` objects. (incomplete, dyn_star, "1.65.0", Some(102425)), /// Uses generic effect parameters for ~const bounds - (unstable, effects, "1.72.0", Some(102090)), + (incomplete, effects, "1.72.0", Some(102090)), /// Allows exhaustive pattern matching on types that contain uninhabited types. (unstable, exhaustive_patterns, "1.13.0", Some(51085)), /// Allows explicit tail calls via `become` expression. diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 8c740d87e953..7ed32fb9d9f3 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -194,7 +194,7 @@ hir_analysis_inherent_ty_outside = cannot define inherent `impl` for a type outs .span_help = alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items hir_analysis_inherent_ty_outside_new = cannot define inherent `impl` for a type outside of the crate where the type is defined - .label = impl for type defined outside of crate. + .label = impl for type defined outside of crate .note = define and implement a trait or new type instead hir_analysis_inherent_ty_outside_primitive = cannot define inherent `impl` for primitive types outside of `core` @@ -510,7 +510,7 @@ hir_analysis_ty_param_some = type parameter `{$param}` must be used as the type .note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local .only_note = only traits defined in the current crate can be implemented for a type parameter -hir_analysis_type_of = {$type_of} +hir_analysis_type_of = {$ty} hir_analysis_typeof_reserved_keyword_used = `typeof` is a reserved keyword but unimplemented @@ -544,7 +544,7 @@ hir_analysis_unrecognized_intrinsic_function = hir_analysis_unused_associated_type_bounds = unnecessary associated type bound for not object safe associated type - .note = this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`. + .note = this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized` .suggestion = remove this bound hir_analysis_unused_generic_parameter = @@ -566,7 +566,7 @@ hir_analysis_value_of_associated_struct_already_specified = hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions} .label = C-variadic function must have a compatible calling convention -hir_analysis_variances_of = {$variances_of} +hir_analysis_variances_of = {$variances} hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause .label = `main` cannot have a `where` clause diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 82b57cdd1069..550f38af8b5d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -397,7 +397,7 @@ struct RemapLateBound<'a, 'tcx> { } impl<'tcx> TypeFolder> for RemapLateBound<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -790,13 +790,13 @@ impl<'tcx, E> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx, E where E: 'tcx, { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.ocx.infcx.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if let ty::Alias(ty::Projection, proj) = ty.kind() - && self.interner().is_impl_trait_in_trait(proj.def_id) + && self.cx().is_impl_trait_in_trait(proj.def_id) { if let Some((ty, _)) = self.types.get(&proj.def_id) { return *ty; @@ -810,9 +810,9 @@ where self.types.insert(proj.def_id, (infer_ty, proj.args)); // Recurse into bounds for (pred, pred_span) in self - .interner() + .cx() .explicit_item_bounds(proj.def_id) - .iter_instantiated_copied(self.interner(), proj.args) + .iter_instantiated_copied(self.cx(), proj.args) { let pred = pred.fold_with(self); let pred = self.ocx.normalize( @@ -822,7 +822,7 @@ where ); self.ocx.register_obligation(traits::Obligation::new( - self.interner(), + self.cx(), ObligationCause::new( self.span, self.body_id, @@ -853,7 +853,7 @@ struct RemapHiddenTyRegions<'tcx> { impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { type Error = ErrorGuaranteed; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -2072,7 +2072,7 @@ struct ReplaceTy<'tcx> { } impl<'tcx> TypeFolder> for ReplaceTy<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 10b097a1060f..6cdbd692f73b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -322,7 +322,7 @@ struct Anonymize<'tcx> { } impl<'tcx> TypeFolder> for Anonymize<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 13180fa2673b..683709f43f2d 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -429,17 +429,17 @@ pub fn check_intrinsic_type( sym::ptr_guaranteed_cmp => ( 1, - 1, + 0, vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))], tcx.types.u8, ), sym::const_allocate => { - (0, 1, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8)) + (0, 0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8)) } sym::const_deallocate => ( 0, - 1, + 0, vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize], tcx.types.unit, ), @@ -478,16 +478,16 @@ pub fn check_intrinsic_type( | sym::frem_algebraic => (1, 0, vec![param(0), param(0)], param(0)), sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), - sym::assume => (0, 1, vec![tcx.types.bool], tcx.types.unit), - sym::likely => (0, 1, vec![tcx.types.bool], tcx.types.bool), - sym::unlikely => (0, 1, vec![tcx.types.bool], tcx.types.bool), + sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit), + sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool), + sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool), sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)), sym::write_via_move => { (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) } - sym::typed_swap => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit), + sym::typed_swap => (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)); 2], tcx.types.unit), sym::discriminant_value => { let assoc_items = tcx.associated_item_def_ids( @@ -566,9 +566,9 @@ pub fn check_intrinsic_type( sym::black_box => (1, 0, vec![param(0)], param(0)), - sym::is_val_statically_known => (1, 1, vec![param(0)], tcx.types.bool), + sym::is_val_statically_known => (1, 0, vec![param(0)], tcx.types.bool), - sym::const_eval_select => (4, 1, vec![param(0), param(1), param(2)], param(3)), + sym::const_eval_select => (4, 0, vec![param(0), param(1), param(2)], param(3)), sym::vtable_size | sym::vtable_align => { (0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize) @@ -576,10 +576,10 @@ pub fn check_intrinsic_type( // This type check is not particularly useful, but the `where` bounds // on the definition in `core` do the heavy lifting for checking it. - sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)), - sym::ptr_metadata => (2, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), + sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)), + sym::ptr_metadata => (2, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), - sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool), + sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool), sym::simd_eq | sym::simd_ne diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 9421269e51ea..5cb91603fd06 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -539,7 +539,7 @@ struct TyVarReplacer<'cx, 'tcx> { } impl<'cx, 'tcx> TypeFolder> for TyVarReplacer<'cx, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c6e8759327f0..e5bd147352de 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -45,8 +45,8 @@ use std::ops::Bound; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::errors; use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; -pub use type_of::test_opaque_hidden_types; +pub(crate) mod dump; mod generics_of; mod item_bounds; mod predicates_of; diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs new file mode 100644 index 000000000000..85e1c600d6da --- /dev/null +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -0,0 +1,43 @@ +use rustc_hir::def::DefKind; +use rustc_hir::def_id::CRATE_DEF_ID; +use rustc_middle::ty::TyCtxt; +use rustc_span::sym; + +pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { + if !tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) { + return; + } + + for id in tcx.hir().items() { + let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue }; + + let ty = tcx.type_of(id.owner_id).instantiate_identity(); + + tcx.dcx().emit_err(crate::errors::TypeOf { span: tcx.def_span(id.owner_id), ty }); + } +} + +pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { + for id in tcx.hir_crate_items(()).owners() { + if tcx.has_attr(id, sym::rustc_dump_predicates) { + let preds = tcx.predicates_of(id).instantiate_identity(tcx).predicates; + let span = tcx.def_span(id); + + let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_predicates.as_str()); + for pred in preds { + diag.note(format!("{pred:?}")); + } + diag.emit(); + } + if tcx.has_attr(id, sym::rustc_dump_item_bounds) { + let bounds = tcx.item_bounds(id).instantiate_identity(); + let span = tcx.def_span(id); + + let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_item_bounds.as_str()); + for bound in bounds { + diag.note(format!("{bound:?}")); + } + diag.emit(); + } + } +} diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 94d6e13d751f..9f198933dee4 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -203,7 +203,7 @@ struct AssocTyToOpaque<'tcx> { } impl<'tcx> TypeFolder> for AssocTyToOpaque<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 2684467a4381..1e2b0c432338 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -15,7 +15,6 @@ use crate::errors::TypeofReservedKeywordUsed; use super::bad_placeholder; use super::ItemCtxt; -pub use opaque::test_opaque_hidden_types; mod opaque; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 2b2f07001d2f..d1048b742a07 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -1,28 +1,14 @@ use rustc_errors::StashKey; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; +use rustc_span::DUMMY_SP; -use crate::errors::{TaitForwardCompat, TaitForwardCompat2, TypeOf, UnconstrainedOpaqueType}; - -pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { - let mut res = Ok(()); - if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) { - for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { - let type_of = tcx.type_of(id.owner_id).instantiate_identity(); - - res = Err(tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of })); - } - } - } - res -} +use crate::errors::{TaitForwardCompat, TaitForwardCompat2, UnconstrainedOpaqueType}; /// Checks "defining uses" of opaque `impl Trait` in associated types. /// These can only be defined by associated items of the same trait. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index cff8d5a5ea50..44025c3cd61c 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -682,7 +682,7 @@ pub(crate) enum CannotCaptureLateBound { pub(crate) struct VariancesOf { #[primary_span] pub span: Span, - pub variances_of: String, + pub variances: String, } #[derive(Diagnostic)] @@ -690,7 +690,7 @@ pub(crate) struct VariancesOf { pub(crate) struct TypeOf<'tcx> { #[primary_span] pub span: Span, - pub type_of: Ty<'tcx>, + pub ty: Ty<'tcx>, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 1927359421d0..0428abcdf24e 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -151,10 +151,6 @@ pub fn provide(providers: &mut Providers) { pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); - if tcx.features().rustc_attrs { - let _ = tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx)); - } - tcx.sess.time("coherence_checking", || { tcx.hir().par_for_each_module(|module| { let _ = tcx.ensure().check_mod_type_wf(module); @@ -169,11 +165,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) { }); if tcx.features().rustc_attrs { - let _ = tcx.sess.time("variance_testing", || variance::test::test_variance(tcx)); - } - - if tcx.features().rustc_attrs { - let _ = collect::test_opaque_hidden_types(tcx); + tcx.sess.time("outlives_dumping", || outlives::dump::inferred_outlives(tcx)); + tcx.sess.time("variance_dumping", || variance::dump::variances(tcx)); + collect::dump::opaque_hidden_types(tcx); + collect::dump::predicates_and_item_bounds(tcx); } // Make sure we evaluate all static and (non-associated) const items, even if unused. diff --git a/compiler/rustc_hir_analysis/src/outlives/dump.rs b/compiler/rustc_hir_analysis/src/outlives/dump.rs new file mode 100644 index 000000000000..ab50d9e86efb --- /dev/null +++ b/compiler/rustc_hir_analysis/src/outlives/dump.rs @@ -0,0 +1,29 @@ +use rustc_middle::bug; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::sym; + +pub(crate) fn inferred_outlives(tcx: TyCtxt<'_>) { + for id in tcx.hir().items() { + if !tcx.has_attr(id.owner_id, sym::rustc_outlives) { + continue; + } + + let preds = tcx.inferred_outlives_of(id.owner_id); + let mut preds: Vec<_> = preds + .iter() + .map(|(pred, _)| match pred.kind().skip_binder() { + ty::ClauseKind::RegionOutlives(p) => p.to_string(), + ty::ClauseKind::TypeOutlives(p) => p.to_string(), + err => bug!("unexpected clause {:?}", err), + }) + .collect(); + preds.sort(); + + let span = tcx.def_span(id.owner_id); + let mut err = tcx.dcx().struct_span_err(span, sym::rustc_outlives.as_str()); + for pred in preds { + err.note(pred); + } + err.emit(); + } +} diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index 97fd7731b1e5..1f74ebf99f16 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -5,10 +5,9 @@ use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt, Upcast}; use rustc_span::Span; +pub(crate) mod dump; mod explicit; mod implicit_infer; -/// Code to write unit test for outlives. -pub mod test; mod utils; pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs deleted file mode 100644 index e9b6c679bd5a..000000000000 --- a/compiler/rustc_hir_analysis/src/outlives/test.rs +++ /dev/null @@ -1,31 +0,0 @@ -use rustc_middle::bug; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::{symbol::sym, ErrorGuaranteed}; - -pub fn test_inferred_outlives(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { - let mut res = Ok(()); - for id in tcx.hir().items() { - // For unit testing: check for a special "rustc_outlives" - // attribute and report an error with various results if found. - if tcx.has_attr(id.owner_id, sym::rustc_outlives) { - let predicates = tcx.inferred_outlives_of(id.owner_id); - let mut pred: Vec = predicates - .iter() - .map(|(out_pred, _)| match out_pred.kind().skip_binder() { - ty::ClauseKind::RegionOutlives(p) => p.to_string(), - ty::ClauseKind::TypeOutlives(p) => p.to_string(), - err => bug!("unexpected clause {:?}", err), - }) - .collect(); - pred.sort(); - - let span = tcx.def_span(id.owner_id); - let mut err = tcx.dcx().struct_span_err(span, "rustc_outlives"); - for p in pred { - err.note(p); - } - res = Err(err.emit()); - } - } - res -} diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs new file mode 100644 index 000000000000..1a17dabb677a --- /dev/null +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -0,0 +1,32 @@ +use rustc_hir::def::DefKind; +use rustc_hir::def_id::CRATE_DEF_ID; +use rustc_middle::ty::TyCtxt; +use rustc_span::symbol::sym; + +pub(crate) fn variances(tcx: TyCtxt<'_>) { + if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { + for id in tcx.hir().items() { + let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue }; + + let variances = tcx.variances_of(id.owner_id); + + tcx.dcx().emit_err(crate::errors::VariancesOf { + span: tcx.def_span(id.owner_id), + variances: format!("{variances:?}"), + }); + } + } + + for id in tcx.hir().items() { + if !tcx.has_attr(id.owner_id, sym::rustc_variance) { + continue; + } + + let variances = tcx.variances_of(id.owner_id); + + tcx.dcx().emit_err(crate::errors::VariancesOf { + span: tcx.def_span(id.owner_id), + variances: format!("{variances:?}"), + }); + } +} diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 1977451f39e0..29f96e27b649 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -22,8 +22,7 @@ mod constraints; /// Code to solve constraints and write out the results. mod solve; -/// Code to write unit tests of variance. -pub mod test; +pub(crate) mod dump; /// Code for transforming variances. mod xform; diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs deleted file mode 100644 index c211e1af046a..000000000000 --- a/compiler/rustc_hir_analysis/src/variance/test.rs +++ /dev/null @@ -1,37 +0,0 @@ -use rustc_hir::def::DefKind; -use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::sym; -use rustc_span::ErrorGuaranteed; - -use crate::errors; - -pub fn test_variance(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { - let mut res = Ok(()); - if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { - for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { - let variances_of = tcx.variances_of(id.owner_id); - - res = Err(tcx.dcx().emit_err(errors::VariancesOf { - span: tcx.def_span(id.owner_id), - variances_of: format!("{variances_of:?}"), - })); - } - } - } - - // For unit testing: check for a special "rustc_variance" - // attribute and report an error with various results if found. - for id in tcx.hir().items() { - if tcx.has_attr(id.owner_id, sym::rustc_variance) { - let variances_of = tcx.variances_of(id.owner_id); - - res = Err(tcx.dcx().emit_err(errors::VariancesOf { - span: tcx.def_span(id.owner_id), - variances_of: format!("{variances_of:?}"), - })); - } - } - res -} diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 2714be1f9b4f..aea0114167eb 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -847,7 +847,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { } impl<'cx, 'tcx> TypeFolder> for Resolver<'cx, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.fcx.tcx } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index bc2592b43f3d..1659f3d04937 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -304,7 +304,7 @@ struct Canonicalizer<'cx, 'tcx> { } impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -773,7 +773,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { ) -> ty::Region<'tcx> { let var = self.canonical_var(info, r.into()); let br = ty::BoundRegion { var, kind: ty::BrAnon }; - ty::Region::new_bound(self.interner(), self.binder_index, br) + ty::Region::new_bound(self.cx(), self.binder_index, br) } /// Given a type variable `ty_var` of the given kind, first check diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index cb0e13652e80..d7349abc44c2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -158,7 +158,7 @@ struct ClosureEraser<'tcx> { } impl<'tcx> TypeFolder> for ClosureEraser<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 50526c964edc..de4267f7cead 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -101,7 +101,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { } impl<'a, 'tcx> TypeFolder> for TypeFreshener<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -118,7 +118,7 @@ impl<'a, 'tcx> TypeFolder> for TypeFreshener<'a, 'tcx> { | ty::RePlaceholder(..) | ty::ReStatic | ty::ReError(_) - | ty::ReErased => self.interner().lifetimes.re_erased, + | ty::ReErased => self.cx().lifetimes.re_erased, } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 4d6ddd7ba66a..a3cf588da1c0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1719,7 +1719,7 @@ struct InferenceLiteralEraser<'tcx> { } impl<'tcx> TypeFolder> for InferenceLiteralEraser<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -1859,7 +1859,7 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( } impl<'tcx> TypeFolder> for ReplaceParamAndInferWithPlaceholder<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 830d79f52b94..ed75fd183f29 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -24,7 +24,7 @@ impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> { } impl<'a, 'tcx> TypeFolder> for OpportunisticVarResolver<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -66,7 +66,7 @@ impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> { } impl<'a, 'tcx> TypeFolder> for OpportunisticRegionResolver<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -85,7 +85,7 @@ impl<'a, 'tcx> TypeFolder> for OpportunisticRegionResolver<'a, 'tcx .inner .borrow_mut() .unwrap_region_constraints() - .opportunistic_resolve_var(TypeFolder::interner(self), vid), + .opportunistic_resolve_var(TypeFolder::cx(self), vid), _ => r, } } @@ -121,7 +121,7 @@ struct FullTypeResolver<'a, 'tcx> { impl<'a, 'tcx> FallibleTypeFolder> for FullTypeResolver<'a, 'tcx> { type Error = FixupError; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index a086c82c92e8..f15bd0babee5 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -183,7 +183,7 @@ pub struct InferenceFudger<'a, 'tcx> { } impl<'a, 'tcx> TypeFolder> for InferenceFudger<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 468673f05c11..fdedf2c2e6d3 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -75,7 +75,7 @@ lint_builtin_deprecated_attr_default_suggestion = remove this attribute lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link} .msg_suggestion = {$msg} .default_suggestion = remove this attribute -lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used. +lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used lint_builtin_deref_nullptr = dereferencing a null pointer .label = this code causes undefined behavior when executed @@ -213,7 +213,7 @@ lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better pe lint_default_source = `forbid` lint level is the default for {$id} lint_deprecated_lint_name = - lint name `{$name}` is deprecated and may not have an effect in the future. + lint name `{$name}` is deprecated and may not have an effect in the future .suggestion = change it to .help = change it to {$replace} @@ -244,11 +244,11 @@ lint_duplicate_matcher_binding = duplicate matcher binding lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type - .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum. + .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum lint_enum_intrinsics_mem_variant = the return value of `mem::variant_count` is unspecified when called with a non-enum type - .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum. + .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 24dd337e6995..300dac442d56 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -390,7 +390,7 @@ struct ReplaceLocalTypesWithInfer<'a, 'tcx, F: FnMut(DefId) -> bool> { impl<'a, 'tcx, F: FnMut(DefId) -> bool> TypeFolder> for ReplaceLocalTypesWithInfer<'a, 'tcx, F> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 932603cd6b26..415399ed06c7 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -248,13 +248,13 @@ metadata_rustc_lib_required = .help = try adding `extern crate rustc_driver;` at the top level of this crate metadata_stable_crate_id_collision = - found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values. + found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values metadata_std_required = `std` is required by `{$current_crate}` because it does not declare `#![no_std]` metadata_symbol_conflicts_current = - the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two. + the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments, so this will result in symbol conflicts between the two metadata_target_no_std_support = the `{$locator_triple}` target may not support the standard library diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 2fc466c0e7e9..cac3bf948a0c 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -40,9 +40,16 @@ pub trait AllocBytes: Clone + fmt::Debug + Deref + DerefMut *mut u8; + + /// Gives direct access to the raw underlying storage. + /// + /// Crucially this pointer is compatible with: + /// - other pointers returned by this method, and + /// - references returned from `deref()`, as long as there was no write. + fn as_ptr(&self) -> *const u8; } /// Default `bytes` for `Allocation` is a `Box`. @@ -62,6 +69,11 @@ impl AllocBytes for Box<[u8]> { // Carefully avoiding any intermediate references. ptr::addr_of_mut!(**self).cast() } + + fn as_ptr(&self) -> *const u8 { + // Carefully avoiding any intermediate references. + ptr::addr_of!(**self).cast() + } } /// This type represents an Allocation in the Miri/CTFE core engine. @@ -490,19 +502,27 @@ impl Allocation self.provenance.clear(range, cx)?; assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check - // Cruciall, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`. + // Crucially, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`. let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize()); let len = range.end().bytes_usize() - range.start.bytes_usize(); Ok(ptr::slice_from_raw_parts_mut(begin_ptr, len)) } /// This gives direct mutable access to the entire buffer, just exposing their internal state - /// without reseting anything. Directly exposes `AllocBytes::as_mut_ptr`. Only works if + /// without resetting anything. Directly exposes `AllocBytes::as_mut_ptr`. Only works if /// `OFFSET_IS_ADDR` is true. pub fn get_bytes_unchecked_raw_mut(&mut self) -> *mut u8 { assert!(Prov::OFFSET_IS_ADDR); self.bytes.as_mut_ptr() } + + /// This gives direct immutable access to the entire buffer, just exposing their internal state + /// without resetting anything. Directly exposes `AllocBytes::as_ptr`. Only works if + /// `OFFSET_IS_ADDR` is true. + pub fn get_bytes_unchecked_raw(&self) -> *const u8 { + assert!(Prov::OFFSET_IS_ADDR); + self.bytes.as_ptr() + } } /// Reading and writing. diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 126387db1d9c..412cfc1fc7a6 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -289,19 +289,7 @@ impl<'tcx> UnOp { pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> { match self { UnOp::Not | UnOp::Neg => arg_ty, - UnOp::PtrMetadata => { - let pointee_ty = arg_ty - .builtin_deref(true) - .unwrap_or_else(|| bug!("PtrMetadata of non-dereferenceable ty {arg_ty:?}")); - if pointee_ty.is_trivially_sized(tcx) { - tcx.types.unit - } else { - let Some(metadata_def_id) = tcx.lang_items().metadata_type() else { - bug!("No metadata_type lang item while looking at {arg_ty:?}") - }; - Ty::new_projection(tcx, metadata_def_id, [pointee_ty]) - } - } + UnOp::PtrMetadata => arg_ty.pointee_metadata_ty_or_projection(tcx), } } } diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 90f80f90767d..7bc4c60f1027 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -53,7 +53,7 @@ impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { self, folder: &mut F, ) -> Result { - Ok(FallibleTypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData { + Ok(FallibleTypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().try_fold_with(folder)?, opaque_types: self .opaque_types @@ -68,7 +68,7 @@ impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { } fn fold_with>>(self, folder: &mut F) -> Self { - TypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData { + TypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData { region_constraints: self.region_constraints.clone().fold_with(folder), opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), normalization_nested_goals: self.normalization_nested_goals.clone().fold_with(folder), @@ -94,19 +94,17 @@ impl<'tcx> TypeFoldable> for PredefinedOpaques<'tcx> { self, folder: &mut F, ) -> Result { - Ok(FallibleTypeFolder::interner(folder).mk_predefined_opaques_in_body( - PredefinedOpaquesData { - opaque_types: self - .opaque_types - .iter() - .map(|opaque| opaque.try_fold_with(folder)) - .collect::>()?, - }, - )) + Ok(FallibleTypeFolder::cx(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { + opaque_types: self + .opaque_types + .iter() + .map(|opaque| opaque.try_fold_with(folder)) + .collect::>()?, + })) } fn fold_with>>(self, folder: &mut F) -> Self { - TypeFolder::interner(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { + TypeFolder::cx(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), }) } diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index fa44fbaa0599..3aa01fbef2fb 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -41,7 +41,7 @@ impl<'tcx> TyCtxt<'tcx> { } impl<'tcx> TypeFolder> for Expander<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8c3ee6955f5d..4bf223379913 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -579,7 +579,7 @@ pub struct MakeSuggestableFolder<'tcx> { impl<'tcx> FallibleTypeFolder> for MakeSuggestableFolder<'tcx> { type Error = (); - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index cd6e7df31f7c..9d5481f3df37 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -37,7 +37,7 @@ struct RegionEraserVisitor<'tcx> { } impl<'tcx> TypeFolder> for RegionEraserVisitor<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 9b5b1430c27f..81ea8738e726 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -28,7 +28,7 @@ where G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>, { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -99,7 +99,7 @@ impl<'a, 'tcx> RegionFolder<'a, 'tcx> { } impl<'a, 'tcx> TypeFolder> for RegionFolder<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -176,7 +176,7 @@ impl<'tcx, D> TypeFolder> for BoundVarReplacer<'tcx, D> where D: BoundVarReplacerDelegate<'tcx>, { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 83d45ca78d9d..5ac3168196ad 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -591,7 +591,7 @@ impl<'tcx> TypeFoldable> for GenericArgsRef<'tcx> { match self.len() { 1 => { let param0 = self[0].try_fold_with(folder)?; - if param0 == self[0] { Ok(self) } else { Ok(folder.interner().mk_args(&[param0])) } + if param0 == self[0] { Ok(self) } else { Ok(folder.cx().mk_args(&[param0])) } } 2 => { let param0 = self[0].try_fold_with(folder)?; @@ -599,7 +599,7 @@ impl<'tcx> TypeFoldable> for GenericArgsRef<'tcx> { if param0 == self[0] && param1 == self[1] { Ok(self) } else { - Ok(folder.interner().mk_args(&[param0, param1])) + Ok(folder.cx().mk_args(&[param0, param1])) } } 0 => Ok(self), @@ -635,7 +635,7 @@ impl<'tcx> TypeFoldable> for &'tcx ty::List> { if param0 == self[0] && param1 == self[1] { Ok(self) } else { - Ok(folder.interner().mk_type_list(&[param0, param1])) + Ok(folder.cx().mk_type_list(&[param0, param1])) } } _ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)), diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index efaf9c7231bb..1ba8820e0e11 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -873,7 +873,7 @@ fn polymorphize<'tcx>( } impl<'tcx> ty::TypeFolder> for PolymorphizationFolder<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index fb16cf5bd363..96f00e1d3063 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -173,7 +173,7 @@ impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { } impl<'tcx> TypeFolder> for NormalizeAfterErasingRegionsFolder<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -211,7 +211,7 @@ impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> { impl<'tcx> FallibleTypeFolder> for TryNormalizeAfterErasingRegionsFolder<'tcx> { type Error = NormalizationError<'tcx>; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 08b2f9e89203..70a54e96d367 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -95,7 +95,7 @@ impl<'tcx> ReverseMapper<'tcx> { } impl<'tcx> TypeFolder> for ReverseMapper<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -144,7 +144,7 @@ impl<'tcx> TypeFolder> for ReverseMapper<'tcx> { ) .emit(); - ty::Region::new_error(self.interner(), e) + ty::Region::new_error(self.cx(), e) } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 72cb3e134027..19700353f594 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2529,7 +2529,7 @@ struct RegionFolder<'a, 'tcx> { } impl<'a, 'tcx> ty::TypeFolder> for RegionFolder<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 71e2e3e9f994..a9dca47ab437 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -335,7 +335,7 @@ impl<'tcx> TypeFoldable> for Pattern<'tcx> { folder: &mut F, ) -> Result { let pat = (*self).clone().try_fold_with(folder)?; - Ok(if pat == *self { self } else { folder.interner().mk_pat(pat) }) + Ok(if pat == *self { self } else { folder.cx().mk_pat(pat) }) } } @@ -407,7 +407,7 @@ impl<'tcx> TypeSuperFoldable> for Ty<'tcx> { | ty::Foreign(..) => return Ok(self), }; - Ok(if *self.kind() == kind { self } else { folder.interner().mk_ty_from_kind(kind) }) + Ok(if *self.kind() == kind { self } else { folder.cx().mk_ty_from_kind(kind) }) } } @@ -512,7 +512,7 @@ impl<'tcx> TypeSuperFoldable> for ty::Predicate<'tcx> { folder: &mut F, ) -> Result { let new = self.kind().try_fold_with(folder)?; - Ok(folder.interner().reuse_or_mk_predicate(self, new)) + Ok(folder.cx().reuse_or_mk_predicate(self, new)) } } @@ -577,7 +577,7 @@ impl<'tcx> TypeSuperFoldable> for ty::Const<'tcx> { ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?), ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), }; - if kind != self.kind() { Ok(folder.interner().mk_ct_from_kind(kind)) } else { Ok(self) } + if kind != self.kind() { Ok(folder.cx().mk_ct_from_kind(kind)) } else { Ok(self) } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9c8a3484aa5b..709c5fe2305d 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1638,6 +1638,34 @@ impl<'tcx> Ty<'tcx> { } } + /// Given a pointer or reference type, returns the type of the *pointee*'s + /// metadata. If it can't be determined exactly (perhaps due to still + /// being generic) then a projection through `ptr::Pointee` will be returned. + /// + /// This is particularly useful for getting the type of the result of + /// [`UnOp::PtrMetadata`](crate::mir::UnOp::PtrMetadata). + /// + /// Panics if `self` is not dereferencable. + #[track_caller] + pub fn pointee_metadata_ty_or_projection(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + let Some(pointee_ty) = self.builtin_deref(true) else { + bug!("Type {self:?} is not a pointer or reference type") + }; + if pointee_ty.is_trivially_sized(tcx) { + tcx.types.unit + } else { + match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) { + Ok(metadata_ty) => metadata_ty, + Err(tail_ty) => { + let Some(metadata_def_id) = tcx.lang_items().metadata_type() else { + bug!("No metadata_type lang item while looking at {self:?}") + }; + Ty::new_projection(tcx, metadata_def_id, [tail_ty]) + } + } + } + } + /// When we create a closure, we record its kind (i.e., what trait /// it implements, constrained by how it uses its borrows) into its /// [`ty::ClosureArgs`] or [`ty::CoroutineClosureArgs`] using a type diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index b079ed521d34..1b5efcee9035 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1083,7 +1083,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { } impl<'tcx> TypeFolder> for OpaqueTypeExpander<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -1130,7 +1130,7 @@ struct WeakAliasTypeExpander<'tcx> { } impl<'tcx> TypeFolder> for WeakAliasTypeExpander<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -1795,7 +1795,7 @@ where for t in iter { new_list.push(t.try_fold_with(folder)?) } - Ok(intern(folder.interner(), &new_list)) + Ok(intern(folder.cx(), &new_list)) } Some((_, Err(err))) => { return Err(err); diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 1ee8777c2741..0c277811fdac 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -103,7 +103,7 @@ mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior .label = dereference of raw pointer -mir_build_exceeds_mcdc_condition_limit = Number of conditions in decision ({$num_conditions}) exceeds limit ({$max_conditions}). MC/DC analysis will not count this expression. +mir_build_exceeds_mcdc_condition_limit = number of conditions in decision ({$num_conditions}) exceeds limit ({$max_conditions}), so MC/DC analysis will not count this expression mir_build_extern_static_requires_unsafe = use of extern static is unsafe and requires unsafe block diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index 32c0d27f635c..7e401b5482f3 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -60,7 +60,15 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, _location: Location) { match rvalue { - Rvalue::NullaryOp(NullOp::UbChecks, ..) if !self.tcx.sess.ub_checks() => { + Rvalue::NullaryOp(NullOp::UbChecks, ..) + if !self + .tcx + .sess + .opts + .unstable_opts + .inline_mir_preserve_debug + .unwrap_or(self.tcx.sess.ub_checks()) => + { // If this is in optimized MIR it's because it's used later, // so if we don't need UB checks this session, give a bonus // here to offset the cost of the call later. @@ -111,12 +119,19 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { } } TerminatorKind::Assert { unwind, msg, .. } => { - self.penalty += - if msg.is_optional_overflow_check() && !self.tcx.sess.overflow_checks() { - INSTR_COST - } else { - CALL_PENALTY - }; + self.penalty += if msg.is_optional_overflow_check() + && !self + .tcx + .sess + .opts + .unstable_opts + .inline_mir_preserve_debug + .unwrap_or(self.tcx.sess.overflow_checks()) + { + INSTR_COST + } else { + CALL_PENALTY + }; if let UnwindAction::Cleanup(_) = unwind { self.penalty += LANDINGPAD_PENALTY; } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index bfdefd5a7d62..936a7e2d9ded 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -823,18 +823,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return self.simplify_cast(kind, value, to, location); } Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => { - let ty = lhs.ty(self.local_decls, self.tcx); - let lhs = self.simplify_operand(lhs, location); - let rhs = self.simplify_operand(rhs, location); - // Only short-circuit options after we called `simplify_operand` - // on both operands for side effect. - let lhs = lhs?; - let rhs = rhs?; - - if let Some(value) = self.simplify_binary(op, ty, lhs, rhs) { - return Some(value); - } - Value::BinaryOp(op, lhs, rhs) + return self.simplify_binary(op, lhs, rhs, location); } Rvalue::UnaryOp(op, ref mut arg_op) => { return self.simplify_unary(op, arg_op, location); @@ -987,23 +976,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // `*const [T]` -> `*const T` which remove metadata. // We run on potentially-generic MIR, though, so unlike codegen // we can't always know exactly what the metadata are. - // Thankfully, equality on `ptr_metadata_ty_or_tail` gives us - // what we need: `Ok(meta_ty)` if the metadata is known, or - // `Err(tail_ty)` if not. Matching metadata is ok, but if - // that's not known, then matching tail types is also ok, - // allowing things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`. - // FIXME: Would it be worth trying to normalize, rather than - // passing the identity closure? Or are the types in the - // Cast realistically about as normalized as we can get anyway? + // To allow things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`, + // it's fine to get a projection as the type. Value::Cast { kind: CastKind::PtrToPtr, value: inner, from, to } - if from - .builtin_deref(true) - .unwrap() - .ptr_metadata_ty_or_tail(self.tcx, |t| t) - == to - .builtin_deref(true) - .unwrap() - .ptr_metadata_ty_or_tail(self.tcx, |t| t) => + if self.pointers_have_same_metadata(*from, *to) => { arg_index = *inner; was_updated = true; @@ -1068,6 +1044,52 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { #[instrument(level = "trace", skip(self), ret)] fn simplify_binary( + &mut self, + op: BinOp, + lhs_operand: &mut Operand<'tcx>, + rhs_operand: &mut Operand<'tcx>, + location: Location, + ) -> Option { + let lhs = self.simplify_operand(lhs_operand, location); + let rhs = self.simplify_operand(rhs_operand, location); + // Only short-circuit options after we called `simplify_operand` + // on both operands for side effect. + let mut lhs = lhs?; + let mut rhs = rhs?; + + let lhs_ty = lhs_operand.ty(self.local_decls, self.tcx); + + // If we're comparing pointers, remove `PtrToPtr` casts if the from + // types of both casts and the metadata all match. + if let BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge = op + && lhs_ty.is_any_ptr() + && let Value::Cast { + kind: CastKind::PtrToPtr, value: lhs_value, from: lhs_from, .. + } = self.get(lhs) + && let Value::Cast { + kind: CastKind::PtrToPtr, value: rhs_value, from: rhs_from, .. + } = self.get(rhs) + && lhs_from == rhs_from + && self.pointers_have_same_metadata(*lhs_from, lhs_ty) + { + lhs = *lhs_value; + rhs = *rhs_value; + if let Some(op) = self.try_as_operand(lhs, location) { + *lhs_operand = op; + } + if let Some(op) = self.try_as_operand(rhs, location) { + *rhs_operand = op; + } + } + + if let Some(value) = self.simplify_binary_inner(op, lhs_ty, lhs, rhs) { + return Some(value); + } + let value = Value::BinaryOp(op, lhs, rhs); + Some(self.insert(value)) + } + + fn simplify_binary_inner( &mut self, op: BinOp, lhs_ty: Ty<'tcx>, @@ -1228,6 +1250,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } + // PtrToPtr-then-PtrToPtr can skip the intermediate step if let PtrToPtr = kind && let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } = *self.get(value) @@ -1235,7 +1258,25 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { { from = inner_from; value = inner_value; - *kind = PtrToPtr; + was_updated = true; + if inner_from == to { + return Some(inner_value); + } + } + + // PtrToPtr-then-Transmute can just transmute the original, so long as the + // PtrToPtr didn't change metadata (and thus the size of the pointer) + if let Transmute = kind + && let Value::Cast { + kind: PtrToPtr, + value: inner_value, + from: inner_from, + to: inner_to, + } = *self.get(value) + && self.pointers_have_same_metadata(inner_from, inner_to) + { + from = inner_from; + value = inner_value; was_updated = true; if inner_from == to { return Some(inner_value); @@ -1289,6 +1330,21 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Fallback: a symbolic `Len`. Some(self.insert(Value::Len(inner))) } + + fn pointers_have_same_metadata(&self, left_ptr_ty: Ty<'tcx>, right_ptr_ty: Ty<'tcx>) -> bool { + let left_meta_ty = left_ptr_ty.pointee_metadata_ty_or_projection(self.tcx); + let right_meta_ty = right_ptr_ty.pointee_metadata_ty_or_projection(self.tcx); + if left_meta_ty == right_meta_ty { + true + } else if let Ok(left) = + self.tcx.try_normalize_erasing_regions(self.param_env, left_meta_ty) + && let Ok(right) = self.tcx.try_normalize_erasing_regions(self.param_env, right_meta_ty) + { + left == right + } else { + false + } + } } fn op_to_prop_const<'tcx>( diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index ecdca8292b43..3f4d2b65ff24 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -60,7 +60,7 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> { let ccx = ConstCx::new(tcx, body); let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx); - let promotable_candidates = validate_candidates(&ccx, &mut temps, &all_candidates); + let promotable_candidates = validate_candidates(&ccx, &mut temps, all_candidates); let promoted = promote_candidates(body, tcx, temps, promotable_candidates); self.promoted_fragments.set(promoted); @@ -98,8 +98,8 @@ struct Collector<'a, 'tcx> { } impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { + #[instrument(level = "debug", skip(self))] fn visit_local(&mut self, index: Local, context: PlaceContext, location: Location) { - debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location); // We're only interested in temporaries and the return place match self.ccx.body.local_kind(index) { LocalKind::Arg => return, @@ -111,20 +111,15 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { // then it's constant and thus drop is noop. // Non-uses are also irrelevant. if context.is_drop() || !context.is_use() { - debug!( - "visit_local: context.is_drop={:?} context.is_use={:?}", - context.is_drop(), - context.is_use(), - ); + debug!(is_drop = context.is_drop(), is_use = context.is_use()); return; } let temp = &mut self.temps[index]; - debug!("visit_local: temp={:?}", temp); + debug!(?temp); *temp = match *temp { TempState::Undefined => match context { - PlaceContext::MutatingUse(MutatingUseContext::Store) - | PlaceContext::MutatingUse(MutatingUseContext::Call) => { + PlaceContext::MutatingUse(MutatingUseContext::Store | MutatingUseContext::Call) => { TempState::Defined { location, uses: 0, valid: Err(()) } } _ => TempState::Unpromotable, @@ -137,7 +132,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { | PlaceContext::NonMutatingUse(_) => true, PlaceContext::MutatingUse(_) | PlaceContext::NonUse(_) => false, }; - debug!("visit_local: allowed_use={:?}", allowed_use); + debug!(?allowed_use); if allowed_use { *uses += 1; return; @@ -146,6 +141,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { } TempState::Unpromotable | TempState::PromotedOut => TempState::Unpromotable, }; + debug!(?temp); } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { @@ -695,15 +691,12 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_candidates( ccx: &ConstCx<'_, '_>, temps: &mut IndexSlice, - candidates: &[Candidate], + mut candidates: Vec, ) -> Vec { let mut validator = Validator { ccx, temps, promotion_safe_blocks: None }; + candidates.retain(|&candidate| validator.validate_candidate(candidate).is_ok()); candidates - .iter() - .copied() - .filter(|&candidate| validator.validate_candidate(candidate).is_ok()) - .collect() } struct Promoter<'a, 'tcx> { @@ -972,7 +965,12 @@ fn promote_candidates<'tcx>( candidates: Vec, ) -> IndexVec> { // Visit candidates in reverse, in case they're nested. - debug!("promote_candidates({:?})", candidates); + debug!(promote_candidates = ?candidates); + + // eagerly fail fast + if candidates.is_empty() { + return IndexVec::new(); + } let mut promotions = IndexVec::new(); diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index a81fd03d034f..695d02705abd 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -7,7 +7,7 @@ use rustc_type_ir::{ self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Interner, }; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; /// Whether we're canonicalizing a query input or the query response. /// @@ -38,8 +38,8 @@ pub enum CanonicalizeMode { }, } -pub struct Canonicalizer<'a, Infcx: SolverDelegate, I: Interner> { - infcx: &'a Infcx, +pub struct Canonicalizer<'a, D: SolverDelegate, I: Interner> { + delegate: &'a D, canonicalize_mode: CanonicalizeMode, variables: &'a mut Vec, @@ -47,15 +47,15 @@ pub struct Canonicalizer<'a, Infcx: SolverDelegate, I: Interner> { binder_index: ty::DebruijnIndex, } -impl<'a, Infcx: SolverDelegate, I: Interner> Canonicalizer<'a, Infcx, I> { +impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { pub fn canonicalize>( - infcx: &'a Infcx, + delegate: &'a D, canonicalize_mode: CanonicalizeMode, variables: &'a mut Vec, value: T, ) -> ty::Canonical { let mut canonicalizer = Canonicalizer { - infcx, + delegate, canonicalize_mode, variables, @@ -70,7 +70,7 @@ impl<'a, Infcx: SolverDelegate, I: Interner> Canonicalizer<'a, Inf let (max_universe, variables) = canonicalizer.finalize(); - let defining_opaque_types = infcx.defining_opaque_types(); + let defining_opaque_types = delegate.defining_opaque_types(); Canonical { defining_opaque_types, max_universe, variables, value } } @@ -102,7 +102,7 @@ impl<'a, Infcx: SolverDelegate, I: Interner> Canonicalizer<'a, Inf .max() .unwrap_or(ty::UniverseIndex::ROOT); - let var_infos = self.infcx.interner().mk_canonical_var_infos(&var_infos); + let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos); return (max_universe, var_infos); } } @@ -206,16 +206,14 @@ impl<'a, Infcx: SolverDelegate, I: Interner> Canonicalizer<'a, Inf } } - let var_infos = self.infcx.interner().mk_canonical_var_infos(&var_infos); + let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos); (curr_compressed_uv, var_infos) } } -impl, I: Interner> TypeFolder - for Canonicalizer<'_, Infcx, I> -{ - fn interner(&self) -> I { - self.infcx.interner() +impl, I: Interner> TypeFolder for Canonicalizer<'_, D, I> { + fn cx(&self) -> I { + self.delegate.cx() } fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder @@ -267,14 +265,14 @@ impl, I: Interner> TypeFolder ty::ReVar(vid) => { assert_eq!( - self.infcx.opportunistic_resolve_lt_var(vid), + self.delegate.opportunistic_resolve_lt_var(vid), r, "region vid should have been resolved fully before canonicalization" ); match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => { - CanonicalVarKind::Region(self.infcx.universe_of_lt(vid).unwrap()) + CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap()) } } } @@ -294,7 +292,7 @@ impl, I: Interner> TypeFolder var }); - Region::new_anon_bound(self.interner(), self.binder_index, var) + Region::new_anon_bound(self.cx(), self.binder_index, var) } fn fold_ty(&mut self, t: I::Ty) -> I::Ty { @@ -302,20 +300,20 @@ impl, I: Interner> TypeFolder ty::Infer(i) => match i { ty::TyVar(vid) => { assert_eq!( - self.infcx.opportunistic_resolve_ty_var(vid), + self.delegate.opportunistic_resolve_ty_var(vid), t, "ty vid should have been resolved fully before canonicalization" ); CanonicalVarKind::Ty(CanonicalTyVarKind::General( - self.infcx + self.delegate .universe_of_ty(vid) .unwrap_or_else(|| panic!("ty var should have been resolved: {t:?}")), )) } ty::IntVar(vid) => { assert_eq!( - self.infcx.opportunistic_resolve_int_var(vid), + self.delegate.opportunistic_resolve_int_var(vid), t, "ty vid should have been resolved fully before canonicalization" ); @@ -323,7 +321,7 @@ impl, I: Interner> TypeFolder } ty::FloatVar(vid) => { assert_eq!( - self.infcx.opportunistic_resolve_float_var(vid), + self.delegate.opportunistic_resolve_float_var(vid), t, "ty vid should have been resolved fully before canonicalization" ); @@ -383,7 +381,7 @@ impl, I: Interner> TypeFolder }), ); - Ty::new_anon_bound(self.interner(), self.binder_index, var) + Ty::new_anon_bound(self.cx(), self.binder_index, var) } fn fold_const(&mut self, c: I::Const) -> I::Const { @@ -391,11 +389,11 @@ impl, I: Interner> TypeFolder ty::ConstKind::Infer(i) => match i { ty::InferConst::Var(vid) => { assert_eq!( - self.infcx.opportunistic_resolve_ct_var(vid), + self.delegate.opportunistic_resolve_ct_var(vid), c, "const vid should have been resolved fully before canonicalization" ); - CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap()) + CanonicalVarKind::Const(self.delegate.universe_of_ct(vid).unwrap()) } ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect, ty::InferConst::Fresh(_) => todo!(), @@ -431,6 +429,6 @@ impl, I: Interner> TypeFolder }), ); - Const::new_anon_bound(self.interner(), self.binder_index, var) + Const::new_anon_bound(self.cx(), self.binder_index, var) } } diff --git a/compiler/rustc_next_trait_solver/src/infcx.rs b/compiler/rustc_next_trait_solver/src/delegate.rs similarity index 98% rename from compiler/rustc_next_trait_solver/src/infcx.rs rename to compiler/rustc_next_trait_solver/src/delegate.rs index c249eb94cf65..6626acfe9639 100644 --- a/compiler/rustc_next_trait_solver/src/infcx.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -7,14 +7,14 @@ use rustc_type_ir::{self as ty, Interner}; pub trait SolverDelegate: Sized { type Interner: Interner; - fn interner(&self) -> Self::Interner; + fn cx(&self) -> Self::Interner; type Span: Copy; fn solver_mode(&self) -> SolverMode; fn build_with_canonical( - interner: Self::Interner, + cx: Self::Interner, solver_mode: SolverMode, canonical: &ty::Canonical, ) -> (Self, V, ty::CanonicalVarValues) @@ -102,7 +102,7 @@ pub trait SolverDelegate: Sized { // FIXME: This is only here because elaboration lives in `rustc_infer`! fn elaborate_supertraits( - interner: Self::Interner, + cx: Self::Interner, trait_ref: ty::Binder>, ) -> impl Iterator>>; diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index ea3e18872fa4..a6a9c01faaa0 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -5,6 +5,6 @@ //! So if you got to this crate from the old solver, it's totally normal. pub mod canonicalizer; -pub mod infcx; +pub mod delegate; pub mod resolve; pub mod solve; diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 3d8d957eaae4..6ed58d0e4fb6 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -1,4 +1,4 @@ -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; @@ -8,37 +8,37 @@ use rustc_type_ir::{self as ty, Interner}; // EAGER RESOLUTION /// Resolves ty, region, and const vars to their inferred values or their root vars. -pub struct EagerResolver<'a, Infcx, I = ::Interner> +pub struct EagerResolver<'a, D, I = ::Interner> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { - infcx: &'a Infcx, + delegate: &'a D, } -impl<'a, Infcx: SolverDelegate> EagerResolver<'a, Infcx> { - pub fn new(infcx: &'a Infcx) -> Self { - EagerResolver { infcx } +impl<'a, D: SolverDelegate> EagerResolver<'a, D> { + pub fn new(delegate: &'a D) -> Self { + EagerResolver { delegate } } } -impl, I: Interner> TypeFolder for EagerResolver<'_, Infcx> { - fn interner(&self) -> I { - self.infcx.interner() +impl, I: Interner> TypeFolder for EagerResolver<'_, D> { + fn cx(&self) -> I { + self.delegate.cx() } fn fold_ty(&mut self, t: I::Ty) -> I::Ty { match t.kind() { ty::Infer(ty::TyVar(vid)) => { - let resolved = self.infcx.opportunistic_resolve_ty_var(vid); + let resolved = self.delegate.opportunistic_resolve_ty_var(vid); if t != resolved && resolved.has_infer() { resolved.fold_with(self) } else { resolved } } - ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid), - ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid), + ty::Infer(ty::IntVar(vid)) => self.delegate.opportunistic_resolve_int_var(vid), + ty::Infer(ty::FloatVar(vid)) => self.delegate.opportunistic_resolve_float_var(vid), _ => { if t.has_infer() { t.super_fold_with(self) @@ -51,7 +51,7 @@ impl, I: Interner> TypeFolder for EagerRe fn fold_region(&mut self, r: I::Region) -> I::Region { match r.kind() { - ty::ReVar(vid) => self.infcx.opportunistic_resolve_lt_var(vid), + ty::ReVar(vid) => self.delegate.opportunistic_resolve_lt_var(vid), _ => r, } } @@ -59,7 +59,7 @@ impl, I: Interner> TypeFolder for EagerRe fn fold_const(&mut self, c: I::Const) -> I::Const { match c.kind() { ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - let resolved = self.infcx.opportunistic_resolve_ct_var(vid); + let resolved = self.delegate.opportunistic_resolve_ct_var(vid); if c != resolved && resolved.has_infer() { resolved.fold_with(self) } else { @@ -67,7 +67,7 @@ impl, I: Interner> TypeFolder for EagerRe } } ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => { - self.infcx.opportunistic_resolve_effect_var(vid) + self.delegate.opportunistic_resolve_effect_var(vid) } _ => { if c.has_infer() { diff --git a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs index fbc8ac1d5d5c..5a95f4edf191 100644 --- a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs +++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs @@ -19,12 +19,12 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::{self as ty, Interner}; use tracing::{instrument, trace}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { #[instrument(level = "trace", skip(self), ret)] @@ -32,7 +32,7 @@ where &mut self, goal: Goal, ) -> QueryResult { - let tcx = self.interner(); + let tcx = self.cx(); let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some()); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 9a1537d26060..cae9c5c85678 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -9,7 +9,7 @@ use rustc_type_ir::visit::TypeVisitableExt as _; use rustc_type_ir::{self as ty, Interner, Upcast as _}; use tracing::{debug, instrument}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource, @@ -28,10 +28,10 @@ pub(super) struct Candidate { } /// Methods used to assemble candidates for either trait or projection goals. -pub(super) trait GoalKind::Interner>: +pub(super) trait GoalKind::Interner>: TypeFoldable + Copy + Eq + std::fmt::Display where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { fn self_ty(self) -> I::Ty; @@ -47,18 +47,18 @@ where /// work, then produce a response (typically by executing /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, source: CandidateSource, goal: Goal, assumption: I::Clause, - then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult, ) -> Result, NoSolution>; /// Consider a clause, which consists of a "assumption" and some "requirements", /// to satisfy a goal. If the requirements hold, then attempt to satisfy our /// goal by equating it with the assumption. fn probe_and_consider_implied_clause( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, parent_source: CandidateSource, goal: Goal, assumption: I::Clause, @@ -76,13 +76,13 @@ where /// additionally checking all of the supertraits and object bounds to hold, /// since they're not implied by the well-formedness of the object type. fn probe_and_consider_object_bound_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, source: CandidateSource, goal: Goal, assumption: I::Clause, ) -> Result, NoSolution> { Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else { panic!("expected object type in `probe_and_consider_object_bound_candidate`"); }; @@ -100,7 +100,7 @@ where } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, impl_def_id: I::DefId, ) -> Result, NoSolution>; @@ -112,7 +112,7 @@ where /// Trait goals always hold while projection goals never do. This is a bit arbitrary /// but prevents incorrect normalization while hiding any trait errors. fn consider_error_guaranteed_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, guar: I::ErrorGuaranteed, ) -> Result, NoSolution>; @@ -121,13 +121,13 @@ where /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_auto_trait`]. fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; /// A trait alias holds if the RHS traits and `where` clauses hold. fn consider_trait_alias_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; @@ -136,7 +136,7 @@ where /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`]. fn consider_builtin_sized_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; @@ -145,27 +145,27 @@ where /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`]. fn consider_builtin_copy_clone_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; /// A type is `PointerLike` if we can compute its layout, and that layout /// matches the layout of `usize`. fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; /// A type is a `FnPtr` if it is of `FnPtr` type. fn consider_builtin_fn_ptr_trait_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn` /// family of traits where `A` is given by the signature of the type. fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, kind: ty::ClosureKind, ) -> Result, NoSolution>; @@ -173,7 +173,7 @@ where /// An async closure is known to implement the `AsyncFn` family of traits /// where `A` is given by the signature of the type. fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, kind: ty::ClosureKind, ) -> Result, NoSolution>; @@ -182,13 +182,13 @@ where /// is used internally to delay computation for async closures until after /// upvar analysis is performed in HIR typeck. fn consider_builtin_async_fn_kind_helper_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; /// `Tuple` is implemented if the `Self` type is a tuple. fn consider_builtin_tuple_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; @@ -198,7 +198,7 @@ where /// the built-in types. For structs, the metadata type is given by the struct /// tail. fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; @@ -206,7 +206,7 @@ where /// `Future`, where `O` is given by the coroutine's return type /// that was computed during type-checking. fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; @@ -214,19 +214,19 @@ where /// `Iterator`, where `O` is given by the generator's yield type /// that was computed during type-checking. fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `FusedIterator` fn consider_builtin_fused_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; @@ -234,27 +234,27 @@ where /// implement `Coroutine`, given the resume, yield, /// and return types of the coroutine computed during type-checking. fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; fn consider_builtin_destruct_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; fn consider_builtin_transmute_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution>; @@ -266,17 +266,17 @@ where /// otherwise recompute this for codegen. This is a bit of a mess but the /// easiest way to maintain the existing behavior for now. fn consider_structural_builtin_unsize_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Vec>; } -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { - pub(super) fn assemble_and_evaluate_candidates>( + pub(super) fn assemble_and_evaluate_candidates>( &mut self, goal: Goal, ) -> Vec> { @@ -291,10 +291,8 @@ where return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect(); } - let goal: Goal = goal.with( - self.interner(), - goal.predicate.with_self_ty(self.interner(), normalized_self_ty), - ); + let goal: Goal = + goal.with(self.cx(), goal.predicate.with_self_ty(self.cx(), normalized_self_ty)); // Vars that show up in the rest of the goal substs may have been constrained by // normalizing the self type as well, since type variables are not uniquified. let goal = self.resolve_vars_if_possible(goal); @@ -337,12 +335,12 @@ where } #[instrument(level = "trace", skip_all)] - fn assemble_impl_candidates>( + fn assemble_impl_candidates>( &mut self, goal: Goal, candidates: &mut Vec>, ) { - let tcx = self.interner(); + let tcx = self.cx(); tcx.for_each_relevant_impl( goal.predicate.trait_def_id(tcx), goal.predicate.self_ty(), @@ -363,12 +361,12 @@ where } #[instrument(level = "trace", skip_all)] - fn assemble_builtin_impl_candidates>( + fn assemble_builtin_impl_candidates>( &mut self, goal: Goal, candidates: &mut Vec>, ) { - let tcx = self.interner(); + let tcx = self.cx(); let trait_def_id = goal.predicate.trait_def_id(tcx); // N.B. When assembling built-in candidates for lang items that are also @@ -394,9 +392,9 @@ where G::consider_builtin_pointer_like_candidate(self, goal) } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::FnPtrTrait) { G::consider_builtin_fn_ptr_trait_candidate(self, goal) - } else if let Some(kind) = self.interner().fn_trait_kind_from_def_id(trait_def_id) { + } else if let Some(kind) = self.cx().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) - } else if let Some(kind) = self.interner().async_fn_trait_kind_from_def_id(trait_def_id) { + } else if let Some(kind) = self.cx().async_fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_async_fn_trait_candidates(self, goal, kind) } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncFnKindHelper) { G::consider_builtin_async_fn_kind_helper_candidate(self, goal) @@ -436,7 +434,7 @@ where } #[instrument(level = "trace", skip_all)] - fn assemble_param_env_candidates>( + fn assemble_param_env_candidates>( &mut self, goal: Goal, candidates: &mut Vec>, @@ -453,7 +451,7 @@ where } #[instrument(level = "trace", skip_all)] - fn assemble_alias_bound_candidates>( + fn assemble_alias_bound_candidates>( &mut self, goal: Goal, candidates: &mut Vec>, @@ -472,7 +470,7 @@ where /// If so, continue searching by recursively calling after normalization. // FIXME: This may recurse infinitely, but I can't seem to trigger it without // hitting another overflow error something. Add a depth parameter needed later. - fn assemble_alias_bound_candidates_recur>( + fn assemble_alias_bound_candidates_recur>( &mut self, self_ty: I::Ty, goal: Goal, @@ -523,15 +521,13 @@ where ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), ty::Alias(ty::Inherent | ty::Weak, _) => { - self.interner().delay_bug(format!("could not normalize {self_ty:?}, it is not WF")); + self.cx().delay_bug(format!("could not normalize {self_ty:?}, it is not WF")); return; } }; - for assumption in self - .interner() - .item_bounds(alias_ty.def_id) - .iter_instantiated(self.interner(), &alias_ty.args) + for assumption in + self.cx().item_bounds(alias_ty.def_id).iter_instantiated(self.cx(), &alias_ty.args) { candidates.extend(G::probe_and_consider_implied_clause( self, @@ -556,12 +552,12 @@ where } #[instrument(level = "trace", skip_all)] - fn assemble_object_bound_candidates>( + fn assemble_object_bound_candidates>( &mut self, goal: Goal, candidates: &mut Vec>, ) { - let tcx = self.interner(); + let tcx = self.cx(); if !tcx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(tcx)) { return; } @@ -629,8 +625,7 @@ where // a projection goal. if let Some(principal) = bounds.principal() { let principal_trait_ref = principal.with_self_ty(tcx, self_ty); - for (idx, assumption) in - Infcx::elaborate_supertraits(tcx, principal_trait_ref).enumerate() + for (idx, assumption) in D::elaborate_supertraits(tcx, principal_trait_ref).enumerate() { candidates.extend(G::probe_and_consider_object_bound_candidate( self, @@ -649,12 +644,12 @@ where /// To do so we add an ambiguous candidate in case such an unknown impl could /// apply to the current goal. #[instrument(level = "trace", skip_all)] - fn assemble_coherence_unknowable_candidates>( + fn assemble_coherence_unknowable_candidates>( &mut self, goal: Goal, candidates: &mut Vec>, ) { - let tcx = self.interner(); + let tcx = self.cx(); candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter( |ecx| { @@ -678,12 +673,12 @@ where // to improve this however. However, this should make it fairly straightforward to refine // the filtering going forward, so it seems alright-ish for now. #[instrument(level = "debug", skip(self, goal))] - fn discard_impls_shadowed_by_env>( + fn discard_impls_shadowed_by_env>( &mut self, goal: Goal, candidates: &mut Vec>, ) { - let tcx = self.interner(); + let tcx = self.cx(); let trait_goal: Goal> = goal.with(tcx, goal.predicate.trait_ref(tcx)); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index dbe3dfd4a1b5..b10be5a9ba70 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -10,20 +10,20 @@ use rustc_type_ir::{self as ty, Interner, Upcast as _}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::instrument; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{EvalCtxt, Goal, NoSolution}; // Calculates the constituent types of a type for `auto trait` purposes. #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait( - ecx: &EvalCtxt<'_, Infcx>, +pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait( + ecx: &EvalCtxt<'_, D>, ty: I::Ty, ) -> Result>, NoSolution> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { - let tcx = ecx.interner(); + let tcx = ecx.cx(); match ty.kind() { ty::Uint(_) | ty::Int(_) @@ -76,7 +76,7 @@ where } ty::CoroutineWitness(def_id, args) => Ok(ecx - .interner() + .cx() .bound_coroutine_hidden_types(def_id) .into_iter() .map(|bty| bty.instantiate(tcx, &args)) @@ -101,12 +101,12 @@ where } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait( - ecx: &EvalCtxt<'_, Infcx>, +pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait( + ecx: &EvalCtxt<'_, D>, ty: I::Ty, ) -> Result>, NoSolution> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { match ty.kind() { @@ -159,8 +159,8 @@ where // "best effort" optimization and `sized_constraint` may return `Some`, even // if the ADT is sized for all possible args. ty::Adt(def, args) => { - if let Some(sized_crit) = def.sized_constraint(ecx.interner()) { - Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), &args))]) + if let Some(sized_crit) = def.sized_constraint(ecx.cx()) { + Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.cx(), &args))]) } else { Ok(vec![]) } @@ -169,12 +169,12 @@ where } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait( - ecx: &EvalCtxt<'_, Infcx>, +pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait( + ecx: &EvalCtxt<'_, D>, ty: I::Ty, ) -> Result>, NoSolution> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { match ty.kind() { @@ -222,10 +222,10 @@ where // only when `coroutine_clone` is enabled and the coroutine is movable // impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses) - ty::Coroutine(def_id, args) => match ecx.interner().coroutine_movability(def_id) { + ty::Coroutine(def_id, args) => match ecx.cx().coroutine_movability(def_id) { Movability::Static => Err(NoSolution), Movability::Movable => { - if ecx.interner().features().coroutine_clone() { + if ecx.cx().features().coroutine_clone() { let coroutine = args.as_coroutine(); Ok(vec![ ty::Binder::dummy(coroutine.tupled_upvars_ty()), @@ -239,10 +239,10 @@ where // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types ty::CoroutineWitness(def_id, args) => Ok(ecx - .interner() + .cx() .bound_coroutine_hidden_types(def_id) .into_iter() - .map(|bty| bty.instantiate(ecx.interner(), &args)) + .map(|bty| bty.instantiate(ecx.cx(), &args)) .collect()), } } @@ -656,17 +656,17 @@ fn coroutine_closure_to_ambiguous_coroutine( // 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( - ecx: &EvalCtxt<'_, Infcx>, +pub(in crate::solve) fn predicates_for_object_candidate( + ecx: &EvalCtxt<'_, D>, param_env: I::ParamEnv, trait_ref: ty::TraitRef, object_bounds: I::BoundExistentialPredicates, ) -> Vec> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let mut requirements = vec![]; requirements .extend(tcx.super_predicates_of(trait_ref.def_id).iter_instantiated(tcx, &trait_ref.args)); @@ -712,18 +712,18 @@ where .collect() } -struct ReplaceProjectionWith<'a, Infcx: SolverDelegate, I: Interner> { - ecx: &'a EvalCtxt<'a, Infcx>, +struct ReplaceProjectionWith<'a, D: SolverDelegate, I: Interner> { + ecx: &'a EvalCtxt<'a, D>, param_env: I::ParamEnv, mapping: HashMap>>, nested: Vec>, } -impl, I: Interner> TypeFolder - for ReplaceProjectionWith<'_, Infcx, I> +impl, I: Interner> TypeFolder + for ReplaceProjectionWith<'_, D, I> { - fn interner(&self) -> I { - self.ecx.interner() + fn cx(&self) -> I { + self.ecx.cx() } fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { @@ -739,7 +739,7 @@ impl, I: Interner> TypeFolder .eq_and_get_goals( self.param_env, alias_ty, - proj.projection_term.expect_ty(self.ecx.interner()), + proj.projection_term.expect_ty(self.ecx.cx()), ) .expect( "expected to be able to unify goal projection with dyn's projection", diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index c6611285a3be..f1d4864a84b7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -18,7 +18,7 @@ use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, Interner}; use tracing::{instrument, trace}; use crate::canonicalizer::{CanonicalizeMode, Canonicalizer}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::resolve::EagerResolver; use crate::solve::eval_ctxt::NestedGoals; use crate::solve::inspect; @@ -44,9 +44,9 @@ impl ResponseT for inspect::State { } } -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { /// Canonicalizes the goal remembering the original values @@ -55,19 +55,19 @@ where &self, goal: Goal, ) -> (Vec, CanonicalInput) { - let opaque_types = self.infcx.clone_opaque_types_for_query_response(); + let opaque_types = self.delegate.clone_opaque_types_for_query_response(); let (goal, opaque_types) = - (goal, opaque_types).fold_with(&mut EagerResolver::new(self.infcx)); + (goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate)); let mut orig_values = Default::default(); let canonical_goal = Canonicalizer::canonicalize( - self.infcx, + self.delegate, CanonicalizeMode::Input, &mut orig_values, QueryInput { goal, predefined_opaques_in_body: self - .interner() + .cx() .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), }, ); @@ -97,7 +97,7 @@ where // We only check for leaks from universes which were entered inside // of the query. - self.infcx.leak_check(self.max_input_universe).map_err(|NoSolution| { + self.delegate.leak_check(self.max_input_universe).map_err(|NoSolution| { trace!("failed the leak check"); NoSolution })?; @@ -125,21 +125,21 @@ where let external_constraints = self.compute_external_query_constraints(certainty, normalization_nested_goals); - let (var_values, mut external_constraints) = - (self.var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx)); + let (var_values, mut external_constraints) = (self.var_values, external_constraints) + .fold_with(&mut EagerResolver::new(self.delegate)); // Remove any trivial region constraints once we've resolved regions external_constraints .region_constraints .retain(|outlives| outlives.0.as_region().map_or(true, |re| re != outlives.1)); let canonical = Canonicalizer::canonicalize( - self.infcx, + self.delegate, CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, &mut Default::default(), Response { var_values, certainty, - external_constraints: self.interner().mk_external_constraints(external_constraints), + external_constraints: self.cx().mk_external_constraints(external_constraints), }, ); @@ -155,7 +155,7 @@ where maybe_cause: MaybeCause, ) -> CanonicalResponse { response_no_constraints_raw( - self.interner(), + self.cx(), self.max_input_universe, self.variables, Certainty::Maybe(maybe_cause), @@ -184,7 +184,7 @@ where // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. let region_constraints = if certainty == Certainty::Yes { - self.infcx.make_deduplicated_outlives_constraints() + self.delegate.make_deduplicated_outlives_constraints() } else { Default::default() }; @@ -192,7 +192,7 @@ where ExternalConstraintsData { region_constraints, opaque_types: self - .infcx + .delegate .clone_opaque_types_for_query_response() .into_iter() // Only return *newly defined* opaque types. @@ -219,15 +219,15 @@ where response: CanonicalResponse, ) -> (NestedNormalizationGoals, Certainty) { let instantiation = Self::compute_query_response_instantiation_values( - self.infcx, + self.delegate, &original_values, &response, ); let Response { var_values, external_constraints, certainty } = - self.infcx.instantiate_canonical(response, instantiation); + self.delegate.instantiate_canonical(response, instantiation); - Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values); + Self::unify_query_var_values(self.delegate, param_env, &original_values, var_values); let ExternalConstraintsData { region_constraints, @@ -243,17 +243,17 @@ where /// the canonical response. This depends on the `original_values` for the /// bound variables. fn compute_query_response_instantiation_values>( - infcx: &Infcx, + delegate: &D, original_values: &[I::GenericArg], response: &Canonical, ) -> CanonicalVarValues { // FIXME: Longterm canonical queries should deal with all placeholders // created inside of the query directly instead of returning them to the // caller. - let prev_universe = infcx.universe(); + let prev_universe = delegate.universe(); let universes_created_in_query = response.max_universe.index(); for _ in 0..universes_created_in_query { - infcx.create_next_universe(); + delegate.create_next_universe(); } let var_values = response.value.var_values(); @@ -290,13 +290,13 @@ where } } - let var_values = infcx.interner().mk_args_from_iter( + let var_values = delegate.cx().mk_args_from_iter( response.variables.into_iter().enumerate().map(|(index, info)| { if info.universe() != ty::UniverseIndex::ROOT { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all (see the FIXME at the start of this method), we have to deal with // them for now. - infcx.instantiate_canonical_var_with_infer(info, |idx| { + delegate.instantiate_canonical_var_with_infer(info, |idx| { ty::UniverseIndex::from(prev_universe.index() + idx.index()) }) } else if info.is_existential() { @@ -310,7 +310,7 @@ where if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] { v } else { - infcx.instantiate_canonical_var_with_infer(info, |_| prev_universe) + delegate.instantiate_canonical_var_with_infer(info, |_| prev_universe) } } else { // For placeholders which were already part of the input, we simply map this @@ -335,9 +335,9 @@ where /// whether an alias is rigid by using the trait solver. When instantiating a response /// from the solver we assume that the solver correctly handled aliases and therefore /// always relate them structurally here. - #[instrument(level = "trace", skip(infcx))] + #[instrument(level = "trace", skip(delegate))] fn unify_query_var_values( - infcx: &Infcx, + delegate: &D, param_env: I::ParamEnv, original_values: &[I::GenericArg], var_values: CanonicalVarValues, @@ -345,7 +345,8 @@ where assert_eq!(original_values.len(), var_values.len()); for (&orig, response) in iter::zip(original_values, var_values.var_values) { - let goals = infcx.eq_structurally_relating_aliases(param_env, orig, response).unwrap(); + let goals = + delegate.eq_structurally_relating_aliases(param_env, orig, response).unwrap(); assert!(goals.is_empty()); } } @@ -365,7 +366,7 @@ where fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey, I::Ty)]) { for &(key, ty) in opaque_types { - self.infcx.inject_new_hidden_type_unchecked(key, ty); + self.delegate.inject_new_hidden_type_unchecked(key, ty); } } } @@ -374,22 +375,22 @@ where /// evaluating a goal. The `var_values` not only include the bound variables /// of the query input, but also contain all unconstrained inference vars /// created while evaluating this goal. -pub(in crate::solve) fn make_canonical_state( - infcx: &Infcx, +pub(in crate::solve) fn make_canonical_state( + delegate: &D, var_values: &[I::GenericArg], max_input_universe: ty::UniverseIndex, data: T, ) -> inspect::CanonicalState where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, T: TypeFoldable, { - let var_values = CanonicalVarValues { var_values: infcx.interner().mk_args(var_values) }; + let var_values = CanonicalVarValues { var_values: delegate.cx().mk_args(var_values) }; let state = inspect::State { var_values, data }; - let state = state.fold_with(&mut EagerResolver::new(infcx)); + let state = state.fold_with(&mut EagerResolver::new(delegate)); Canonicalizer::canonicalize( - infcx, + delegate, CanonicalizeMode::Response { max_input_universe }, &mut vec![], state, @@ -398,15 +399,15 @@ where // FIXME: needs to be pub to be accessed by downstream // `rustc_trait_selection::solve::inspect::analyse`. -pub fn instantiate_canonical_state>( - infcx: &Infcx, - span: Infcx::Span, +pub fn instantiate_canonical_state>( + delegate: &D, + span: D::Span, param_env: I::ParamEnv, orig_values: &mut Vec, state: inspect::CanonicalState, ) -> T where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { // In case any fresh inference variables have been created between `state` @@ -415,15 +416,15 @@ where for &arg in &state.value.var_values.var_values[orig_values.len()..state.value.var_values.len()] { // FIXME: This is so ugly. - let unconstrained = infcx.fresh_var_for_kind_with_span(arg, span); + let unconstrained = delegate.fresh_var_for_kind_with_span(arg, span); orig_values.push(unconstrained); } let instantiation = - EvalCtxt::compute_query_response_instantiation_values(infcx, orig_values, &state); + EvalCtxt::compute_query_response_instantiation_values(delegate, orig_values, &state); - let inspect::State { var_values, data } = infcx.instantiate_canonical(state, instantiation); + let inspect::State { var_values, data } = delegate.instantiate_canonical(state, instantiation); - EvalCtxt::unify_query_var_values(infcx, param_env, orig_values, var_values); + EvalCtxt::unify_query_var_values(delegate, param_env, orig_values, var_values); data } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 8548c647b6b1..6644fff2140c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -11,7 +11,7 @@ use rustc_type_ir::{self as ty, CanonicalVarValues, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::{instrument, trace}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ @@ -23,9 +23,9 @@ use crate::solve::{ pub(super) mod canonical; mod probe; -pub struct EvalCtxt<'a, Infcx, I = ::Interner> +pub struct EvalCtxt<'a, D, I = ::Interner> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { /// The inference context that backs (mostly) inference and placeholder terms @@ -43,7 +43,7 @@ where /// If some `InferCtxt` method is missing, please first think defensively about /// the method's compatibility with this solver, or if an existing one does /// the job already. - infcx: &'a Infcx, + delegate: &'a D, /// The variable info for the `var_values`, only used to make an ambiguous response /// with no constraints. @@ -83,7 +83,7 @@ where // evaluation code. tainted: Result<(), NoSolution>, - pub(super) inspect: ProofTreeBuilder, + pub(super) inspect: ProofTreeBuilder, } #[derive(derivative::Derivative)] @@ -143,9 +143,9 @@ pub trait SolverDelegateEvalExt: SolverDelegate { ); } -impl SolverDelegateEvalExt for Infcx +impl SolverDelegateEvalExt for D where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { /// Evaluates a goal from **outside** of the trait solver. @@ -178,9 +178,9 @@ where } } -impl<'a, Infcx, I> EvalCtxt<'a, Infcx> +impl<'a, D, I> EvalCtxt<'a, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { pub(super) fn solver_mode(&self) -> SolverMode { @@ -195,22 +195,22 @@ where /// used from outside of any evaluation, and other methods should be preferred /// over using this manually (such as [`SolverDelegateEvalExt::evaluate_root_goal`]). pub(super) fn enter_root( - infcx: &Infcx, + delegate: &D, generate_proof_tree: GenerateProofTree, - f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> R, + f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R, ) -> (R, Option>) { - let mut search_graph = search_graph::SearchGraph::new(infcx.solver_mode()); + let mut search_graph = search_graph::SearchGraph::new(delegate.solver_mode()); let mut ecx = EvalCtxt { - infcx, + delegate, search_graph: &mut search_graph, nested_goals: NestedGoals::new(), inspect: ProofTreeBuilder::new_maybe_root(generate_proof_tree), // Only relevant when canonicalizing the response, // which we don't do within this evaluation context. - predefined_opaques_in_body: infcx - .interner() + predefined_opaques_in_body: delegate + .cx() .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()), max_input_universe: ty::UniverseIndex::ROOT, variables: Default::default(), @@ -242,14 +242,14 @@ where tcx: I, search_graph: &'a mut search_graph::SearchGraph, canonical_input: CanonicalInput, - canonical_goal_evaluation: &mut ProofTreeBuilder, - f: impl FnOnce(&mut EvalCtxt<'_, Infcx>, Goal) -> R, + canonical_goal_evaluation: &mut ProofTreeBuilder, + f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal) -> R, ) -> R { - let (ref infcx, input, var_values) = + let (ref delegate, input, var_values) = SolverDelegate::build_with_canonical(tcx, search_graph.solver_mode(), &canonical_input); let mut ecx = EvalCtxt { - infcx, + delegate, variables: canonical_input.variables, var_values, is_normalizes_to_goal: false, @@ -262,7 +262,7 @@ where }; for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { - ecx.infcx.inject_new_hidden_type_unchecked(key, ty); + ecx.delegate.inject_new_hidden_type_unchecked(key, ty); } if !ecx.nested_goals.is_empty() { @@ -270,7 +270,7 @@ where } let result = f(&mut ecx, input.goal); - ecx.inspect.probe_final_state(ecx.infcx, ecx.max_input_universe); + ecx.inspect.probe_final_state(ecx.delegate, ecx.max_input_universe); canonical_goal_evaluation.goal_evaluation_step(ecx.inspect); // When creating a query response we clone the opaque type constraints @@ -278,7 +278,7 @@ where // assertions against dropping an `InferCtxt` without taking opaques. // FIXME: Once we remove support for the old impl we can remove this. // FIXME: Could we make `build_with_canonical` into `enter_with_canonical` and call this at the end? - infcx.reset_opaque_types(); + delegate.reset_opaque_types(); result } @@ -297,7 +297,7 @@ where tcx: I, search_graph: &'a mut search_graph::SearchGraph, canonical_input: CanonicalInput, - goal_evaluation: &mut ProofTreeBuilder, + goal_evaluation: &mut ProofTreeBuilder, ) -> QueryResult { let mut canonical_goal_evaluation = goal_evaluation.new_canonical_goal_evaluation(canonical_input); @@ -364,7 +364,7 @@ where let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); let canonical_response = EvalCtxt::evaluate_canonical_goal( - self.interner(), + self.cx(), self.search_graph, canonical_goal, &mut goal_evaluation, @@ -466,8 +466,8 @@ where } } } else { - self.infcx.enter_forall(kind, |kind| { - let goal = goal.with(self.interner(), ty::Binder::dummy(kind)); + self.delegate.enter_forall(kind, |kind| { + let goal = goal.with(self.cx(), ty::Binder::dummy(kind)); self.add_goal(GoalSource::InstantiateHigherRanked, goal); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) @@ -506,7 +506,7 @@ where /// /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. fn evaluate_added_goals_step(&mut self) -> Result, NoSolution> { - let tcx = self.interner(); + let tcx = self.cx(); let mut goals = core::mem::take(&mut self.nested_goals); // If this loop did not result in any progress, what's our final certainty. @@ -588,11 +588,11 @@ where /// Record impl args in the proof tree for later access by `InspectCandidate`. pub(crate) fn record_impl_args(&mut self, impl_args: I::GenericArgs) { - self.inspect.record_impl_args(self.infcx, self.max_input_universe, impl_args) + self.inspect.record_impl_args(self.delegate, self.max_input_universe, impl_args) } - pub(super) fn interner(&self) -> I { - self.infcx.interner() + pub(super) fn cx(&self) -> I { + self.delegate.cx() } #[instrument(level = "trace", skip(self))] @@ -600,7 +600,7 @@ where goal.predicate = goal .predicate .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); - self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); + self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal); self.nested_goals.normalizes_to_goals.push(goal); } @@ -609,7 +609,7 @@ where goal.predicate = goal .predicate .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); - self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal); + self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); self.nested_goals.goals.push((source, goal)); } @@ -625,13 +625,13 @@ where } pub(super) fn next_ty_infer(&mut self) -> I::Ty { - let ty = self.infcx.next_ty_infer(); + let ty = self.delegate.next_ty_infer(); self.inspect.add_var_value(ty); ty } pub(super) fn next_const_infer(&mut self) -> I::Const { - let ct = self.infcx.next_const_infer(); + let ct = self.delegate.next_const_infer(); self.inspect.add_var_value(ct); ct } @@ -654,27 +654,27 @@ where let universe_of_term = match goal.predicate.term.kind() { ty::TermKind::Ty(ty) => { if let ty::Infer(ty::TyVar(vid)) = ty.kind() { - self.infcx.universe_of_ty(vid).unwrap() + self.delegate.universe_of_ty(vid).unwrap() } else { return false; } } ty::TermKind::Const(ct) => { if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { - self.infcx.universe_of_ct(vid).unwrap() + self.delegate.universe_of_ct(vid).unwrap() } else { return false; } } }; - struct ContainsTermOrNotNameable<'a, Infcx: SolverDelegate, I: Interner> { + struct ContainsTermOrNotNameable<'a, D: SolverDelegate, I: Interner> { term: I::Term, universe_of_term: ty::UniverseIndex, - infcx: &'a Infcx, + delegate: &'a D, } - impl, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> { + impl, I: Interner> ContainsTermOrNotNameable<'_, D, I> { fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> { if self.universe_of_term.can_name(universe) { ControlFlow::Continue(()) @@ -684,8 +684,8 @@ where } } - impl, I: Interner> TypeVisitor - for ContainsTermOrNotNameable<'_, Infcx, I> + impl, I: Interner> TypeVisitor + for ContainsTermOrNotNameable<'_, D, I> { type Result = ControlFlow<()>; fn visit_ty(&mut self, t: I::Ty) -> Self::Result { @@ -693,13 +693,15 @@ where ty::Infer(ty::TyVar(vid)) => { if let ty::TermKind::Ty(term) = self.term.kind() { if let ty::Infer(ty::TyVar(term_vid)) = term.kind() { - if self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid) { + if self.delegate.root_ty_var(vid) + == self.delegate.root_ty_var(term_vid) + { return ControlFlow::Break(()); } } } - self.check_nameable(self.infcx.universe_of_ty(vid).unwrap()) + self.check_nameable(self.delegate.universe_of_ty(vid).unwrap()) } ty::Placeholder(p) => self.check_nameable(p.universe()), _ => { @@ -718,15 +720,15 @@ where if let ty::TermKind::Const(term) = self.term.kind() { if let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() { - if self.infcx.root_const_var(vid) - == self.infcx.root_const_var(term_vid) + if self.delegate.root_const_var(vid) + == self.delegate.root_const_var(term_vid) { return ControlFlow::Break(()); } } } - self.check_nameable(self.infcx.universe_of_ct(vid).unwrap()) + self.check_nameable(self.delegate.universe_of_ct(vid).unwrap()) } ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()), _ => { @@ -741,7 +743,7 @@ where } let mut visitor = ContainsTermOrNotNameable { - infcx: self.infcx, + delegate: self.delegate, universe_of_term, term: goal.predicate.term, }; @@ -775,7 +777,7 @@ where // NOTE: this check is purely an optimization, the structural eq would // always fail if the term is not an inference variable. if term.is_infer() { - let tcx = self.interner(); + let tcx = self.cx(); // We need to relate `alias` to `term` treating only the outermost // constructor as rigid, relating any contained generic arguments as // normal. We do this by first structurally equating the `term` @@ -788,7 +790,7 @@ where let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args); let ctor_term = rigid_ctor.to_term(tcx); let obligations = - self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?; + self.delegate.eq_structurally_relating_aliases(param_env, term, ctor_term)?; debug_assert!(obligations.is_empty()); self.relate(param_env, alias, variance, rigid_ctor) } else { @@ -806,7 +808,7 @@ where lhs: T, rhs: T, ) -> Result<(), NoSolution> { - let result = self.infcx.eq_structurally_relating_aliases(param_env, lhs, rhs)?; + let result = self.delegate.eq_structurally_relating_aliases(param_env, lhs, rhs)?; assert_eq!(result, vec![]); Ok(()) } @@ -829,7 +831,7 @@ where variance: ty::Variance, rhs: T, ) -> Result<(), NoSolution> { - let goals = self.infcx.relate(param_env, lhs, variance, rhs)?; + let goals = self.delegate.relate(param_env, lhs, variance, rhs)?; self.add_goals(GoalSource::Misc, goals); Ok(()) } @@ -846,14 +848,14 @@ where lhs: T, rhs: T, ) -> Result>, NoSolution> { - self.infcx.relate(param_env, lhs, ty::Variance::Invariant, rhs) + self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs) } pub(super) fn instantiate_binder_with_infer + Copy>( &self, value: ty::Binder, ) -> T { - self.infcx.instantiate_binder_with_infer(value) + self.delegate.instantiate_binder_with_infer(value) } pub(super) fn enter_forall + Copy, U>( @@ -861,18 +863,18 @@ where value: ty::Binder, f: impl FnOnce(T) -> U, ) -> U { - self.infcx.enter_forall(value, f) + self.delegate.enter_forall(value, f) } pub(super) fn resolve_vars_if_possible(&self, value: T) -> T where T: TypeFoldable, { - self.infcx.resolve_vars_if_possible(value) + self.delegate.resolve_vars_if_possible(value) } pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs { - let args = self.infcx.fresh_args_for_item(def_id); + let args = self.delegate.fresh_args_for_item(def_id); for arg in args { self.inspect.add_var_value(arg); } @@ -880,12 +882,12 @@ where } pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) { - self.infcx.register_ty_outlives(ty, lt); + self.delegate.register_ty_outlives(ty, lt); } pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) { // `b : a` ==> `a <= b` - self.infcx.sub_regions(b, a); + self.delegate.sub_regions(b, a); } /// Computes the list of goals required for `arg` to be well-formed @@ -894,7 +896,7 @@ where param_env: I::ParamEnv, arg: I::GenericArg, ) -> Option>> { - self.infcx.well_formed_goals(param_env, arg) + self.delegate.well_formed_goals(param_env, arg) } pub(super) fn trait_ref_is_knowable( @@ -902,9 +904,9 @@ where param_env: I::ParamEnv, trait_ref: ty::TraitRef, ) -> Result { - let infcx = self.infcx; + let delegate = self.delegate; let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty); - infcx.trait_ref_is_knowable(trait_ref, lazily_normalize_ty) + delegate.trait_ref_is_knowable(trait_ref, lazily_normalize_ty) } pub(super) fn fetch_eligible_assoc_item( @@ -914,7 +916,7 @@ where trait_assoc_def_id: I::DefId, impl_def_id: I::DefId, ) -> Result, NoSolution> { - self.infcx.fetch_eligible_assoc_item( + self.delegate.fetch_eligible_assoc_item( param_env, goal_trait_ref, trait_assoc_def_id, @@ -923,7 +925,7 @@ where } pub(super) fn can_define_opaque_ty(&self, def_id: I::LocalDefId) -> bool { - self.infcx.defining_opaque_types().contains(&def_id) + self.delegate.defining_opaque_types().contains(&def_id) } pub(super) fn insert_hidden_type( @@ -933,7 +935,7 @@ where hidden_ty: I::Ty, ) -> Result<(), NoSolution> { let mut goals = Vec::new(); - self.infcx.insert_hidden_type(opaque_type_key, param_env, hidden_ty, &mut goals)?; + self.delegate.insert_hidden_type(opaque_type_key, param_env, hidden_ty, &mut goals)?; self.add_goals(GoalSource::Misc, goals); Ok(()) } @@ -946,7 +948,7 @@ where hidden_ty: I::Ty, ) { let mut goals = Vec::new(); - self.infcx.add_item_bounds_for_hidden_type( + self.delegate.add_item_bounds_for_hidden_type( opaque_def_id, opaque_args, param_env, @@ -965,7 +967,7 @@ where ty: I::Ty, ) -> Vec> { // FIXME: Super inefficient to be cloning this... - let opaques = self.infcx.clone_opaque_types_for_query_response(); + let opaques = self.delegate.clone_opaque_types_for_query_response(); let mut values = vec![]; for (candidate_key, candidate_ty) in opaques { @@ -1002,7 +1004,7 @@ where param_env: I::ParamEnv, unevaluated: ty::UnevaluatedConst, ) -> Option { - self.infcx.try_const_eval_resolve(param_env, unevaluated) + self.delegate.try_const_eval_resolve(param_env, unevaluated) } pub(super) fn is_transmutable( @@ -1012,7 +1014,7 @@ where src: I::Ty, assume: I::Const, ) -> Result { - self.infcx.is_transmutable(param_env, dst, src, assume) + self.delegate.is_transmutable(param_env, dst, src, assume) } } @@ -1023,22 +1025,22 @@ where /// /// This is a performance optimization to more eagerly detect cycles during trait /// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. -struct ReplaceAliasWithInfer<'me, 'a, Infcx, I> +struct ReplaceAliasWithInfer<'me, 'a, D, I> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { - ecx: &'me mut EvalCtxt<'a, Infcx>, + ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv, } -impl TypeFolder for ReplaceAliasWithInfer<'_, '_, Infcx, I> +impl TypeFolder for ReplaceAliasWithInfer<'_, '_, D, I> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { - fn interner(&self) -> I { - self.ecx.interner() + fn cx(&self) -> I { + self.ecx.cx() } fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { @@ -1052,7 +1054,7 @@ where ); self.ecx.add_goal( GoalSource::Misc, - Goal::new(self.interner(), self.param_env, normalizes_to), + Goal::new(self.cx(), self.param_env, normalizes_to), ); infer_ty } @@ -1071,7 +1073,7 @@ where ); self.ecx.add_goal( GoalSource::Misc, - Goal::new(self.interner(), self.param_env, normalizes_to), + Goal::new(self.cx(), self.param_env, normalizes_to), ); infer_ct } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index 1c5358b3edb4..e9516c60c70f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -3,34 +3,34 @@ use std::marker::PhantomData; use rustc_type_ir::Interner; use tracing::instrument; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::assembly::Candidate; use crate::solve::inspect; use crate::solve::{BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult}; -pub(in crate::solve) struct ProbeCtxt<'me, 'a, Infcx, I, F, T> +pub(in crate::solve) struct ProbeCtxt<'me, 'a, D, I, F, T> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { - ecx: &'me mut EvalCtxt<'a, Infcx, I>, + ecx: &'me mut EvalCtxt<'a, D, I>, probe_kind: F, _result: PhantomData, } -impl ProbeCtxt<'_, '_, Infcx, I, F, T> +impl ProbeCtxt<'_, '_, D, I, F, T> where F: FnOnce(&T) -> inspect::ProbeKind, - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { - pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> T) -> T { + pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T) -> T { let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self; - let infcx = outer_ecx.infcx; + let delegate = outer_ecx.delegate; let max_input_universe = outer_ecx.max_input_universe; let mut nested_ecx = EvalCtxt { - infcx, + delegate, variables: outer_ecx.variables, var_values: outer_ecx.var_values, is_normalizes_to_goal: outer_ecx.is_normalizes_to_goal, @@ -41,9 +41,9 @@ where tainted: outer_ecx.tainted, inspect: outer_ecx.inspect.take_and_enter_probe(), }; - let r = nested_ecx.infcx.probe(|| { + let r = nested_ecx.delegate.probe(|| { let r = f(&mut nested_ecx); - nested_ecx.inspect.probe_final_state(infcx, max_input_universe); + nested_ecx.inspect.probe_final_state(delegate, max_input_universe); r }); if !nested_ecx.inspect.is_noop() { @@ -55,41 +55,38 @@ where } } -pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, Infcx, I, F> +pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, D, I, F> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { - cx: ProbeCtxt<'me, 'a, Infcx, I, F, QueryResult>, + cx: ProbeCtxt<'me, 'a, D, I, F, QueryResult>, source: CandidateSource, } -impl TraitProbeCtxt<'_, '_, Infcx, I, F> +impl TraitProbeCtxt<'_, '_, D, I, F> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, F: FnOnce(&QueryResult) -> inspect::ProbeKind, { #[instrument(level = "debug", skip_all, fields(source = ?self.source))] pub(in crate::solve) fn enter( self, - f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + f: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult, ) -> Result, NoSolution> { self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result }) } } -impl<'a, Infcx, I> EvalCtxt<'a, Infcx, I> +impl<'a, D, I> EvalCtxt<'a, D, I> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { /// `probe_kind` is only called when proof tree building is enabled so it can be /// as expensive as necessary to output the desired information. - pub(in crate::solve) fn probe( - &mut self, - probe_kind: F, - ) -> ProbeCtxt<'_, 'a, Infcx, I, F, T> + pub(in crate::solve) fn probe(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, D, I, F, T> where F: FnOnce(&T) -> inspect::ProbeKind, { @@ -99,16 +96,14 @@ where pub(in crate::solve) fn probe_builtin_trait_candidate( &mut self, source: BuiltinImplSource, - ) -> TraitProbeCtxt<'_, 'a, Infcx, I, impl FnOnce(&QueryResult) -> inspect::ProbeKind> - { + ) -> TraitProbeCtxt<'_, 'a, D, I, impl FnOnce(&QueryResult) -> inspect::ProbeKind> { self.probe_trait_candidate(CandidateSource::BuiltinImpl(source)) } pub(in crate::solve) fn probe_trait_candidate( &mut self, source: CandidateSource, - ) -> TraitProbeCtxt<'_, 'a, Infcx, I, impl FnOnce(&QueryResult) -> inspect::ProbeKind> - { + ) -> TraitProbeCtxt<'_, 'a, D, I, impl FnOnce(&QueryResult) -> inspect::ProbeKind> { TraitProbeCtxt { cx: ProbeCtxt { ecx: self, diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 5fbec4b28d43..ae59f0c5e957 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -9,7 +9,7 @@ use std::mem; use rustc_type_ir::{self as ty, Interner}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::eval_ctxt::canonical; use crate::solve::inspect; use crate::solve::{ @@ -37,12 +37,12 @@ use crate::solve::{ /// trees. At the end of trait solving `ProofTreeBuilder::finalize` /// is called to recursively convert the whole structure to a /// finished proof tree. -pub(in crate::solve) struct ProofTreeBuilder::Interner> +pub(in crate::solve) struct ProofTreeBuilder::Interner> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { - _infcx: PhantomData, + _infcx: PhantomData, state: Option>>, } @@ -235,8 +235,8 @@ impl WipProbeStep { } } -impl, I: Interner> ProofTreeBuilder { - fn new(state: impl Into>) -> ProofTreeBuilder { +impl, I: Interner> ProofTreeBuilder { + fn new(state: impl Into>) -> ProofTreeBuilder { ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData } } @@ -258,7 +258,7 @@ impl, I: Interner> ProofTreeBuilder { self.state.as_deref_mut() } - pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder { + pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder { let mut nested = ProofTreeBuilder { state: self.state.take(), _infcx: PhantomData }; nested.enter_probe(); nested @@ -273,18 +273,18 @@ impl, I: Interner> ProofTreeBuilder { } } - pub fn new_maybe_root(generate_proof_tree: GenerateProofTree) -> ProofTreeBuilder { + pub fn new_maybe_root(generate_proof_tree: GenerateProofTree) -> ProofTreeBuilder { match generate_proof_tree { GenerateProofTree::No => ProofTreeBuilder::new_noop(), GenerateProofTree::Yes => ProofTreeBuilder::new_root(), } } - pub fn new_root() -> ProofTreeBuilder { + pub fn new_root() -> ProofTreeBuilder { ProofTreeBuilder::new(DebugSolver::Root) } - pub fn new_noop() -> ProofTreeBuilder { + pub fn new_noop() -> ProofTreeBuilder { ProofTreeBuilder { state: None, _infcx: PhantomData } } @@ -297,7 +297,7 @@ impl, I: Interner> ProofTreeBuilder { goal: Goal, orig_values: &[I::GenericArg], kind: GoalEvaluationKind, - ) -> ProofTreeBuilder { + ) -> ProofTreeBuilder { self.opt_nested(|| match kind { GoalEvaluationKind::Root => Some(WipGoalEvaluation { uncanonicalized_goal: goal, @@ -311,7 +311,7 @@ impl, I: Interner> ProofTreeBuilder { pub fn new_canonical_goal_evaluation( &mut self, goal: CanonicalInput, - ) -> ProofTreeBuilder { + ) -> ProofTreeBuilder { self.nested(|| WipCanonicalGoalEvaluation { goal, kind: None, @@ -337,10 +337,7 @@ impl, I: Interner> ProofTreeBuilder { }) } - pub fn canonical_goal_evaluation( - &mut self, - canonical_goal_evaluation: ProofTreeBuilder, - ) { + pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder) { if let Some(this) = self.as_mut() { match (this, *canonical_goal_evaluation.state.unwrap()) { ( @@ -366,7 +363,7 @@ impl, I: Interner> ProofTreeBuilder { } } - pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder) { + pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder) { if let Some(this) = self.as_mut() { match this { DebugSolver::Root => *this = *goal_evaluation.state.unwrap(), @@ -382,7 +379,7 @@ impl, I: Interner> ProofTreeBuilder { &mut self, var_values: ty::CanonicalVarValues, instantiated_goal: QueryInput, - ) -> ProofTreeBuilder { + ) -> ProofTreeBuilder { self.nested(|| WipCanonicalGoalEvaluationStep { var_values: var_values.var_values.to_vec(), instantiated_goal, @@ -396,7 +393,7 @@ impl, I: Interner> ProofTreeBuilder { }) } - pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder) { + pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder) { if let Some(this) = self.as_mut() { match (this, *goal_evaluation_step.state.unwrap()) { ( @@ -448,12 +445,12 @@ impl, I: Interner> ProofTreeBuilder { } } - pub fn probe_final_state(&mut self, infcx: &Infcx, max_input_universe: ty::UniverseIndex) { + pub fn probe_final_state(&mut self, delegate: &D, max_input_universe: ty::UniverseIndex) { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { let final_state = canonical::make_canonical_state( - infcx, + delegate, &state.var_values, max_input_universe, (), @@ -467,21 +464,21 @@ impl, I: Interner> ProofTreeBuilder { pub fn add_normalizes_to_goal( &mut self, - infcx: &Infcx, + delegate: &D, max_input_universe: ty::UniverseIndex, goal: Goal>, ) { self.add_goal( - infcx, + delegate, max_input_universe, GoalSource::Misc, - goal.with(infcx.interner(), goal.predicate), + goal.with(delegate.cx(), goal.predicate), ); } pub fn add_goal( &mut self, - infcx: &Infcx, + delegate: &D, max_input_universe: ty::UniverseIndex, source: GoalSource, goal: Goal, @@ -490,7 +487,7 @@ impl, I: Interner> ProofTreeBuilder { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { let goal = canonical::make_canonical_state( - infcx, + delegate, &state.var_values, max_input_universe, goal, @@ -503,14 +500,14 @@ impl, I: Interner> ProofTreeBuilder { pub(crate) fn record_impl_args( &mut self, - infcx: &Infcx, + delegate: &D, max_input_universe: ty::UniverseIndex, impl_args: I::GenericArgs, ) { match self.as_mut() { Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { let impl_args = canonical::make_canonical_state( - infcx, + delegate, &state.var_values, max_input_universe, impl_args, @@ -538,7 +535,7 @@ impl, I: Interner> ProofTreeBuilder { } } - pub fn finish_probe(mut self) -> ProofTreeBuilder { + pub fn finish_probe(mut self) -> ProofTreeBuilder { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 02069016c2bd..b76b4c098523 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -29,7 +29,7 @@ use rustc_type_ir::{self as ty, Interner}; use tracing::instrument; pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; /// How many fixpoint iterations we should attempt inside of the solver before bailing /// with overflow. @@ -56,9 +56,9 @@ fn has_no_inference_or_external_constraints( && response.value.external_constraints.opaque_types.is_empty() } -impl<'a, Infcx, I> EvalCtxt<'a, Infcx> +impl<'a, D, I> EvalCtxt<'a, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { #[instrument(level = "trace", skip(self))] @@ -104,7 +104,7 @@ where } fn compute_object_safe_goal(&mut self, trait_def_id: I::DefId) -> QueryResult { - if self.interner().trait_is_object_safe(trait_def_id) { + if self.cx().trait_is_object_safe(trait_def_id) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) @@ -182,7 +182,7 @@ where return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } ty::ConstKind::Unevaluated(uv) => { - self.interner().type_of(uv.def).instantiate(self.interner(), &uv.args) + self.cx().type_of(uv.def).instantiate(self.cx(), &uv.args) } ty::ConstKind::Expr(_) => unimplemented!( "`feature(generic_const_exprs)` is not supported in the new trait solver" @@ -193,7 +193,7 @@ where ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct), ty::ConstKind::Value(ty, _) => ty, ty::ConstKind::Placeholder(placeholder) => { - self.interner().find_const_ty_from_env(goal.param_env, placeholder) + self.cx().find_const_ty_from_env(goal.param_env, placeholder) } }; @@ -202,9 +202,9 @@ where } } -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`. @@ -267,7 +267,7 @@ where if let ty::Alias(..) = ty.kind() { let normalized_ty = self.next_ty_infer(); let alias_relate_goal = Goal::new( - self.interner(), + self.cx(), param_env, ty::PredicateKind::AliasRelate( ty.into(), diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index 0f1c1f13c165..5d5597429da4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -1,12 +1,12 @@ use rustc_type_ir::{self as ty, Interner}; use tracing::instrument; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { #[instrument(level = "trace", skip(self), ret)] diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 8436f3ad4841..827fe5f2ca40 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -7,19 +7,19 @@ use rustc_type_ir::{self as ty, Interner}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { pub(super) fn normalize_inherent_associated_type( &mut self, goal: Goal>, ) -> QueryResult { - let tcx = self.interner(); + let tcx = self.cx(); let inherent = goal.predicate.alias.expect_ty(tcx); let impl_def_id = tcx.parent(inherent.def_id); diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index ebc83bef5137..f58384d86cd6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -9,7 +9,7 @@ use rustc_type_ir::Upcast as _; use rustc_type_ir::{self as ty, Interner, NormalizesTo}; use tracing::instrument; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; use crate::solve::assembly::{self, Candidate}; use crate::solve::inspect::ProbeKind; @@ -18,9 +18,9 @@ use crate::solve::{ NoSolution, QueryResult, }; -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { #[instrument(level = "trace", skip(self), ret)] @@ -48,7 +48,7 @@ where /// returns `NoSolution`. #[instrument(level = "trace", skip(self), ret)] fn normalize_at_least_one_step(&mut self, goal: Goal>) -> QueryResult { - match goal.predicate.alias.kind(self.interner()) { + match goal.predicate.alias.kind(self.cx()) { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { let candidates = self.assemble_and_evaluate_candidates(goal); self.merge_candidates(candidates) @@ -75,9 +75,9 @@ where } } -impl assembly::GoalKind for NormalizesTo +impl assembly::GoalKind for NormalizesTo where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { fn self_ty(self) -> I::Ty { @@ -97,15 +97,15 @@ where } fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, source: CandidateSource, goal: Goal, assumption: I::Clause, - then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult, ) -> Result, NoSolution> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { - let tcx = ecx.interner(); + let tcx = ecx.cx(); ecx.probe_trait_candidate(source).enter(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); @@ -136,15 +136,15 @@ where } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal>, impl_def_id: I::DefId, ) -> Result, NoSolution> { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let goal_trait_ref = goal.predicate.alias.trait_ref(tcx); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); - if !ecx.interner().args_may_unify_deep( + if !ecx.cx().args_may_unify_deep( goal.predicate.alias.trait_ref(tcx).args, impl_trait_ref.skip_binder().args, ) { @@ -194,7 +194,7 @@ where return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); }; - let error_response = |ecx: &mut EvalCtxt<'_, Infcx>, msg: &str| { + let error_response = |ecx: &mut EvalCtxt<'_, D>, msg: &str| { let guar = tcx.delay_bug(msg); let error_term = match goal.predicate.alias.kind(tcx) { ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(), @@ -262,61 +262,61 @@ where /// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error` /// and succeed. Can experiment with this to figure out what results in better error messages. fn consider_error_guaranteed_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, _guar: I::ErrorGuaranteed, ) -> Result, NoSolution> { Err(NoSolution) } fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, _goal: Goal, ) -> Result, NoSolution> { - ecx.interner().delay_bug("associated types not allowed on auto traits"); + ecx.cx().delay_bug("associated types not allowed on auto traits"); Err(NoSolution) } fn consider_trait_alias_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { panic!("trait aliases do not have associated types: {:?}", goal); } fn consider_builtin_sized_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { panic!("`Sized` does not have an associated type: {:?}", goal); } fn consider_builtin_copy_clone_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } fn consider_builtin_pointer_like_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { panic!("`PointerLike` does not have an associated type: {:?}", goal); } fn consider_builtin_fn_ptr_trait_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { panic!("`FnPtr` does not have an associated type: {:?}", goal); } fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, @@ -355,11 +355,11 @@ where } fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let env_region = match goal_kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2), @@ -457,7 +457,7 @@ where } fn consider_builtin_async_fn_kind_helper_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { let [ @@ -489,7 +489,7 @@ where } let upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( - ecx.interner(), + ecx.cx(), goal_kind, tupled_inputs_ty.expect_ty(), tupled_upvars_ty.expect_ty(), @@ -504,17 +504,17 @@ where } fn consider_builtin_tuple_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { panic!("`Tuple` does not have an associated type: {:?}", goal); } fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let metadata_def_id = tcx.require_lang_item(TraitSolverLangItem::Metadata); assert_eq!(metadata_def_id, goal.predicate.def_id()); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { @@ -592,7 +592,7 @@ where } fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -601,7 +601,7 @@ where }; // Coroutines are not futures unless they come from `async` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_async(def_id) { return Err(NoSolution); } @@ -613,11 +613,7 @@ where CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new( - ecx.interner(), - goal.predicate.def_id(), - [self_ty], - ), + projection_term: ty::AliasTerm::new(ecx.cx(), goal.predicate.def_id(), [self_ty]), term, } .upcast(tcx), @@ -628,7 +624,7 @@ where } fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -637,7 +633,7 @@ where }; // Coroutines are not Iterators unless they come from `gen` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -649,11 +645,7 @@ where CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new( - ecx.interner(), - goal.predicate.def_id(), - [self_ty], - ), + projection_term: ty::AliasTerm::new(ecx.cx(), goal.predicate.def_id(), [self_ty]), term, } .upcast(tcx), @@ -664,14 +656,14 @@ where } fn consider_builtin_fused_iterator_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { panic!("`FusedIterator` does not have an associated type: {:?}", goal); } fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -680,7 +672,7 @@ where }; // Coroutines are not AsyncIterators unless they come from `gen` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_async_gen(def_id) { return Err(NoSolution); } @@ -707,7 +699,7 @@ where } fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -716,7 +708,7 @@ where }; // `async`-desugared coroutines do not implement the coroutine trait - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.is_general_coroutine(def_id) { return Err(NoSolution); } @@ -739,7 +731,7 @@ where goal, ty::ProjectionPredicate { projection_term: ty::AliasTerm::new( - ecx.interner(), + ecx.cx(), goal.predicate.def_id(), [self_ty, coroutine.resume_ty()], ), @@ -753,14 +745,14 @@ where } fn consider_structural_builtin_unsize_candidates( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Vec> { panic!("`Unsize` does not have an associated type: {:?}", goal); } fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -788,7 +780,7 @@ where | ty::Slice(_) | ty::Dynamic(_, _, _) | ty::Tuple(_) - | ty::Error(_) => self_ty.discriminant_ty(ecx.interner()), + | ty::Error(_) => self_ty.discriminant_ty(ecx.cx()), // We do not call `Ty::discriminant_ty` on alias, param, or placeholder // types, which return `::Discriminant` @@ -812,7 +804,7 @@ where } fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -835,7 +827,7 @@ where | ty::Str | ty::Slice(_) | ty::Tuple(_) - | ty::Error(_) => self_ty.async_destructor_ty(ecx.interner()), + | ty::Error(_) => self_ty.async_destructor_ty(ecx.cx()), // We do not call `Ty::async_destructor_ty` on alias, param, or placeholder // types, which return `::AsyncDestructor` @@ -865,23 +857,23 @@ where } fn consider_builtin_destruct_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { panic!("`Destruct` does not have an associated type: {:?}", goal); } fn consider_builtin_transmute_candidate( - _ecx: &mut EvalCtxt<'_, Infcx>, + _ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } } -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { fn translate_args( @@ -892,7 +884,7 @@ where impl_trait_ref: rustc_type_ir::TraitRef, target_container_def_id: I::DefId, ) -> Result { - let tcx = self.interner(); + let tcx = self.cx(); Ok(if target_container_def_id == impl_trait_ref.def_id { // Default value from the trait definition. No need to rebase. goal.predicate.alias.args diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index 710671b45d0e..f3494328d9e4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -6,19 +6,19 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_type_ir::inherent::*; use rustc_type_ir::{self as ty, Interner}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode}; -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { pub(super) fn normalize_opaque_type( &mut self, goal: Goal>, ) -> QueryResult { - let tcx = self.interner(); + let tcx = self.cx(); let opaque_ty = goal.predicate.alias; let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const"); @@ -34,7 +34,7 @@ where return Err(NoSolution); } // FIXME: This may have issues when the args contain aliases... - match uses_unique_placeholders_ignoring_regions(self.interner(), opaque_ty.args) { + match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { return self.evaluate_added_goals_and_make_canonical_response( Certainty::AMBIGUOUS, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs index 45341917bb24..27d5ae07729a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs @@ -6,19 +6,19 @@ use rustc_type_ir::{self as ty, Interner}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { pub(super) fn normalize_weak_type( &mut self, goal: Goal>, ) -> QueryResult { - let tcx = self.interner(); + let tcx = self.cx(); let weak_ty = goal.predicate.alias; // Check where clauses diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs index 4bb1fe5be6f0..a430dbb408c5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs @@ -1,12 +1,12 @@ use rustc_type_ir::{self as ty, Interner, ProjectionPredicate}; use tracing::instrument; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { #[instrument(level = "trace", skip(self), ret)] @@ -14,7 +14,7 @@ where &mut self, goal: Goal>, ) -> QueryResult { - let tcx = self.interner(); + let tcx = self.cx(); let projection_term = goal.predicate.projection_term.to_term(tcx); let goal = goal.with( tcx, diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index fc78a864f81a..d3ad55d6491b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -6,7 +6,7 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::Interner; use tracing::debug; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::{ CacheData, CanonicalInput, Certainty, QueryResult, SolverMode, FIXPOINT_STEP_LIMIT, @@ -255,12 +255,12 @@ impl SearchGraph { /// /// Given some goal which is proven via the `prove_goal` closure, this /// handles caching, overflow, and coinductive cycles. - pub(super) fn with_new_goal>( + pub(super) fn with_new_goal>( &mut self, tcx: I, input: CanonicalInput, - inspect: &mut ProofTreeBuilder, - mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, + inspect: &mut ProofTreeBuilder, + mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, ) -> QueryResult { self.check_invariants(); // Check for overflow. @@ -416,12 +416,12 @@ impl SearchGraph { /// Try to fetch a previously computed result from the global cache, /// making sure to only do so if it would match the result of reevaluating /// this goal. - fn lookup_global_cache>( + fn lookup_global_cache>( &mut self, tcx: I, input: CanonicalInput, available_depth: SolverLimit, - inspect: &mut ProofTreeBuilder, + inspect: &mut ProofTreeBuilder, ) -> Option> { let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self .global_cache(tcx) @@ -465,16 +465,16 @@ impl SearchGraph { /// of this we continuously recompute the cycle until the result /// of the previous iteration is equal to the final result, at which /// point we are done. - fn fixpoint_step_in_task( + fn fixpoint_step_in_task( &mut self, tcx: I, input: CanonicalInput, - inspect: &mut ProofTreeBuilder, + inspect: &mut ProofTreeBuilder, prove_goal: &mut F, ) -> StepResult where - Infcx: SolverDelegate, - F: FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, + D: SolverDelegate, + F: FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, { let result = prove_goal(self, inspect); let stack_entry = self.pop_stack(); diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index c0353f92bf8a..2ddb3c981db9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -8,7 +8,7 @@ use rustc_type_ir::visit::TypeVisitableExt as _; use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _}; use tracing::{instrument, trace}; -use crate::infcx::SolverDelegate; +use crate::delegate::SolverDelegate; use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; use crate::solve::assembly::{self, Candidate}; use crate::solve::inspect::ProbeKind; @@ -17,9 +17,9 @@ use crate::solve::{ NoSolution, QueryResult, Reveal, SolverMode, }; -impl assembly::GoalKind for TraitPredicate +impl assembly::GoalKind for TraitPredicate where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { fn self_ty(self) -> I::Ty { @@ -39,11 +39,11 @@ where } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal>, impl_def_id: I::DefId, ) -> Result, NoSolution> { - let tcx = ecx.interner(); + let tcx = ecx.cx(); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); if !tcx @@ -91,7 +91,7 @@ where } fn consider_error_guaranteed_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, _guar: I::ErrorGuaranteed, ) -> Result, NoSolution> { // FIXME: don't need to enter a probe here. @@ -100,11 +100,11 @@ where } fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, source: CandidateSource, goal: Goal, assumption: I::Clause, - then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult, ) -> Result, NoSolution> { if let Some(trait_clause) = assumption.as_trait_clause() { if trait_clause.def_id() == goal.predicate.def_id() @@ -128,7 +128,7 @@ where } fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -174,14 +174,14 @@ where } fn consider_trait_alias_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let tcx = ecx.interner(); + let tcx = ecx.cx(); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let nested_obligations = tcx @@ -195,7 +195,7 @@ where } fn consider_builtin_sized_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -210,7 +210,7 @@ where } fn consider_builtin_copy_clone_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -225,14 +225,14 @@ where } fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let tcx = ecx.interner(); + let tcx = ecx.cx(); // But if there are inference variables, we have to wait until it's resolved. if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() { return ecx.forced_ambiguity(MaybeCause::Ambiguity); @@ -247,7 +247,7 @@ where } fn consider_builtin_fn_ptr_trait_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { let self_ty = goal.predicate.self_ty(); @@ -278,7 +278,7 @@ where } fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { @@ -286,7 +286,7 @@ where return Err(NoSolution); } - let tcx = ecx.interner(); + let tcx = ecx.cx(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, @@ -319,7 +319,7 @@ where } fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { @@ -327,7 +327,7 @@ where return Err(NoSolution); } - let tcx = ecx.interner(); + let tcx = ecx.cx(); let (tupled_inputs_and_output_and_coroutine, nested_preds) = structural_traits::extract_tupled_inputs_and_output_from_async_callable( tcx, @@ -370,7 +370,7 @@ where } fn consider_builtin_async_fn_kind_helper_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else { @@ -397,7 +397,7 @@ where /// impl Tuple for (T1, .., Tn) {} /// ``` fn consider_builtin_tuple_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -413,7 +413,7 @@ where } fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -425,7 +425,7 @@ where } fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -437,7 +437,7 @@ where }; // Coroutines are not futures unless they come from `async` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_async(def_id) { return Err(NoSolution); } @@ -451,7 +451,7 @@ where } fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -463,7 +463,7 @@ where }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -477,7 +477,7 @@ where } fn consider_builtin_fused_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -489,7 +489,7 @@ where }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -501,7 +501,7 @@ where } fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -513,7 +513,7 @@ where }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.coroutine_is_async_gen(def_id) { return Err(NoSolution); } @@ -527,7 +527,7 @@ where } fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -540,7 +540,7 @@ where }; // `async`-desugared coroutines do not implement the coroutine trait - let tcx = ecx.interner(); + let tcx = ecx.cx(); if !tcx.is_general_coroutine(def_id) { return Err(NoSolution); } @@ -559,7 +559,7 @@ where } fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -572,7 +572,7 @@ where } fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -585,7 +585,7 @@ where } fn consider_builtin_destruct_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -601,7 +601,7 @@ where } fn consider_builtin_transmute_candidate( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -634,7 +634,7 @@ where /// impl<'a, T: Trait + 'a> Unsize for T {} /// ``` fn consider_structural_builtin_unsize_candidates( - ecx: &mut EvalCtxt<'_, Infcx>, + ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Vec> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { @@ -657,7 +657,7 @@ where return vec![]; }; - let goal = goal.with(ecx.interner(), (a_ty, b_ty)); + let goal = goal.with(ecx.cx(), (a_ty, b_ty)); match (a_ty.kind(), b_ty.kind()) { (ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"), @@ -705,9 +705,9 @@ where } } -impl EvalCtxt<'_, Infcx> +impl EvalCtxt<'_, D> where - Infcx: SolverDelegate, + D: SolverDelegate, I: Interner, { /// Trait upcasting allows for coercions between trait objects: @@ -727,7 +727,7 @@ where b_data: I::BoundExistentialPredicates, b_region: I::Region, ) -> Vec> { - let tcx = self.interner(); + let tcx = self.cx(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; let mut responses = vec![]; @@ -745,8 +745,7 @@ where )); } else if let Some(a_principal) = a_data.principal() { for new_a_principal in - Infcx::elaborate_supertraits(self.interner(), a_principal.with_self_ty(tcx, a_ty)) - .skip(1) + D::elaborate_supertraits(self.cx(), a_principal.with_self_ty(tcx, a_ty)).skip(1) { responses.extend(self.consider_builtin_upcast_to_principal( goal, @@ -771,7 +770,7 @@ where b_data: I::BoundExistentialPredicates, b_region: I::Region, ) -> Result, NoSolution> { - let tcx = self.interner(); + let tcx = self.cx(); let Goal { predicate: (a_ty, _), .. } = goal; // Can only unsize to an object-safe trait. @@ -825,10 +824,10 @@ where .auto_traits() .into_iter() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { - self.interner() + self.cx() .supertrait_def_ids(principal_def_id) .into_iter() - .filter(|def_id| self.interner().trait_is_auto(*def_id)) + .filter(|def_id| self.cx().trait_is_auto(*def_id)) })) .collect(); @@ -837,7 +836,7 @@ where // having any inference side-effects. We process obligations because // unification may initially succeed due to deferred projection equality. let projection_may_match = - |ecx: &mut EvalCtxt<'_, Infcx>, + |ecx: &mut EvalCtxt<'_, D>, source_projection: ty::Binder>, target_projection: ty::Binder>| { source_projection.item_def_id() == target_projection.item_def_id() @@ -896,7 +895,7 @@ where // Also require that a_ty's lifetime outlives b_ty's lifetime. ecx.add_goal( GoalSource::ImplWhereBound, - Goal::new(ecx.interner(), param_env, ty::OutlivesPredicate(a_region, b_region)), + Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)), ); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) @@ -942,7 +941,7 @@ where a_args: I::GenericArgs, b_args: I::GenericArgs, ) -> Result, NoSolution> { - let tcx = self.interner(); + let tcx = self.cx(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; let unsizing_params = tcx.unsizing_params_for_adt(def.def_id()); @@ -1002,7 +1001,7 @@ where a_tys: I::Tys, b_tys: I::Tys, ) -> Result, NoSolution> { - let tcx = self.interner(); + let tcx = self.cx(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; let (&a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); @@ -1062,11 +1061,9 @@ where // takes precedence over the structural auto trait candidate being // assembled. ty::Coroutine(def_id, _) - if self - .interner() - .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) => + if self.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) => { - match self.interner().coroutine_movability(def_id) { + match self.cx().coroutine_movability(def_id) { Movability::Static => Some(Err(NoSolution)), Movability::Movable => Some( self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { @@ -1111,7 +1108,7 @@ where | ty::Tuple(_) | ty::Adt(_, _) => { let mut disqualifying_impl = None; - self.interner().for_each_relevant_impl( + self.cx().for_each_relevant_impl( goal.predicate.def_id(), goal.predicate.self_ty(), |impl_def_id| { @@ -1140,7 +1137,7 @@ where source: CandidateSource, goal: Goal>, constituent_tys: impl Fn( - &EvalCtxt<'_, Infcx>, + &EvalCtxt<'_, D>, I::Ty, ) -> Result>, NoSolution>, ) -> Result, NoSolution> { @@ -1151,10 +1148,7 @@ where .into_iter() .map(|ty| { ecx.enter_forall(ty, |ty| { - goal.with( - ecx.interner(), - goal.predicate.with_self_ty(ecx.interner(), ty), - ) + goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty)) }) }) .collect::>(), diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 84dbd192723e..84c71c4bed29 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -14,7 +14,7 @@ passes_abi_of = fn_abi_of({$fn_name}) = {$fn_abi} passes_allow_incoherent_impl = - `rustc_allow_incoherent_impl` attribute should be applied to impl items. + `rustc_allow_incoherent_impl` attribute should be applied to impl items .label = the only currently supported targets are inherent methods passes_allow_internal_unstable = @@ -253,8 +253,8 @@ passes_doc_test_unknown_spotlight = .no_op_note = `doc(spotlight)` is now a no-op passes_duplicate_diagnostic_item_in_crate = - duplicate diagnostic item in crate `{$crate_name}`: `{$name}`. - .note = the diagnostic item is first defined in crate `{$orig_crate_name}`. + duplicate diagnostic item in crate `{$crate_name}`: `{$name}` + .note = the diagnostic item is first defined in crate `{$orig_crate_name}` passes_duplicate_feature_err = the feature `{$feature}` has already been declared @@ -263,27 +263,27 @@ passes_duplicate_lang_item = found duplicate lang item `{$lang_item_name}` .first_defined_span = the lang item is first defined here .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}` .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) .second_definition_local = second definition in the local crate (`{$crate_name}`) .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} passes_duplicate_lang_item_crate = - duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}`. + duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}` .first_defined_span = the lang item is first defined here .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}` .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) .second_definition_local = second definition in the local crate (`{$crate_name}`) .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} passes_duplicate_lang_item_crate_depends = - duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}`. + duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}` .first_defined_span = the lang item is first defined here .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on) - .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`. + .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}` .first_definition_local = first definition in the local crate (`{$orig_crate_name}`) .second_definition_local = second definition in the local crate (`{$crate_name}`) .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} @@ -315,7 +315,7 @@ passes_ffi_pure_invalid_target = `#[ffi_pure]` may only be used on foreign functions passes_has_incoherent_inherent_impl = - `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. + `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits .label = only adts, extern types and traits are supported passes_ignored_attr = diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 358f25e23343..4b9c36ad39fb 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -240,7 +240,7 @@ resolve_label_with_similar_name_reachable = resolve_lending_iterator_report_error = associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type - .note = you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type. + .note = you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type resolve_lifetime_param_in_enum_discriminant = lifetime parameters may not be used in enum discriminant values diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index e74c1208a395..44b31f2659c1 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -214,7 +214,7 @@ impl<'tcx> TypeFolder> for TransformTy<'tcx> { } } - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } } diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index b8dacc6968d3..b84280a3ccf3 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -82,9 +82,9 @@ session_octal_float_literal_not_supported = octal float literal is not supported session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg} -session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist. +session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist -session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist. +session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi` diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 9afd507ce113..dde5e30c3d07 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -533,6 +533,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> { Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables)) } + fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let sig = fn_ptr.internal(&mut *tables, tcx); + Ok(tables.fn_abi_of_fn_ptr(sig, List::empty())?.stable(&mut *tables)) + } + fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId { let mut tables = self.0.borrow_mut(); let def_id = tables.instances[def].def_id(); diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 98ed985738ad..83a554fe31de 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +derivative = "2.2.0" indexmap = { version = "2.0.0" } itoa = "1.0" md5 = { package = "md-5", version = "0.10.0" } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index ba0ad9230c86..483e32c64539 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -43,9 +43,15 @@ use std::hash::Hash; use tracing::{debug, trace}; /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct SyntaxContext(u32); +// To ensure correctness of incremental compilation, +// `SyntaxContext` must not implement `Ord` or `PartialOrd`. +// See https://github.com/rust-lang/rust/issues/90317. +impl !Ord for SyntaxContext {} +impl !PartialOrd for SyntaxContext {} + #[derive(Debug, Encodable, Decodable, Clone)] pub struct SyntaxContextData { outer_expn: ExpnId, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index b3f3899542d4..266956d63d71 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -467,46 +467,23 @@ impl FileName { /// `SpanData` is public because `Span` uses a thread-local interner and can't be /// sent to other threads, but some pieces of performance infra run in a separate thread. /// Using `Span` is generally preferred. -#[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[derive(Clone, Copy, Hash, PartialEq, Eq, derivative::Derivative)] +#[derivative(PartialOrd, Ord)] pub struct SpanData { pub lo: BytePos, pub hi: BytePos, /// Information about where the macro came from, if this piece of /// code was created by a macro expansion. + #[derivative(PartialOrd = "ignore", Ord = "ignore")] + // `SyntaxContext` does not implement `Ord`. + // The other fields are enough to determine in-file order. pub ctxt: SyntaxContext, + #[derivative(PartialOrd = "ignore", Ord = "ignore")] + // `LocalDefId` does not implement `Ord`. + // The other fields are enough to determine in-file order. pub parent: Option, } -// Order spans by position in the file. -impl Ord for SpanData { - fn cmp(&self, other: &Self) -> Ordering { - let SpanData { - lo: s_lo, - hi: s_hi, - ctxt: s_ctxt, - // `LocalDefId` does not implement `Ord`. - // The other fields are enough to determine in-file order. - parent: _, - } = self; - let SpanData { - lo: o_lo, - hi: o_hi, - ctxt: o_ctxt, - // `LocalDefId` does not implement `Ord`. - // The other fields are enough to determine in-file order. - parent: _, - } = other; - - (s_lo, s_hi, s_ctxt).cmp(&(o_lo, o_hi, o_ctxt)) - } -} - -impl PartialOrd for SpanData { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - impl SpanData { #[inline] pub fn span(&self) -> Span { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a508c2794390..a8123fe994c3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1593,6 +1593,8 @@ symbols! { rustc_do_not_const_check, rustc_doc_primitive, rustc_dummy, + rustc_dump_item_bounds, + rustc_dump_predicates, rustc_dump_user_args, rustc_dump_vtable, rustc_effective_visibility, @@ -2054,6 +2056,8 @@ symbols! { yes, yield_expr, ymm_reg, + zfh, + zfhmin, zmm_reg, } } diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs index 37184393a730..9d79faadd619 100644 --- a/compiler/rustc_target/src/asm/arm.rs +++ b/compiler/rustc_target/src/asm/arm.rs @@ -47,16 +47,18 @@ impl ArmInlineAsmRegClass { _arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option)] { match self { - Self::reg => types! { _: I8, I16, I32, F32; }, - Self::sreg | Self::sreg_low16 => types! { vfp2: I32, F32; }, + Self::reg => types! { _: I8, I16, I32, F16, F32; }, + Self::sreg | Self::sreg_low16 => types! { vfp2: I32, F16, F32; }, Self::dreg_low16 | Self::dreg_low8 => types! { - vfp2: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2); + vfp2: I64, F64; + neon: VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF16(4), VecF32(2); }, Self::dreg => types! { - d32: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2); + d32: I64, F64; + neon: VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF16(4), VecF32(2); }, Self::qreg | Self::qreg_low8 | Self::qreg_low4 => types! { - neon: VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4); + neon: VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4); }, } } diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs index 3845a0e14af0..02a4a5e2ece5 100644 --- a/compiler/rustc_target/src/asm/riscv.rs +++ b/compiler/rustc_target/src/asm/riscv.rs @@ -40,12 +40,13 @@ impl RiscVInlineAsmRegClass { match self { Self::reg => { if arch == InlineAsmArch::RiscV64 { - types! { _: I8, I16, I32, I64, F32, F64; } + types! { _: I8, I16, I32, I64, F16, F32, F64; } } else { - types! { _: I8, I16, I32, F32; } + types! { _: I8, I16, I32, F16, F32; } } } - Self::freg => types! { f: F32; d: F64; }, + // FIXME(f16_f128): Add `q: F128;` once LLVM support the `Q` extension. + Self::freg => types! { f: F16, F32; d: F64; }, Self::vreg => &[], } } diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index a7c8cc5a32b6..e47f5389cd18 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -1,7 +1,7 @@ pub use rustc_next_trait_solver::solve::*; +mod delegate; mod fulfill; -mod infcx; pub mod inspect; mod normalize; mod select; diff --git a/compiler/rustc_trait_selection/src/solve/infcx.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs similarity index 99% rename from compiler/rustc_trait_selection/src/solve/infcx.rs rename to compiler/rustc_trait_selection/src/solve/delegate.rs index e574166cbfc2..643d5f804808 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -39,10 +39,10 @@ impl<'tcx> Deref for SolverDelegate<'tcx> { } } -impl<'tcx> rustc_next_trait_solver::infcx::SolverDelegate for SolverDelegate<'tcx> { +impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<'tcx> { type Interner = TyCtxt<'tcx>; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.0.tcx } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 8937ed467a1f..76b88aeb0f7e 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -17,7 +17,7 @@ use rustc_span::symbol::sym; use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError}; -use super::infcx::SolverDelegate; +use super::delegate::SolverDelegate; use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; use super::Certainty; diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index cb621487125f..e8de8457440f 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -22,7 +22,7 @@ use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state} use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _}; use rustc_span::{Span, DUMMY_SP}; -use crate::solve::infcx::SolverDelegate; +use crate::solve::delegate::SolverDelegate; use crate::traits::ObligationCtxt; pub struct InspectConfig { diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index f42edebfcc42..2679da942b76 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -156,7 +156,7 @@ where { type Error = Vec; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.at.infcx.tcx } @@ -244,7 +244,7 @@ struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> { } impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.at.infcx.tcx } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 33074c20f575..b2fa3489dda2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -4936,7 +4936,7 @@ impl<'tcx> TypeFolder> for ReplaceImplTraitFolder<'tcx> { t.super_fold_with(self) } - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index b5f2d34852fc..d3096cf4b52c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -2840,7 +2840,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } impl<'a, 'tcx> TypeFolder> for ParamToVarFolder<'a, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index af6bfdae4402..662d95db8ba5 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -350,7 +350,7 @@ pub fn normalize_param_env_or_error<'tcx>( struct ConstNormalizer<'tcx>(TyCtxt<'tcx>); impl<'tcx> TypeFolder> for ConstNormalizer<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.0 } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index d7408eab84a4..a9ac0f7eb25b 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -163,7 +163,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { } impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.selcx.tcx() } @@ -217,7 +217,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx Reveal::UserFacing => ty.super_fold_with(self), Reveal::All => { - let recursion_limit = self.interner().recursion_limit(); + let recursion_limit = self.cx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { self.selcx.infcx.err_ctxt().report_overflow_error( OverflowCause::DeeplyNormalize(data.into()), @@ -228,8 +228,8 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx } let args = data.args.fold_with(self); - let generic_ty = self.interner().type_of(data.def_id); - let concrete_ty = generic_ty.instantiate(self.interner(), args); + let generic_ty = self.cx().type_of(data.def_id); + let concrete_ty = generic_ty.instantiate(self.cx(), args); self.depth += 1; let folded_ty = self.fold_ty(concrete_ty); self.depth -= 1; @@ -313,7 +313,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx normalized_ty } ty::Weak => { - let recursion_limit = self.interner().recursion_limit(); + let recursion_limit = self.cx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { self.selcx.infcx.err_ctxt().report_overflow_error( OverflowCause::DeeplyNormalize(data.into()), diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index e170d7cae937..bed76b84ee07 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -172,7 +172,7 @@ struct QueryNormalizer<'cx, 'tcx> { impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> { type Error = NoSolution; - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -217,7 +217,7 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> Reveal::All => { let args = data.args.try_fold_with(self)?; - let recursion_limit = self.interner().recursion_limit(); + let recursion_limit = self.cx().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { let guar = self @@ -229,15 +229,15 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> true, ) .delay_as_bug(); - return Ok(Ty::new_error(self.interner(), guar)); + return Ok(Ty::new_error(self.cx(), guar)); } - let generic_ty = self.interner().type_of(data.def_id); - let mut concrete_ty = generic_ty.instantiate(self.interner(), args); + let generic_ty = self.cx().type_of(data.def_id); + let mut concrete_ty = generic_ty.instantiate(self.cx(), args); self.anon_depth += 1; if concrete_ty == ty { concrete_ty = Ty::new_error_with_message( - self.interner(), + self.cx(), DUMMY_SP, "recursive opaque type", ); diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index c3fe816028e3..f132e36468ac 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -394,7 +394,7 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { } impl<'tcx> TypeFolder> for BoundVarReplacer<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -509,7 +509,7 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { } impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -550,7 +550,7 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - ty::Region::new_bound(self.interner(), db, *replace_var) + ty::Region::new_bound(self.cx(), db, *replace_var) } None => r1, } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 59de7c552af3..18b34f8d99b9 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -625,7 +625,7 @@ struct ArgFolder<'a, I: Interner> { impl<'a, I: Interner> TypeFolder for ArgFolder<'a, I> { #[inline] - fn interner(&self) -> I { + fn cx(&self) -> I { self.tcx } @@ -845,7 +845,7 @@ impl<'a, I: Interner> ArgFolder<'a, I> { return val; } - let result = ty::fold::shift_vars(TypeFolder::interner(self), val, self.binders_passed); + let result = ty::fold::shift_vars(TypeFolder::cx(self), val, self.binders_passed); debug!("shift_vars: shifted result = {:?}", result); result diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 26e365f64faa..953a438cb14d 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -129,7 +129,7 @@ pub trait TypeSuperFoldable: TypeFoldable { /// the infallible methods of this trait to ensure that the two APIs /// are coherent. pub trait TypeFolder: FallibleTypeFolder { - fn interner(&self) -> I; + fn cx(&self) -> I; fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder where @@ -167,7 +167,7 @@ pub trait TypeFolder: FallibleTypeFolder { pub trait FallibleTypeFolder: Sized { type Error; - fn interner(&self) -> I; + fn cx(&self) -> I; fn try_fold_binder(&mut self, t: ty::Binder) -> Result, Self::Error> where @@ -203,8 +203,8 @@ where { type Error = Never; - fn interner(&self) -> I { - TypeFolder::interner(self) + fn cx(&self) -> I { + TypeFolder::cx(self) } fn try_fold_binder(&mut self, t: ty::Binder) -> Result, Never> @@ -351,7 +351,7 @@ impl Shifter { } impl TypeFolder for Shifter { - fn interner(&self) -> I { + fn cx(&self) -> I { self.tcx } diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 97752934632c..3a17a27bd03b 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -521,7 +521,7 @@ struct FoldEscapingRegions { } impl TypeFolder for FoldEscapingRegions { - fn interner(&self) -> I { + fn cx(&self) -> I { self.interner } diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 3e138e3c2e04..44dbf549c1a7 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -215,6 +215,9 @@ pub trait Context { /// Get an instance ABI. fn instance_abi(&self, def: InstanceDef) -> Result; + /// Get the ABI of a function pointer. + fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result; + /// Get the layout of a type. fn ty_layout(&self, ty: Ty) -> Result; diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 35927237281a..8c120a96e75b 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -2,7 +2,7 @@ use super::{ mir::{Body, Mutability, Safety}, with, DefId, Error, Symbol, }; -use crate::abi::Layout; +use crate::abi::{FnAbi, Layout}; use crate::crate_def::{CrateDef, CrateDefType}; use crate::mir::alloc::{read_target_int, read_target_uint, AllocId}; use crate::mir::mono::StaticDef; @@ -996,6 +996,16 @@ pub struct AliasTerm { pub type PolyFnSig = Binder; +impl PolyFnSig { + /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. + /// + /// NB: this doesn't handle virtual calls - those should use `Instance::fn_abi` + /// instead, where the instance is an `InstanceKind::Virtual`. + pub fn fn_ptr_abi(self) -> Result { + with(|cx| cx.fn_ptr_abi(self)) + } +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct FnSig { pub inputs_and_output: Vec, diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 6677534eafc6..1833a7f477f0 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -424,29 +424,3 @@ pub mod __alloc_error_handler { } } } - -#[cfg(not(no_global_oom_handling))] -/// Specialize clones into pre-allocated, uninitialized memory. -/// Used by `Box::clone` and `Rc`/`Arc::make_mut`. -pub(crate) trait WriteCloneIntoRaw: Sized { - unsafe fn write_clone_into_raw(&self, target: *mut Self); -} - -#[cfg(not(no_global_oom_handling))] -impl WriteCloneIntoRaw for T { - #[inline] - default unsafe fn write_clone_into_raw(&self, target: *mut Self) { - // Having allocated *first* may allow the optimizer to create - // the cloned value in-place, skipping the local and move. - unsafe { target.write(self.clone()) }; - } -} - -#[cfg(not(no_global_oom_handling))] -impl WriteCloneIntoRaw for T { - #[inline] - unsafe fn write_clone_into_raw(&self, target: *mut Self) { - // We can always copy in-place, without ever involving a local value. - unsafe { target.copy_from_nonoverlapping(self, 1) }; - } -} diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 01a954ed75be..1ec095a46f70 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -188,6 +188,8 @@ use core::any::Any; use core::async_iter::AsyncIterator; use core::borrow; +#[cfg(not(no_global_oom_handling))] +use core::clone::CloneToUninit; use core::cmp::Ordering; use core::error::Error; use core::fmt; @@ -207,7 +209,7 @@ use core::slice; use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))] -use crate::alloc::{handle_alloc_error, WriteCloneIntoRaw}; +use crate::alloc::handle_alloc_error; use crate::alloc::{AllocError, Allocator, Global, Layout}; #[cfg(not(no_global_oom_handling))] use crate::borrow::Cow; @@ -1346,7 +1348,7 @@ impl Clone for Box { // Pre-allocate memory to allow writing the cloned value directly. let mut boxed = Self::new_uninit_in(self.1.clone()); unsafe { - (**self).write_clone_into_raw(boxed.as_mut_ptr()); + (**self).clone_to_uninit(boxed.as_mut_ptr()); boxed.assume_init() } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 022a14b931a3..ecb019b49c64 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -103,6 +103,7 @@ #![feature(assert_matches)] #![feature(async_fn_traits)] #![feature(async_iterator)] +#![feature(clone_to_uninit)] #![feature(coerce_unsized)] #![feature(const_align_of_val)] #![feature(const_box)] @@ -175,7 +176,6 @@ #![feature(const_mut_refs)] #![feature(const_precise_live_drops)] #![feature(const_ptr_write)] -#![feature(const_trait_impl)] #![feature(const_try)] #![feature(decl_macro)] #![feature(dropck_eyepatch)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 2b7ab2f6e259..3745ecb48c18 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -249,6 +249,8 @@ use std::boxed::Box; use core::any::Any; use core::borrow; use core::cell::Cell; +#[cfg(not(no_global_oom_handling))] +use core::clone::CloneToUninit; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; @@ -268,8 +270,6 @@ use core::slice::from_raw_parts_mut; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; -#[cfg(not(no_global_oom_handling))] -use crate::alloc::WriteCloneIntoRaw; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; #[cfg(not(no_global_oom_handling))] @@ -1749,7 +1749,8 @@ impl Rc { } } -impl Rc { +#[cfg(not(no_global_oom_handling))] +impl Rc { /// Makes a mutable reference into the given `Rc`. /// /// If there are other `Rc` pointers to the same allocation, then `make_mut` will @@ -1800,31 +1801,52 @@ impl Rc { /// assert!(76 == *data); /// assert!(weak.upgrade().is_none()); /// ``` - #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rc_unique", since = "1.4.0")] pub fn make_mut(this: &mut Self) -> &mut T { + let size_of_val = size_of_val::(&**this); + if Rc::strong_count(this) != 1 { // Gotta clone the data, there are other Rcs. - // Pre-allocate memory to allow writing the cloned value directly. - let mut rc = Self::new_uninit_in(this.alloc.clone()); - unsafe { - let data = Rc::get_mut_unchecked(&mut rc); - (**this).write_clone_into_raw(data.as_mut_ptr()); - *this = rc.assume_init(); - } + + let this_data_ref: &T = &**this; + // `in_progress` drops the allocation if we panic before finishing initializing it. + let mut in_progress: UniqueRcUninit = + UniqueRcUninit::new(this_data_ref, this.alloc.clone()); + + // Initialize with clone of this. + let initialized_clone = unsafe { + // Clone. If the clone panics, `in_progress` will be dropped and clean up. + this_data_ref.clone_to_uninit(in_progress.data_ptr()); + // Cast type of pointer, now that it is initialized. + in_progress.into_rc() + }; + + // Replace `this` with newly constructed Rc. + *this = initialized_clone; } else if Rc::weak_count(this) != 0 { // Can just steal the data, all that's left is Weaks - let mut rc = Self::new_uninit_in(this.alloc.clone()); + + // We don't need panic-protection like the above branch does, but we might as well + // use the same mechanism. + let mut in_progress: UniqueRcUninit = + UniqueRcUninit::new(&**this, this.alloc.clone()); unsafe { - let data = Rc::get_mut_unchecked(&mut rc); - data.as_mut_ptr().copy_from_nonoverlapping(&**this, 1); + // Initialize `in_progress` with move of **this. + // We have to express this in terms of bytes because `T: ?Sized`; there is no + // operation that just copies a value based on its `size_of_val()`. + ptr::copy_nonoverlapping( + ptr::from_ref(&**this).cast::(), + in_progress.data_ptr().cast::(), + size_of_val, + ); this.inner().dec_strong(); // Remove implicit strong-weak ref (no need to craft a fake // Weak here -- we know other Weaks can clean up for us) this.inner().dec_weak(); - ptr::write(this, rc.assume_init()); + // Replace `this` with newly constructed Rc that has the moved data. + ptr::write(this, in_progress.into_rc()); } } // This unsafety is ok because we're guaranteed that the pointer @@ -3686,3 +3708,67 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc { } } } + +/// A unique owning pointer to a [`RcBox`] **that does not imply the contents are initialized,** +/// but will deallocate it (without dropping the value) when dropped. +/// +/// This is a helper for [`Rc::make_mut()`] to ensure correct cleanup on panic. +/// It is nearly a duplicate of `UniqueRc, A>` except that it allows `T: !Sized`, +/// which `MaybeUninit` does not. +#[cfg(not(no_global_oom_handling))] +struct UniqueRcUninit { + ptr: NonNull>, + layout_for_value: Layout, + alloc: Option, +} + +#[cfg(not(no_global_oom_handling))] +impl UniqueRcUninit { + /// Allocate a RcBox with layout suitable to contain `for_value` or a clone of it. + fn new(for_value: &T, alloc: A) -> UniqueRcUninit { + let layout = Layout::for_value(for_value); + let ptr = unsafe { + Rc::allocate_for_layout( + layout, + |layout_for_rcbox| alloc.allocate(layout_for_rcbox), + |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcBox), + ) + }; + Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) } + } + + /// Returns the pointer to be written into to initialize the [`Rc`]. + fn data_ptr(&mut self) -> *mut T { + let offset = data_offset_align(self.layout_for_value.align()); + unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } + } + + /// Upgrade this into a normal [`Rc`]. + /// + /// # Safety + /// + /// The data must have been initialized (by writing to [`Self::data_ptr()`]). + unsafe fn into_rc(mut self) -> Rc { + let ptr = self.ptr; + let alloc = self.alloc.take().unwrap(); + mem::forget(self); + // SAFETY: The pointer is valid as per `UniqueRcUninit::new`, and the caller is responsible + // for having initialized the data. + unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) } + } +} + +#[cfg(not(no_global_oom_handling))] +impl Drop for UniqueRcUninit { + fn drop(&mut self) { + // SAFETY: + // * new() produced a pointer safe to deallocate. + // * We own the pointer unless into_rc() was called, which forgets us. + unsafe { + self.alloc + .take() + .unwrap() + .deallocate(self.ptr.cast(), rcbox_layout_for_value_layout(self.layout_for_value)); + } + } +} diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 0f09be7721fa..5e2e4beb94a2 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -316,6 +316,24 @@ fn test_cowrc_clone_weak() { assert!(cow1_weak.upgrade().is_none()); } +/// This is similar to the doc-test for `Rc::make_mut()`, but on an unsized type (slice). +#[test] +fn test_cowrc_unsized() { + use std::rc::Rc; + + let mut data: Rc<[i32]> = Rc::new([10, 20, 30]); + + Rc::make_mut(&mut data)[0] += 1; // Won't clone anything + let mut other_data = Rc::clone(&data); // Won't clone inner data + Rc::make_mut(&mut data)[1] += 1; // Clones inner data + Rc::make_mut(&mut data)[2] += 1; // Won't clone anything + Rc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything + + // Now `data` and `other_data` point to different allocations. + assert_eq!(*data, [11, 21, 31]); + assert_eq!(*other_data, [110, 20, 30]); +} + #[test] fn test_show() { let foo = Rc::new(75); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index f9d884e0ea55..90672164cb93 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -10,6 +10,8 @@ use core::any::Any; use core::borrow; +#[cfg(not(no_global_oom_handling))] +use core::clone::CloneToUninit; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; @@ -30,8 +32,6 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; -#[cfg(not(no_global_oom_handling))] -use crate::alloc::WriteCloneIntoRaw; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; @@ -2150,7 +2150,8 @@ unsafe impl DerefPure for Arc {} #[unstable(feature = "receiver_trait", issue = "none")] impl Receiver for Arc {} -impl Arc { +#[cfg(not(no_global_oom_handling))] +impl Arc { /// Makes a mutable reference into the given `Arc`. /// /// If there are other `Arc` pointers to the same allocation, then `make_mut` will @@ -2201,10 +2202,11 @@ impl Arc { /// assert!(76 == *data); /// assert!(weak.upgrade().is_none()); /// ``` - #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "arc_unique", since = "1.4.0")] pub fn make_mut(this: &mut Self) -> &mut T { + let size_of_val = mem::size_of_val::(&**this); + // Note that we hold both a strong reference and a weak reference. // Thus, releasing our strong reference only will not, by itself, cause // the memory to be deallocated. @@ -2215,13 +2217,19 @@ impl Arc { // deallocated. if this.inner().strong.compare_exchange(1, 0, Acquire, Relaxed).is_err() { // Another strong pointer exists, so we must clone. - // Pre-allocate memory to allow writing the cloned value directly. - let mut arc = Self::new_uninit_in(this.alloc.clone()); - unsafe { - let data = Arc::get_mut_unchecked(&mut arc); - (**this).write_clone_into_raw(data.as_mut_ptr()); - *this = arc.assume_init(); - } + + let this_data_ref: &T = &**this; + // `in_progress` drops the allocation if we panic before finishing initializing it. + let mut in_progress: UniqueArcUninit = + UniqueArcUninit::new(this_data_ref, this.alloc.clone()); + + let initialized_clone = unsafe { + // Clone. If the clone panics, `in_progress` will be dropped and clean up. + this_data_ref.clone_to_uninit(in_progress.data_ptr()); + // Cast type of pointer, now that it is initialized. + in_progress.into_arc() + }; + *this = initialized_clone; } else if this.inner().weak.load(Relaxed) != 1 { // Relaxed suffices in the above because this is fundamentally an // optimization: we are always racing with weak pointers being @@ -2240,11 +2248,22 @@ impl Arc { let _weak = Weak { ptr: this.ptr, alloc: this.alloc.clone() }; // Can just steal the data, all that's left is Weaks - let mut arc = Self::new_uninit_in(this.alloc.clone()); + // + // We don't need panic-protection like the above branch does, but we might as well + // use the same mechanism. + let mut in_progress: UniqueArcUninit = + UniqueArcUninit::new(&**this, this.alloc.clone()); unsafe { - let data = Arc::get_mut_unchecked(&mut arc); - data.as_mut_ptr().copy_from_nonoverlapping(&**this, 1); - ptr::write(this, arc.assume_init()); + // Initialize `in_progress` with move of **this. + // We have to express this in terms of bytes because `T: ?Sized`; there is no + // operation that just copies a value based on its `size_of_val()`. + ptr::copy_nonoverlapping( + ptr::from_ref(&**this).cast::(), + in_progress.data_ptr().cast::(), + size_of_val, + ); + + ptr::write(this, in_progress.into_arc()); } } else { // We were the sole reference of either kind; bump back up the @@ -3809,6 +3828,68 @@ fn data_offset_align(align: usize) -> usize { layout.size() + layout.padding_needed_for(align) } +/// A unique owning pointer to a [`ArcInner`] **that does not imply the contents are initialized,** +/// but will deallocate it (without dropping the value) when dropped. +/// +/// This is a helper for [`Arc::make_mut()`] to ensure correct cleanup on panic. +#[cfg(not(no_global_oom_handling))] +struct UniqueArcUninit { + ptr: NonNull>, + layout_for_value: Layout, + alloc: Option, +} + +#[cfg(not(no_global_oom_handling))] +impl UniqueArcUninit { + /// Allocate a ArcInner with layout suitable to contain `for_value` or a clone of it. + fn new(for_value: &T, alloc: A) -> UniqueArcUninit { + let layout = Layout::for_value(for_value); + let ptr = unsafe { + Arc::allocate_for_layout( + layout, + |layout_for_arcinner| alloc.allocate(layout_for_arcinner), + |mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const ArcInner), + ) + }; + Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) } + } + + /// Returns the pointer to be written into to initialize the [`Arc`]. + fn data_ptr(&mut self) -> *mut T { + let offset = data_offset_align(self.layout_for_value.align()); + unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T } + } + + /// Upgrade this into a normal [`Arc`]. + /// + /// # Safety + /// + /// The data must have been initialized (by writing to [`Self::data_ptr()`]). + unsafe fn into_arc(mut self) -> Arc { + let ptr = self.ptr; + let alloc = self.alloc.take().unwrap(); + mem::forget(self); + // SAFETY: The pointer is valid as per `UniqueArcUninit::new`, and the caller is responsible + // for having initialized the data. + unsafe { Arc::from_ptr_in(ptr.as_ptr(), alloc) } + } +} + +#[cfg(not(no_global_oom_handling))] +impl Drop for UniqueArcUninit { + fn drop(&mut self) { + // SAFETY: + // * new() produced a pointer safe to deallocate. + // * We own the pointer unless into_arc() was called, which forgets us. + unsafe { + self.alloc.take().unwrap().deallocate( + self.ptr.cast(), + arcinner_layout_for_value_layout(self.layout_for_value), + ); + } + } +} + #[stable(feature = "arc_error", since = "1.52.0")] impl core::error::Error for Arc { #[allow(deprecated, deprecated_in_future)] diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs index d564a30b1039..c37a80dca95c 100644 --- a/library/alloc/tests/arc.rs +++ b/library/alloc/tests/arc.rs @@ -209,3 +209,21 @@ fn weak_may_dangle() { // `val` dropped here while still borrowed // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak` } + +/// This is similar to the doc-test for `Arc::make_mut()`, but on an unsized type (slice). +#[test] +fn make_mut_unsized() { + use alloc::sync::Arc; + + let mut data: Arc<[i32]> = Arc::new([10, 20, 30]); + + Arc::make_mut(&mut data)[0] += 1; // Won't clone anything + let mut other_data = Arc::clone(&data); // Won't clone inner data + Arc::make_mut(&mut data)[1] += 1; // Clones inner data + Arc::make_mut(&mut data)[2] += 1; // Won't clone anything + Arc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything + + // Now `data` and `other_data` point to different allocations. + assert_eq!(*data, [11, 21, 31]); + assert_eq!(*other_data, [110, 20, 30]); +} diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index d448c5338fc4..d7ce65f6c53a 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -36,6 +36,9 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::mem::{self, MaybeUninit}; +use crate::ptr; + /// A common trait for the ability to explicitly duplicate an object. /// /// Differs from [`Copy`] in that [`Copy`] is implicit and an inexpensive bit-wise copy, while @@ -204,6 +207,189 @@ pub struct AssertParamIsCopy { _field: crate::marker::PhantomData, } +/// A generalization of [`Clone`] to dynamically-sized types stored in arbitrary containers. +/// +/// This trait is implemented for all types implementing [`Clone`], and also [slices](slice) of all +/// such types. You may also implement this trait to enable cloning trait objects and custom DSTs +/// (structures containing dynamically-sized fields). +/// +/// # Safety +/// +/// Implementations must ensure that when `.clone_to_uninit(dst)` returns normally rather than +/// panicking, it always leaves `*dst` initialized as a valid value of type `Self`. +/// +/// # See also +/// +/// * [`Clone::clone_from`] is a safe function which may be used instead when `Self` is a [`Sized`] +/// and the destination is already initialized; it may be able to reuse allocations owned by +/// the destination. +/// * [`ToOwned`], which allocates a new destination container. +/// +/// [`ToOwned`]: ../../std/borrow/trait.ToOwned.html +#[unstable(feature = "clone_to_uninit", issue = "126799")] +pub unsafe trait CloneToUninit { + /// Performs copy-assignment from `self` to `dst`. + /// + /// This is analogous to to `std::ptr::write(dst, self.clone())`, + /// except that `self` may be a dynamically-sized type ([`!Sized`](Sized)). + /// + /// Before this function is called, `dst` may point to uninitialized memory. + /// After this function is called, `dst` will point to initialized memory; it will be + /// sound to create a `&Self` reference from the pointer. + /// + /// # Safety + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * `dst` must be [valid] for writes. + /// * `dst` must be properly aligned. + /// * `dst` must have the same [pointer metadata] (slice length or `dyn` vtable) as `self`. + /// + /// [valid]: ptr#safety + /// [pointer metadata]: crate::ptr::metadata() + /// + /// # Panics + /// + /// This function may panic. (For example, it might panic if memory allocation for a clone + /// of a value owned by `self` fails.) + /// If the call panics, then `*dst` should be treated as uninitialized memory; it must not be + /// read or dropped, because even if it was previously valid, it may have been partially + /// overwritten. + /// + /// The caller may also need to take care to deallocate the allocation pointed to by `dst`, + /// if applicable, to avoid a memory leak, and may need to take other precautions to ensure + /// soundness in the presence of unwinding. + /// + /// Implementors should avoid leaking values by, upon unwinding, dropping all component values + /// that might have already been created. (For example, if a `[Foo]` of length 3 is being + /// cloned, and the second of the three calls to `Foo::clone()` unwinds, then the first `Foo` + /// cloned should be dropped.) + unsafe fn clone_to_uninit(&self, dst: *mut Self); +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for T { + default unsafe fn clone_to_uninit(&self, dst: *mut Self) { + // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of + // ptr::write(). + unsafe { + // We hope the optimizer will figure out to create the cloned value in-place, + // skipping ever storing it on the stack and the copy to the destination. + ptr::write(dst, self.clone()); + } + } +} + +// Specialized implementation for types that are [`Copy`], not just [`Clone`], +// and can therefore be copied bitwise. +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for T { + unsafe fn clone_to_uninit(&self, dst: *mut Self) { + // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of + // ptr::copy_nonoverlapping(). + unsafe { + ptr::copy_nonoverlapping(self, dst, 1); + } + } +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for [T] { + #[cfg_attr(debug_assertions, track_caller)] + default unsafe fn clone_to_uninit(&self, dst: *mut Self) { + let len = self.len(); + // This is the most likely mistake to make, so check it as a debug assertion. + debug_assert_eq!( + len, + dst.len(), + "clone_to_uninit() source and destination must have equal lengths", + ); + + // SAFETY: The produced `&mut` is valid because: + // * The caller is obligated to provide a pointer which is valid for writes. + // * All bytes pointed to are in MaybeUninit, so we don't care about the memory's + // initialization status. + let uninit_ref = unsafe { &mut *(dst as *mut [MaybeUninit]) }; + + // Copy the elements + let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref); + for element_ref in self.iter() { + // If the clone() panics, `initializing` will take care of the cleanup. + initializing.push(element_ref.clone()); + } + // If we reach here, then the entire slice is initialized, and we've satisfied our + // responsibilities to the caller. Disarm the cleanup guard by forgetting it. + mem::forget(initializing); + } +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for [T] { + #[cfg_attr(debug_assertions, track_caller)] + unsafe fn clone_to_uninit(&self, dst: *mut Self) { + let len = self.len(); + // This is the most likely mistake to make, so check it as a debug assertion. + debug_assert_eq!( + len, + dst.len(), + "clone_to_uninit() source and destination must have equal lengths", + ); + + // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of + // ptr::copy_nonoverlapping(). + unsafe { + ptr::copy_nonoverlapping(self.as_ptr(), dst.as_mut_ptr(), len); + } + } +} + +/// Ownership of a collection of values stored in a non-owned `[MaybeUninit]`, some of which +/// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation. +/// Its responsibility is to provide cleanup on unwind by dropping the values that *are* +/// initialized, unless disarmed by forgetting. +/// +/// This is a helper for `impl CloneToUninit for [T]`. +struct InitializingSlice<'a, T> { + data: &'a mut [MaybeUninit], + /// Number of elements of `*self.data` that are initialized. + initialized_len: usize, +} + +impl<'a, T> InitializingSlice<'a, T> { + #[inline] + fn from_fully_uninit(data: &'a mut [MaybeUninit]) -> Self { + Self { data, initialized_len: 0 } + } + + /// Push a value onto the end of the initialized part of the slice. + /// + /// # Panics + /// + /// Panics if the slice is already fully initialized. + #[inline] + fn push(&mut self, value: T) { + MaybeUninit::write(&mut self.data[self.initialized_len], value); + self.initialized_len += 1; + } +} + +impl<'a, T> Drop for InitializingSlice<'a, T> { + #[cold] // will only be invoked on unwind + fn drop(&mut self) { + let initialized_slice = ptr::slice_from_raw_parts_mut( + MaybeUninit::slice_as_mut_ptr(self.data), + self.initialized_len, + ); + // SAFETY: + // * the pointer is valid because it was made from a mutable reference + // * `initialized_len` counts the initialized elements as an invariant of this type, + // so each of the pointed-to elements is initialized and may be dropped. + unsafe { + ptr::drop_in_place::<[T]>(initialized_slice); + } + } +} + /// Implementations of `Clone` for primitive types. /// /// Implementations that cannot be described in Rust diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index f3f757ce69df..cff75870790c 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -245,7 +245,6 @@ use self::Ordering::*; append_const_msg )] #[rustc_diagnostic_item = "PartialEq"] -#[const_trait] pub trait PartialEq { /// This method tests for `self` and `other` values to be equal, and is used /// by `==`. @@ -1475,8 +1474,7 @@ mod impls { macro_rules! partial_eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] - impl const PartialEq for $t { + impl PartialEq for $t { #[inline] fn eq(&self, other: &$t) -> bool { (*self) == (*other) } #[inline] diff --git a/library/core/src/escape.rs b/library/core/src/escape.rs index f6ec30b9f793..b213cc2b9167 100644 --- a/library/core/src/escape.rs +++ b/library/core/src/escape.rs @@ -60,7 +60,7 @@ const fn escape_ascii(byte: u8) -> ([ascii::Char; N], Range) const fn escape_unicode(c: char) -> ([ascii::Char; N], Range) { const { assert!(N >= 10 && N < u8::MAX as usize) }; - let c = u32::from(c); + let c = c as u32; // OR-ing `1` ensures that for `c == 0` the code computes that // one digit should be printed. diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 297f52e756bc..d2a408485d16 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -515,7 +515,10 @@ impl CStr { #[inline] #[must_use] const fn as_non_null_ptr(&self) -> NonNull { - NonNull::from(&self.inner).as_non_null_ptr() + // FIXME(effects) replace with `NonNull::from` + // SAFETY: a reference is never null + unsafe { NonNull::new_unchecked(&self.inner as *const [c_char] as *mut [c_char]) } + .as_non_null_ptr() } /// Returns the length of `self`. Like C's `strlen`, this does not include the nul terminator. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 94ad8fbd5df0..2d0b8825f433 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -200,6 +200,7 @@ // Language features: // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(c_unwind))] +#![cfg_attr(bootstrap, feature(effects))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] @@ -214,13 +215,11 @@ #![feature(const_mut_refs)] #![feature(const_precise_live_drops)] #![feature(const_refs_to_cell)] -#![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] #![feature(doc_cfg_hide)] #![feature(doc_notable_trait)] -#![feature(effects)] #![feature(extern_types)] #![feature(f128)] #![feature(f16)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 1d073a6d649b..2e8be7bde4bc 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -944,7 +944,6 @@ marker_impls! { #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] #[rustc_deny_explicit_impl(implement_via_object = false)] -#[const_trait] pub trait Destruct {} /// A marker for tuple types. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 448894849639..d40e02352a1d 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -484,7 +484,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) { overflow_panic::add() } else { a } + if b { overflow_panic::add() } else { a } } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow @@ -580,7 +580,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_add_unsigned(self, rhs: $UnsignedT) -> Self { let (a, b) = self.overflowing_add_unsigned(rhs); - if unlikely!(b) { overflow_panic::add() } else { a } + if b { overflow_panic::add() } else { a } } /// Checked integer subtraction. Computes `self - rhs`, returning `None` if @@ -636,7 +636,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) { overflow_panic::sub() } else { a } + if b { overflow_panic::sub() } else { a } } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow @@ -732,7 +732,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_sub_unsigned(self, rhs: $UnsignedT) -> Self { let (a, b) = self.overflowing_sub_unsigned(rhs); - if unlikely!(b) { overflow_panic::sub() } else { a } + if b { overflow_panic::sub() } else { a } } /// Checked integer multiplication. Computes `self * rhs`, returning `None` if @@ -788,7 +788,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) { overflow_panic::mul() } else { a } + if b { overflow_panic::mul() } else { a } } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow @@ -902,7 +902,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_div(self, rhs: Self) -> Self { let (a, b) = self.overflowing_div(rhs); - if unlikely!(b) { overflow_panic::div() } else { a } + if b { overflow_panic::div() } else { a } } /// Checked Euclidean division. Computes `self.div_euclid(rhs)`, @@ -976,7 +976,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_div_euclid(self, rhs: Self) -> Self { let (a, b) = self.overflowing_div_euclid(rhs); - if unlikely!(b) { overflow_panic::div() } else { a } + if b { overflow_panic::div() } else { a } } /// Checked integer remainder. Computes `self % rhs`, returning `None` if @@ -1049,7 +1049,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_rem(self, rhs: Self) -> Self { let (a, b) = self.overflowing_rem(rhs); - if unlikely!(b) { overflow_panic::rem() } else { a } + if b { overflow_panic::rem() } else { a } } /// Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` @@ -1122,7 +1122,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_rem_euclid(self, rhs: Self) -> Self { let (a, b) = self.overflowing_rem_euclid(rhs); - if unlikely!(b) { overflow_panic::rem() } else { a } + if b { overflow_panic::rem() } else { a } } /// Checked negation. Computes `-self`, returning `None` if `self == MIN`. @@ -1210,7 +1210,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_neg(self) -> Self { let (a, b) = self.overflowing_neg(); - if unlikely!(b) { overflow_panic::neg() } else { a } + if b { overflow_panic::neg() } else { a } } /// Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger @@ -1273,7 +1273,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_shl(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) { overflow_panic::shl() } else { a } + if b { overflow_panic::shl() } else { a } } /// Unchecked shift left. Computes `self << rhs`, assuming that @@ -1371,7 +1371,7 @@ macro_rules! int_impl { #[track_caller] pub const fn strict_shr(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) { overflow_panic::shr() } else { a } + if b { overflow_panic::shr() } else { a } } /// Unchecked shift right. Computes `self >> rhs`, assuming that diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 5956a08593ad..0c6f06dc017e 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -33,7 +33,6 @@ use super::{IntErrorKind, ParseIntError}; reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] -#[const_trait] pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed { #[doc(hidden)] type NonZeroInner: Sized + Copy; @@ -47,7 +46,6 @@ macro_rules! impl_zeroable_primitive { reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] - #[const_trait] pub trait Sealed {} $( @@ -70,14 +68,14 @@ macro_rules! impl_zeroable_primitive { reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] - impl const private::Sealed for $primitive {} + impl private::Sealed for $primitive {} #[unstable( feature = "nonzero_internals", reason = "implementation detail which may disappear or be replaced at any time", issue = "none" )] - unsafe impl const ZeroablePrimitive for $primitive { + unsafe impl ZeroablePrimitive for $primitive { type NonZeroInner = private::$NonZeroInner; } )+ diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index cdbd695008e8..00450c2cda3e 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -491,7 +491,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_add(self, rhs: Self) -> Self { let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) { overflow_panic ::add()} else {a} + if b { overflow_panic::add() } else { a } } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow @@ -593,7 +593,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_add_signed(self, rhs: $SignedT) -> Self { let (a, b) = self.overflowing_add_signed(rhs); - if unlikely!(b) { overflow_panic ::add()} else {a} + if b { overflow_panic::add() } else { a } } /// Checked integer subtraction. Computes `self - rhs`, returning @@ -658,7 +658,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_sub(self, rhs: Self) -> Self { let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) { overflow_panic ::sub()} else {a} + if b { overflow_panic::sub() } else { a } } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow @@ -779,7 +779,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_mul(self, rhs: Self) -> Self { let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) { overflow_panic ::mul()} else {a} + if b { overflow_panic::mul() } else { a } } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow @@ -1304,7 +1304,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_neg(self) -> Self { let (a, b) = self.overflowing_neg(); - if unlikely!(b) { overflow_panic::neg() } else { a } + if b { overflow_panic::neg() } else { a } } /// Checked shift left. Computes `self << rhs`, returning `None` @@ -1367,7 +1367,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_shl(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) { overflow_panic::shl() } else { a } + if b { overflow_panic::shl() } else { a } } /// Unchecked shift left. Computes `self << rhs`, assuming that @@ -1465,7 +1465,7 @@ macro_rules! uint_impl { #[track_caller] pub const fn strict_shr(self, rhs: u32) -> Self { let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) { overflow_panic::shr() } else { a } + if b { overflow_panic::shr() } else { a } } /// Unchecked shift right. Computes `self >> rhs`, assuming that diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 5e77788d8ea3..133ae04f0261 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -73,7 +73,6 @@ append_const_msg )] #[doc(alias = "+")] -#[const_trait] pub trait Add { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -95,8 +94,7 @@ pub trait Add { macro_rules! add_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ops", issue = "90080")] - impl const Add for $t { + impl Add for $t { type Output = $t; #[inline] diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 3d21b09fa8a0..86a965f68e08 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -282,7 +282,7 @@ impl<'a> Context<'a> { pub const fn ext(&mut self) -> &mut dyn Any { // FIXME: this field makes Context extra-weird about unwind safety // can we justify AssertUnwindSafe if we stabilize this? do we care? - match &mut *self.ext { + match &mut self.ext.0 { ExtData::Some(data) => *data, ExtData::None(unit) => unit, } @@ -356,7 +356,7 @@ impl<'a> ContextBuilder<'a> { #[rustc_const_unstable(feature = "const_waker", issue = "102012")] #[unstable(feature = "context_ext", issue = "123392")] pub const fn from(cx: &'a mut Context<'_>) -> Self { - let ext = match &mut *cx.ext { + let ext = match &mut cx.ext.0 { ExtData::Some(ext) => ExtData::Some(*ext), ExtData::None(()) => ExtData::None(()), }; diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs index 64193e115589..23efab2f1b59 100644 --- a/library/core/tests/clone.rs +++ b/library/core/tests/clone.rs @@ -1,3 +1,6 @@ +use core::clone::CloneToUninit; +use core::mem::MaybeUninit; + #[test] #[allow(suspicious_double_ref_op)] fn test_borrowed_clone() { @@ -14,3 +17,66 @@ fn test_clone_from() { b.clone_from(&a); assert_eq!(*b, 5); } + +#[test] +fn test_clone_to_uninit_slice_success() { + // Using `String`s to exercise allocation and Drop of the individual elements; + // if something is aliased or double-freed, at least Miri will catch that. + let a: [String; 3] = ["a", "b", "c"].map(String::from); + + let mut storage: MaybeUninit<[String; 3]> = MaybeUninit::uninit(); + let b: [String; 3] = unsafe { + a[..].clone_to_uninit(storage.as_mut_ptr() as *mut [String]); + storage.assume_init() + }; + + assert_eq!(a, b); +} + +#[test] +#[cfg(panic = "unwind")] +fn test_clone_to_uninit_slice_drops_on_panic() { + use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; + + /// A static counter is OK to use as long as _this one test_ isn't run several times in + /// multiple threads. + static COUNTER: AtomicUsize = AtomicUsize::new(0); + /// Counts how many instances are live, and panics if a fifth one is created + struct CountsDropsAndPanics {} + impl CountsDropsAndPanics { + fn new() -> Self { + COUNTER.fetch_add(1, Relaxed); + Self {} + } + } + impl Clone for CountsDropsAndPanics { + fn clone(&self) -> Self { + if COUNTER.load(Relaxed) == 4 { panic!("intentional panic") } else { Self::new() } + } + } + impl Drop for CountsDropsAndPanics { + fn drop(&mut self) { + COUNTER.fetch_sub(1, Relaxed); + } + } + + let a: [CountsDropsAndPanics; 3] = core::array::from_fn(|_| CountsDropsAndPanics::new()); + assert_eq!(COUNTER.load(Relaxed), 3); + + let panic_payload = std::panic::catch_unwind(|| { + let mut storage: MaybeUninit<[CountsDropsAndPanics; 3]> = MaybeUninit::uninit(); + // This should panic halfway through + unsafe { + a[..].clone_to_uninit(storage.as_mut_ptr() as *mut [CountsDropsAndPanics]); + } + }) + .unwrap_err(); + assert_eq!(panic_payload.downcast().unwrap(), Box::new("intentional panic")); + + // Check for lack of leak, which is what this test is looking for + assert_eq!(COUNTER.load(Relaxed), 3, "leaked during clone!"); + + // Might as well exercise the rest of the drops + drop(a); + assert_eq!(COUNTER.load(Relaxed), 0); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 6845a630dff3..3a2c98db0d50 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -8,6 +8,7 @@ #![feature(async_iterator)] #![feature(bigint_helper_methods)] #![feature(cell_update)] +#![feature(clone_to_uninit)] #![feature(const_align_offset)] #![feature(const_align_of_val_raw)] #![feature(const_black_box)] @@ -53,6 +54,7 @@ #![feature(slice_split_once)] #![feature(split_as_slice)] #![feature(maybe_uninit_fill)] +#![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_write_slice)] #![feature(maybe_uninit_uninit_array_transpose)] diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml index dce2da316444..f830808d1964 100644 --- a/library/panic_unwind/Cargo.toml +++ b/library/panic_unwind/Cargo.toml @@ -16,7 +16,7 @@ alloc = { path = "../alloc" } core = { path = "../core" } unwind = { path = "../unwind" } compiler_builtins = "0.1.0" -cfg-if = "1.0" +cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2", default-features = false } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index cf9a3446522c..6413b3515ece 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2742,18 +2742,15 @@ impl AsInnerMut for DirBuilder { /// # Examples /// /// ```no_run -/// #![feature(fs_try_exists)] /// use std::fs; /// -/// assert!(!fs::try_exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt")); -/// assert!(fs::try_exists("/root/secret_file.txt").is_err()); +/// assert!(!fs::exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt")); +/// assert!(fs::exists("/root/secret_file.txt").is_err()); /// ``` /// /// [`Path::exists`]: crate::path::Path::exists -// FIXME: stabilization should modify documentation of `exists()` to recommend this method -// instead. -#[unstable(feature = "fs_try_exists", issue = "83186")] +#[stable(feature = "fs_try_exists", since = "CURRENT_RUSTC_VERSION")] #[inline] -pub fn try_exists>(path: P) -> io::Result { - fs_imp::try_exists(path.as_ref()) +pub fn exists>(path: P) -> io::Result { + fs_imp::exists(path.as_ref()) } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 80f67838ac00..caa8c7375ec4 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -284,7 +284,6 @@ #![feature(cfi_encoding)] #![feature(concat_idents)] #![feature(const_mut_refs)] -#![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs index 2ba67a6dd1aa..919590947972 100644 --- a/library/std/src/os/linux/process.rs +++ b/library/std/src/os/linux/process.rs @@ -6,20 +6,20 @@ use crate::io::Result; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; -use crate::process; +use crate::process::{self, ExitStatus}; use crate::sealed::Sealed; #[cfg(not(doc))] -use crate::sys::fd::FileDesc; +use crate::sys::{fd::FileDesc, linux::pidfd::PidFd as InnerPidFd}; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[cfg(doc)] -struct FileDesc; +struct InnerPidFd; /// This type represents a file descriptor that refers to a process. /// /// A `PidFd` can be obtained by setting the corresponding option on [`Command`] /// with [`create_pidfd`]. Subsequently, the created pidfd can be retrieved -/// from the [`Child`] by calling [`pidfd`] or [`take_pidfd`]. +/// from the [`Child`] by calling [`pidfd`] or [`into_pidfd`]. /// /// Example: /// ```no_run @@ -33,7 +33,7 @@ struct FileDesc; /// .expect("Failed to spawn child"); /// /// let pidfd = child -/// .take_pidfd() +/// .into_pidfd() /// .expect("Failed to retrieve pidfd"); /// /// // The file descriptor will be closed when `pidfd` is dropped. @@ -44,28 +44,63 @@ struct FileDesc; /// [`create_pidfd`]: CommandExt::create_pidfd /// [`Child`]: process::Child /// [`pidfd`]: fn@ChildExt::pidfd -/// [`take_pidfd`]: ChildExt::take_pidfd +/// [`into_pidfd`]: ChildExt::into_pidfd /// [`pidfd_open(2)`]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html #[derive(Debug)] +#[repr(transparent)] pub struct PidFd { - inner: FileDesc, + inner: InnerPidFd, } -impl AsInner for PidFd { +impl PidFd { + /// Forces the child process to exit. + /// + /// Unlike [`Child::kill`] it is possible to attempt to kill + /// reaped children since PidFd does not suffer from pid recycling + /// races. But doing so will return an Error. + /// + /// [`Child::kill`]: process::Child::kill + pub fn kill(&self) -> Result<()> { + self.inner.kill() + } + + /// Waits for the child to exit completely, returning the status that it exited with. + /// + /// Unlike [`Child::wait`] it does not ensure that the stdin handle is closed. + /// Additionally it will not return an `ExitStatus` if the child + /// has already been reaped. Instead an error will be returned. + /// + /// [`Child::wait`]: process::Child::wait + pub fn wait(&self) -> Result { + self.inner.wait().map(FromInner::from_inner) + } + + /// Attempts to collect the exit status of the child if it has already exited. + /// + /// Unlike [`Child::try_wait`] this method will return an Error + /// if the child has already been reaped. + /// + /// [`Child::try_wait`]: process::Child::try_wait + pub fn try_wait(&self) -> Result> { + Ok(self.inner.try_wait()?.map(FromInner::from_inner)) + } +} + +impl AsInner for PidFd { #[inline] - fn as_inner(&self) -> &FileDesc { + fn as_inner(&self) -> &InnerPidFd { &self.inner } } -impl FromInner for PidFd { - fn from_inner(inner: FileDesc) -> PidFd { +impl FromInner for PidFd { + fn from_inner(inner: InnerPidFd) -> PidFd { PidFd { inner } } } -impl IntoInner for PidFd { - fn into_inner(self) -> FileDesc { +impl IntoInner for PidFd { + fn into_inner(self) -> InnerPidFd { self.inner } } @@ -73,37 +108,37 @@ impl IntoInner for PidFd { impl AsRawFd for PidFd { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().as_raw_fd() + self.as_inner().as_inner().as_raw_fd() } } impl FromRawFd for PidFd { unsafe fn from_raw_fd(fd: RawFd) -> Self { - Self::from_inner(FileDesc::from_raw_fd(fd)) + Self::from_inner(InnerPidFd::from_raw_fd(fd)) } } impl IntoRawFd for PidFd { fn into_raw_fd(self) -> RawFd { - self.into_inner().into_raw_fd() + self.into_inner().into_inner().into_raw_fd() } } impl AsFd for PidFd { fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().as_fd() + self.as_inner().as_inner().as_fd() } } impl From for PidFd { fn from(fd: OwnedFd) -> Self { - Self::from_inner(FileDesc::from_inner(fd)) + Self::from_inner(InnerPidFd::from_inner(FileDesc::from_inner(fd))) } } impl From for OwnedFd { fn from(pid_fd: PidFd) -> Self { - pid_fd.into_inner().into_inner() + pid_fd.into_inner().into_inner().into_inner() } } @@ -124,18 +159,26 @@ pub trait ChildExt: Sealed { /// [`Child`]: process::Child fn pidfd(&self) -> Result<&PidFd>; - /// Takes ownership of the [`PidFd`] created for this [`Child`], if available. + /// Returns the [`PidFd`] created for this [`Child`], if available. + /// Otherwise self is returned. /// /// A pidfd will only be available if its creation was requested with /// [`create_pidfd`] when the corresponding [`Command`] was created. /// + /// Taking ownership of the PidFd consumes the Child to avoid pid reuse + /// races. Use [`pidfd`] and [`BorrowedFd::try_clone_to_owned`] if + /// you don't want to disassemble the Child yet. + /// /// Even if requested, a pidfd may not be available due to an older /// version of Linux being in use, or if some other error occurred. /// /// [`Command`]: process::Command /// [`create_pidfd`]: CommandExt::create_pidfd + /// [`pidfd`]: ChildExt::pidfd /// [`Child`]: process::Child - fn take_pidfd(&mut self) -> Result; + fn into_pidfd(self) -> crate::result::Result + where + Self: Sized; } /// Os-specific extensions for [`Command`] @@ -146,7 +189,7 @@ pub trait CommandExt: Sealed { /// spawned by this [`Command`]. /// By default, no pidfd will be created. /// - /// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`]. + /// The pidfd can be retrieved from the child with [`pidfd`] or [`into_pidfd`]. /// /// A pidfd will only be created if it is possible to do so /// in a guaranteed race-free manner. Otherwise, [`pidfd`] will return an error. @@ -160,7 +203,7 @@ pub trait CommandExt: Sealed { /// [`Command`]: process::Command /// [`Child`]: process::Child /// [`pidfd`]: fn@ChildExt::pidfd - /// [`take_pidfd`]: ChildExt::take_pidfd + /// [`into_pidfd`]: ChildExt::into_pidfd fn create_pidfd(&mut self, val: bool) -> &mut process::Command; } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 7b8caaa26847..72073d132802 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2907,6 +2907,8 @@ impl Path { /// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios /// where those bugs are not an issue. /// + /// This is an alias for [`std::fs::exists`](crate::fs::exists). + /// /// # Examples /// /// ```no_run @@ -2919,7 +2921,7 @@ impl Path { #[stable(feature = "path_try_exists", since = "1.63.0")] #[inline] pub fn try_exists(&self) -> io::Result { - fs::try_exists(self) + fs::exists(self) } /// Returns `true` if the path exists on disk and is pointing at a regular file. diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs index a98a1006ef47..e4e9eee044ef 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/pal/hermit/fs.rs @@ -18,7 +18,7 @@ use crate::sys::time::SystemTime; use crate::sys::unsupported; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; -pub use crate::sys_common::fs::{copy, try_exists}; +pub use crate::sys_common::fs::{copy, exists}; #[derive(Debug)] pub struct File(FileDesc); diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs index a6c1336109ad..dc83e4f4b499 100644 --- a/library/std/src/sys/pal/solid/fs.rs +++ b/library/std/src/sys/pal/solid/fs.rs @@ -12,7 +12,7 @@ use crate::{ sys::unsupported, }; -pub use crate::sys_common::fs::try_exists; +pub use crate::sys_common::fs::exists; /// A file descriptor. #[derive(Clone, Copy)] diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 035c92bc84bf..5c4ccd32850e 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -97,7 +97,7 @@ use libc::{ ))] use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64}; -pub use crate::sys_common::fs::try_exists; +pub use crate::sys_common::fs::exists; pub struct File(FileDesc); diff --git a/library/std/src/sys/pal/unix/linux/mod.rs b/library/std/src/sys/pal/unix/linux/mod.rs new file mode 100644 index 000000000000..88aa1e3deccf --- /dev/null +++ b/library/std/src/sys/pal/unix/linux/mod.rs @@ -0,0 +1 @@ +pub mod pidfd; diff --git a/library/std/src/sys/pal/unix/linux/pidfd.rs b/library/std/src/sys/pal/unix/linux/pidfd.rs new file mode 100644 index 000000000000..7474f80e94f9 --- /dev/null +++ b/library/std/src/sys/pal/unix/linux/pidfd.rs @@ -0,0 +1,76 @@ +use crate::io; +use crate::os::fd::{AsRawFd, FromRawFd, RawFd}; +use crate::sys::cvt; +use crate::sys::pal::unix::fd::FileDesc; +use crate::sys::process::ExitStatus; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +#[cfg(test)] +mod tests; + +#[derive(Debug)] +pub(crate) struct PidFd(FileDesc); + +impl PidFd { + pub fn kill(&self) -> io::Result<()> { + return cvt(unsafe { + libc::syscall( + libc::SYS_pidfd_send_signal, + self.0.as_raw_fd(), + libc::SIGKILL, + crate::ptr::null::<()>(), + 0, + ) + }) + .map(drop); + } + + pub fn wait(&self) -> io::Result { + let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; + cvt(unsafe { + libc::waitid(libc::P_PIDFD, self.0.as_raw_fd() as u32, &mut siginfo, libc::WEXITED) + })?; + return Ok(ExitStatus::from_waitid_siginfo(siginfo)); + } + + pub fn try_wait(&self) -> io::Result> { + let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; + + cvt(unsafe { + libc::waitid( + libc::P_PIDFD, + self.0.as_raw_fd() as u32, + &mut siginfo, + libc::WEXITED | libc::WNOHANG, + ) + })?; + if unsafe { siginfo.si_pid() } == 0 { + return Ok(None); + } + return Ok(Some(ExitStatus::from_waitid_siginfo(siginfo))); + } +} + +impl AsInner for PidFd { + fn as_inner(&self) -> &FileDesc { + &self.0 + } +} + +impl IntoInner for PidFd { + fn into_inner(self) -> FileDesc { + self.0 + } +} + +impl FromInner for PidFd { + fn from_inner(inner: FileDesc) -> Self { + Self(inner) + } +} + +impl FromRawFd for PidFd { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Self(FileDesc::from_raw_fd(fd)) + } +} diff --git a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs new file mode 100644 index 000000000000..6d9532f2ef1f --- /dev/null +++ b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs @@ -0,0 +1,87 @@ +use crate::assert_matches::assert_matches; +use crate::os::fd::{AsRawFd, RawFd}; +use crate::os::linux::process::{ChildExt, CommandExt}; +use crate::os::unix::process::ExitStatusExt; +use crate::process::Command; + +#[test] +fn test_command_pidfd() { + let pidfd_open_available = probe_pidfd_support(); + + // always exercise creation attempts + let mut child = Command::new("false").create_pidfd(true).spawn().unwrap(); + + // but only check if we know that the kernel supports pidfds. + // We don't assert the precise value, since the standard library + // might have opened other file descriptors before our code runs. + if pidfd_open_available { + assert!(child.pidfd().is_ok()); + } + if let Ok(pidfd) = child.pidfd() { + let flags = super::cvt(unsafe { libc::fcntl(pidfd.as_raw_fd(), libc::F_GETFD) }).unwrap(); + assert!(flags & libc::FD_CLOEXEC != 0); + } + let status = child.wait().expect("error waiting on pidfd"); + assert_eq!(status.code(), Some(1)); + + let mut child = Command::new("sleep").arg("1000").create_pidfd(true).spawn().unwrap(); + assert_matches!(child.try_wait(), Ok(None)); + child.kill().expect("failed to kill child"); + let status = child.wait().expect("error waiting on pidfd"); + assert_eq!(status.signal(), Some(libc::SIGKILL)); + + let _ = Command::new("echo") + .create_pidfd(false) + .spawn() + .unwrap() + .pidfd() + .expect_err("pidfd should not have been created when create_pid(false) is set"); + + let _ = Command::new("echo") + .spawn() + .unwrap() + .pidfd() + .expect_err("pidfd should not have been created"); +} + +#[test] +fn test_pidfd() { + if !probe_pidfd_support() { + return; + } + + let child = Command::new("sleep") + .arg("1000") + .create_pidfd(true) + .spawn() + .expect("executing 'sleep' failed"); + + let fd = child.into_pidfd().unwrap(); + + assert_matches!(fd.try_wait(), Ok(None)); + fd.kill().expect("kill failed"); + fd.kill().expect("sending kill twice failed"); + let status = fd.wait().expect("1st wait failed"); + assert_eq!(status.signal(), Some(libc::SIGKILL)); + + // Trying to wait again for a reaped child is safe since there's no pid-recycling race. + // But doing so will return an error. + let res = fd.wait(); + assert_matches!(res, Err(e) if e.raw_os_error() == Some(libc::ECHILD)); + + // Ditto for additional attempts to kill an already-dead child. + let res = fd.kill(); + assert_matches!(res, Err(e) if e.raw_os_error() == Some(libc::ESRCH)); +} + +fn probe_pidfd_support() -> bool { + // pidfds require the pidfd_open syscall + let our_pid = crate::process::id(); + let pidfd = unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) }; + if pidfd >= 0 { + unsafe { libc::close(pidfd as RawFd) }; + true + } else { + false + } +} diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 735ed96bc7b1..b370f06e92ba 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -20,6 +20,8 @@ pub mod io; pub mod kernel_copy; #[cfg(target_os = "l4re")] mod l4re; +#[cfg(target_os = "linux")] +pub mod linux; #[cfg(not(target_os = "l4re"))] pub mod net; #[cfg(target_os = "l4re")] diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 72bda90a9ba7..32382d9a50cf 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -7,9 +7,7 @@ use crate::sys::cvt; use crate::sys::process::process_common::*; #[cfg(target_os = "linux")] -use crate::os::linux::process::PidFd; -#[cfg(target_os = "linux")] -use crate::os::unix::io::AsRawFd; +use crate::sys::pal::unix::linux::pidfd::PidFd; #[cfg(target_os = "vxworks")] use libc::RTP_ID as pid_t; @@ -815,16 +813,7 @@ impl Process { #[cfg(target_os = "linux")] if let Some(pid_fd) = self.pidfd.as_ref() { // pidfd_send_signal predates pidfd_open. so if we were able to get an fd then sending signals will work too - return cvt(unsafe { - libc::syscall( - libc::SYS_pidfd_send_signal, - pid_fd.as_raw_fd(), - libc::SIGKILL, - crate::ptr::null::<()>(), - 0, - ) - }) - .map(drop); + return pid_fd.kill(); } cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop) } @@ -836,12 +825,7 @@ impl Process { } #[cfg(target_os = "linux")] if let Some(pid_fd) = self.pidfd.as_ref() { - let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; - - cvt_r(|| unsafe { - libc::waitid(libc::P_PIDFD, pid_fd.as_raw_fd() as u32, &mut siginfo, libc::WEXITED) - })?; - let status = ExitStatus::from_waitid_siginfo(siginfo); + let status = pid_fd.wait()?; self.status = Some(status); return Ok(status); } @@ -857,22 +841,11 @@ impl Process { } #[cfg(target_os = "linux")] if let Some(pid_fd) = self.pidfd.as_ref() { - let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; - - cvt(unsafe { - libc::waitid( - libc::P_PIDFD, - pid_fd.as_raw_fd() as u32, - &mut siginfo, - libc::WEXITED | libc::WNOHANG, - ) - })?; - if unsafe { siginfo.si_pid() } == 0 { - return Ok(None); + let status = pid_fd.try_wait()?; + if let Some(status) = status { + self.status = Some(status) } - let status = ExitStatus::from_waitid_siginfo(siginfo); - self.status = Some(status); - return Ok(Some(status)); + return Ok(status); } let mut status = 0 as c_int; let pid = cvt(unsafe { libc::waitpid(self.pid, &mut status, libc::WNOHANG) })?; @@ -1105,20 +1078,33 @@ impl ExitStatusError { } #[cfg(target_os = "linux")] -#[unstable(feature = "linux_pidfd", issue = "82971")] -impl crate::os::linux::process::ChildExt for crate::process::Child { - fn pidfd(&self) -> io::Result<&PidFd> { - self.handle - .pidfd - .as_ref() - .ok_or_else(|| Error::new(ErrorKind::Uncategorized, "No pidfd was created.")) - } +mod linux_child_ext { - fn take_pidfd(&mut self) -> io::Result { - self.handle - .pidfd - .take() - .ok_or_else(|| Error::new(ErrorKind::Uncategorized, "No pidfd was created.")) + use crate::io; + use crate::mem; + use crate::os::linux::process as os; + use crate::sys::pal::unix::linux::pidfd as imp; + use crate::sys::pal::unix::ErrorKind; + use crate::sys_common::FromInner; + + #[unstable(feature = "linux_pidfd", issue = "82971")] + impl crate::os::linux::process::ChildExt for crate::process::Child { + fn pidfd(&self) -> io::Result<&os::PidFd> { + self.handle + .pidfd + .as_ref() + // SAFETY: The os type is a transparent wrapper, therefore we can transmute references + .map(|fd| unsafe { mem::transmute::<&imp::PidFd, &os::PidFd>(fd) }) + .ok_or_else(|| io::Error::new(ErrorKind::Uncategorized, "No pidfd was created.")) + } + + fn into_pidfd(mut self) -> Result { + self.handle + .pidfd + .take() + .map(|fd| >::from_inner(fd)) + .ok_or_else(|| self) + } } } diff --git a/library/std/src/sys/pal/unix/process/process_unix/tests.rs b/library/std/src/sys/pal/unix/process/process_unix/tests.rs index 0a6c6ec19fc7..e5e1f956bc35 100644 --- a/library/std/src/sys/pal/unix/process/process_unix/tests.rs +++ b/library/std/src/sys/pal/unix/process/process_unix/tests.rs @@ -60,57 +60,3 @@ fn test_command_fork_no_unwind() { || signal == libc::SIGSEGV ); } - -#[test] -#[cfg(target_os = "linux")] // pidfds are a linux-specific concept -fn test_command_pidfd() { - use crate::assert_matches::assert_matches; - use crate::os::fd::{AsRawFd, RawFd}; - use crate::os::linux::process::{ChildExt, CommandExt}; - use crate::process::Command; - - // pidfds require the pidfd_open syscall - let our_pid = crate::process::id(); - let pidfd = unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) }; - let pidfd_open_available = if pidfd >= 0 { - unsafe { libc::close(pidfd as RawFd) }; - true - } else { - false - }; - - // always exercise creation attempts - let mut child = Command::new("false").create_pidfd(true).spawn().unwrap(); - - // but only check if we know that the kernel supports pidfds. - // We don't assert the precise value, since the standard library - // might have opened other file descriptors before our code runs. - if pidfd_open_available { - assert!(child.pidfd().is_ok()); - } - if let Ok(pidfd) = child.pidfd() { - let flags = super::cvt(unsafe { libc::fcntl(pidfd.as_raw_fd(), libc::F_GETFD) }).unwrap(); - assert!(flags & libc::FD_CLOEXEC != 0); - } - let status = child.wait().expect("error waiting on pidfd"); - assert_eq!(status.code(), Some(1)); - - let mut child = Command::new("sleep").arg("1000").create_pidfd(true).spawn().unwrap(); - assert_matches!(child.try_wait(), Ok(None)); - child.kill().expect("failed to kill child"); - let status = child.wait().expect("error waiting on pidfd"); - assert_eq!(status.signal(), Some(libc::SIGKILL)); - - let _ = Command::new("echo") - .create_pidfd(false) - .spawn() - .unwrap() - .pidfd() - .expect_err("pidfd should not have been created when create_pid(false) is set"); - - let _ = Command::new("echo") - .spawn() - .unwrap() - .pidfd() - .expect_err("pidfd should not have been created"); -} diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 3ebf1cfd33f8..619f4e4121e7 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -478,7 +478,7 @@ mod cgroups { use crate::borrow::Cow; use crate::ffi::OsString; - use crate::fs::{try_exists, File}; + use crate::fs::{exists, File}; use crate::io::Read; use crate::io::{BufRead, BufReader}; use crate::os::unix::ffi::OsStringExt; @@ -556,7 +556,7 @@ mod cgroups { path.push("cgroup.controllers"); // skip if we're not looking at cgroup2 - if matches!(try_exists(&path), Err(_) | Ok(false)) { + if matches!(exists(&path), Err(_) | Ok(false)) { return usize::MAX; }; @@ -613,7 +613,7 @@ mod cgroups { path.push(&group_path); // skip if we guessed the mount incorrectly - if matches!(try_exists(&path), Err(_) | Ok(false)) { + if matches!(exists(&path), Err(_) | Ok(false)) { continue; } diff --git a/library/std/src/sys/pal/unsupported/fs.rs b/library/std/src/sys/pal/unsupported/fs.rs index 6ac1b5d2bcfc..474c9fe97d18 100644 --- a/library/std/src/sys/pal/unsupported/fs.rs +++ b/library/std/src/sys/pal/unsupported/fs.rs @@ -291,7 +291,7 @@ pub fn remove_dir_all(_path: &Path) -> io::Result<()> { unsupported() } -pub fn try_exists(_path: &Path) -> io::Result { +pub fn exists(_path: &Path) -> io::Result { unsupported() } diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 529b82e01989..c58e6a08b374 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -17,7 +17,7 @@ use crate::sys::time::SystemTime; use crate::sys::unsupported; use crate::sys_common::{AsInner, FromInner, IntoInner}; -pub use crate::sys_common::fs::try_exists; +pub use crate::sys_common::fs::exists; pub struct File { fd: WasiFd, diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 629ff114b5a8..cc68f5ef5f08 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1531,7 +1531,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { } // Try to see if a file exists but, unlike `exists`, report I/O errors. -pub fn try_exists(path: &Path) -> io::Result { +pub fn exists(path: &Path) -> io::Result { // Open the file to ensure any symlinks are followed to their target. let mut opts = OpenOptions::new(); // No read, write, etc access rights are needed. diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs index 617ac52e51ca..acb6713cf1b1 100644 --- a/library/std/src/sys_common/fs.rs +++ b/library/std/src/sys_common/fs.rs @@ -42,7 +42,7 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { fs::remove_dir(path) } -pub fn try_exists(path: &Path) -> io::Result { +pub fn exists(path: &Path) -> io::Result { match fs::metadata(path) { Ok(_) => Ok(true), Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false), diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs index 381ee7ef53b4..004174e35e1d 100644 --- a/src/bootstrap/src/core/build_steps/mod.rs +++ b/src/bootstrap/src/core/build_steps/mod.rs @@ -7,6 +7,7 @@ pub(crate) mod doc; pub(crate) mod format; pub(crate) mod install; pub(crate) mod llvm; +pub(crate) mod perf; pub(crate) mod run; pub(crate) mod setup; pub(crate) mod suggest; diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs new file mode 100644 index 000000000000..9d70ca6bd71f --- /dev/null +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -0,0 +1,45 @@ +use std::process::Command; + +use crate::core::build_steps::compile::{Std, Sysroot}; +use crate::core::build_steps::tool::RustcPerf; +use crate::core::builder::Builder; +use crate::core::config::DebuginfoLevel; + +/// Performs profiling using `rustc-perf` on a built version of the compiler. +pub fn perf(builder: &Builder<'_>) { + let collector = builder.ensure(RustcPerf { + compiler: builder.compiler(0, builder.config.build), + target: builder.config.build, + }); + + if builder.build.config.rust_debuginfo_level_rustc == DebuginfoLevel::None { + builder.info(r#"WARNING: You are compiling rustc without debuginfo, this will make profiling less useful. +Consider setting `rust.debuginfo-level = 1` in `config.toml`."#); + } + + let compiler = builder.compiler(builder.top_stage, builder.config.build); + builder.ensure(Std::new(compiler, builder.config.build)); + let sysroot = builder.ensure(Sysroot::new(compiler)); + let rustc = sysroot.join("bin/rustc"); + + let results_dir = builder.build.tempdir().join("rustc-perf"); + + let mut cmd = Command::new(collector); + let cmd = cmd + .arg("profile_local") + .arg("eprintln") + .arg("--out-dir") + .arg(&results_dir) + .arg("--include") + .arg("helloworld") + .arg(&rustc); + + builder.info(&format!("Running `rustc-perf` using `{}`", rustc.display())); + + // We need to set the working directory to `src/tools/perf`, so that it can find the directory + // with compile-time benchmarks. + let cmd = cmd.current_dir(builder.src.join("src/tools/rustc-perf")); + builder.build.run(cmd); + + builder.info(&format!("You can find the results at `{}`", results_dir.display())); +} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 5459b4c7b295..8a2bc3b9d484 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -26,7 +26,7 @@ use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::flags::get_completion; use crate::core::config::flags::Subcommand; use crate::core::config::TargetSelection; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::{BootstrapCommand, OutputMode}; use crate::utils::helpers::{ self, add_link_lib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var, linker_args, linker_flags, output, t, target_supports_cranelift_backend, up_to_date, @@ -156,7 +156,10 @@ You can skip linkcheck with --skip src/tools/linkchecker" let _guard = builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host); let _time = helpers::timeit(builder); - builder.run_delaying_failure(linkchecker.arg(builder.out.join(host.triple).join("doc"))); + builder.run_tracked( + BootstrapCommand::from(linkchecker.arg(builder.out.join(host.triple).join("doc"))) + .delay_failure(), + ); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -213,8 +216,11 @@ impl Step for HtmlCheck { builder, )); - builder.run_delaying_failure( - builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)), + builder.run_tracked( + BootstrapCommand::from( + builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)), + ) + .delay_failure(), ); } } @@ -261,7 +267,7 @@ impl Step for Cargotest { .env("RUSTC", builder.rustc(compiler)) .env("RUSTDOC", builder.rustdoc(compiler)); add_rustdoc_cargo_linker_args(cmd, builder, compiler.host, LldThreads::No); - builder.run_delaying_failure(cmd); + builder.run_tracked(BootstrapCommand::from(cmd).delay_failure()); } } @@ -813,7 +819,7 @@ impl Step for RustdocTheme { .env("RUSTC_BOOTSTRAP", "1"); cmd.args(linker_args(builder, self.compiler.host, LldThreads::No)); - builder.run_delaying_failure(&mut cmd); + builder.run_tracked(BootstrapCommand::from(&mut cmd).delay_failure()); } } @@ -1093,7 +1099,7 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to } builder.info("tidy check"); - builder.run_delaying_failure(&mut cmd); + builder.run_tracked(BootstrapCommand::from(&mut cmd).delay_failure()); builder.info("x.py completions check"); let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"] @@ -2179,7 +2185,8 @@ impl BookTest { compiler.host, ); let _time = helpers::timeit(builder); - let toolstate = if builder.run_delaying_failure(&mut rustbook_cmd) { + let cmd = BootstrapCommand::from(&mut rustbook_cmd).delay_failure(); + let toolstate = if builder.run_tracked(cmd).is_success() { ToolState::TestPass } else { ToolState::TestFail @@ -2312,7 +2319,8 @@ impl Step for ErrorIndex { let guard = builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host); let _time = helpers::timeit(builder); - builder.run_quiet(&mut tool); + builder + .run_tracked(BootstrapCommand::from(&mut tool).output_mode(OutputMode::OnlyOnFailure)); drop(guard); // The tests themselves need to link to std, so make sure it is // available. @@ -2341,11 +2349,11 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> let test_args = builder.config.test_args().join(" "); cmd.arg("--test-args").arg(test_args); - if builder.config.verbose_tests { - builder.run_delaying_failure(&mut cmd) - } else { - builder.run_quiet_delaying_failure(&mut cmd) + let mut cmd = BootstrapCommand::from(&mut cmd).delay_failure(); + if !builder.config.verbose_tests { + cmd = cmd.quiet(); } + builder.run_tracked(cmd).is_success() } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -2370,7 +2378,8 @@ impl Step for RustcGuide { let src = builder.src.join(relative_path); let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); - let toolstate = if builder.run_delaying_failure(rustbook_cmd.arg("linkcheck").arg(&src)) { + let cmd = BootstrapCommand::from(rustbook_cmd.arg("linkcheck").arg(&src)).delay_failure(); + let toolstate = if builder.run_tracked(cmd).is_success() { ToolState::TestPass } else { ToolState::TestFail @@ -2984,7 +2993,7 @@ impl Step for Bootstrap { .current_dir(builder.src.join("src/bootstrap/")); // NOTE: we intentionally don't pass test_args here because the args for unittest and cargo test are mutually incompatible. // Use `python -m unittest` manually if you want to pass arguments. - builder.run_delaying_failure(&mut check_bootstrap); + builder.run_tracked(BootstrapCommand::from(&mut check_bootstrap).delay_failure()); let mut cmd = Command::new(&builder.initial_cargo); cmd.arg("test") @@ -3061,7 +3070,7 @@ impl Step for TierCheck { self.compiler.host, self.compiler.host, ); - builder.run_delaying_failure(&mut cargo.into()); + builder.run_tracked(BootstrapCommand::from(&mut cargo.into()).delay_failure()); } } @@ -3147,7 +3156,7 @@ impl Step for RustInstaller { cmd.env("CARGO", &builder.initial_cargo); cmd.env("RUSTC", &builder.initial_rustc); cmd.env("TMP_DIR", &tmpdir); - builder.run_delaying_failure(&mut cmd); + builder.run_tracked(BootstrapCommand::from(&mut cmd).delay_failure()); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 613484788b60..850c8bfe2f8b 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -32,6 +32,8 @@ struct ToolBuild { extra_features: Vec, /// Nightly-only features that are allowed (comma-separated list). allow_features: &'static str, + /// Additional arguments to pass to the `cargo` invocation. + cargo_args: Vec, } impl Builder<'_> { @@ -100,6 +102,7 @@ impl Step for ToolBuild { if !self.allow_features.is_empty() { cargo.allow_features(self.allow_features); } + cargo.args(self.cargo_args); let _guard = builder.msg_tool( Kind::Build, self.mode, @@ -126,10 +129,7 @@ impl Step for ToolBuild { if tool == "tidy" { tool = "rust-tidy"; } - let cargo_out = builder.cargo_out(compiler, self.mode, target).join(exe(tool, target)); - let bin = builder.tools_dir(compiler).join(exe(tool, target)); - builder.copy_link(&cargo_out, &bin); - bin + copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool) } } } @@ -214,6 +214,21 @@ pub fn prepare_tool_cargo( cargo } +/// Links a built tool binary with the given `name` from the build directory to the +/// tools directory. +fn copy_link_tool_bin( + builder: &Builder<'_>, + compiler: Compiler, + target: TargetSelection, + mode: Mode, + name: &str, +) -> PathBuf { + let cargo_out = builder.cargo_out(compiler, mode, target).join(exe(name, target)); + let bin = builder.tools_dir(compiler).join(exe(name, target)); + builder.copy_link(&cargo_out, &bin); + bin +} + macro_rules! bootstrap_tool { ($( $name:ident, $path:expr, $tool_name:expr @@ -283,6 +298,7 @@ macro_rules! bootstrap_tool { }, extra_features: vec![], allow_features: concat!($($allow_features)*), + cargo_args: vec![] }) } } @@ -349,10 +365,60 @@ impl Step for OptimizedDist { source_type: SourceType::InTree, extra_features: Vec::new(), allow_features: "", + cargo_args: Vec::new(), }) } } +/// The [rustc-perf](https://github.com/rust-lang/rustc-perf) benchmark suite, which is added +/// as a submodule at `src/tools/rustc-perf`. +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct RustcPerf { + pub compiler: Compiler, + pub target: TargetSelection, +} + +impl Step for RustcPerf { + /// Path to the built `collector` binary. + type Output = PathBuf; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/rustc-perf") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(RustcPerf { + compiler: run.builder.compiler(0, run.builder.config.build), + target: run.target, + }); + } + + fn run(self, builder: &Builder<'_>) -> PathBuf { + // We need to ensure the rustc-perf submodule is initialized. + builder.update_submodule(Path::new("src/tools/rustc-perf")); + + let tool = ToolBuild { + compiler: self.compiler, + target: self.target, + tool: "collector", + mode: Mode::ToolBootstrap, + path: "src/tools/rustc-perf", + source_type: SourceType::Submodule, + extra_features: Vec::new(), + allow_features: "", + // Only build the collector package, which is used for benchmarking through + // a CLI. + cargo_args: vec!["-p".to_string(), "collector".to_string()], + }; + let collector_bin = builder.ensure(tool.clone()); + // We also need to symlink the `rustc-fake` binary to the corresponding directory, + // because `collector` expects it in the same directory. + copy_link_tool_bin(builder, tool.compiler, tool.target, tool.mode, "rustc-fake"); + + collector_bin + } +} + #[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct ErrorIndex { pub compiler: Compiler, @@ -403,6 +469,7 @@ impl Step for ErrorIndex { source_type: SourceType::InTree, extra_features: Vec::new(), allow_features: "", + cargo_args: Vec::new(), }) } } @@ -437,6 +504,7 @@ impl Step for RemoteTestServer { source_type: SourceType::InTree, extra_features: Vec::new(), allow_features: "", + cargo_args: Vec::new(), }) } } @@ -595,6 +663,7 @@ impl Step for Cargo { source_type: SourceType::Submodule, extra_features: Vec::new(), allow_features: "", + cargo_args: Vec::new(), }) } } @@ -622,6 +691,7 @@ impl Step for LldWrapper { source_type: SourceType::InTree, extra_features: Vec::new(), allow_features: "", + cargo_args: Vec::new(), }) } } @@ -670,6 +740,7 @@ impl Step for RustAnalyzer { extra_features: vec!["in-rust-tree".to_owned()], source_type: SourceType::InTree, allow_features: RustAnalyzer::ALLOW_FEATURES, + cargo_args: Vec::new(), }) } } @@ -717,6 +788,7 @@ impl Step for RustAnalyzerProcMacroSrv { extra_features: vec!["in-rust-tree".to_owned()], source_type: SourceType::InTree, allow_features: RustAnalyzer::ALLOW_FEATURES, + cargo_args: Vec::new(), }); // Copy `rust-analyzer-proc-macro-srv` to `/libexec/` @@ -923,6 +995,7 @@ macro_rules! tool_extended { extra_features: $sel.extra_features, source_type: SourceType::InTree, allow_features: concat!($($allow_features)*), + cargo_args: vec![] }); if (false $(|| !$add_bins_to_sysroot.is_empty())?) && $sel.compiler.stage > 0 { diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 3c4806a13117..a638d6f31db0 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -666,6 +666,7 @@ pub enum Kind { Setup, Suggest, Vendor, + Perf, } impl Kind { @@ -687,6 +688,7 @@ impl Kind { Kind::Setup => "setup", Kind::Suggest => "suggest", Kind::Vendor => "vendor", + Kind::Perf => "perf", } } @@ -698,6 +700,7 @@ impl Kind { Kind::Run => "Running", Kind::Suggest => "Suggesting", Kind::Clippy => "Linting", + Kind::Perf => "Profiling & benchmarking", _ => { let title_letter = self.as_str()[0..1].to_ascii_uppercase(); return format!("{title_letter}{}ing", &self.as_str()[1..]); @@ -749,7 +752,8 @@ impl<'a> Builder<'a> { tool::RustdocGUITest, tool::OptimizedDist, tool::CoverageDump, - tool::LlvmBitcodeLinker + tool::LlvmBitcodeLinker, + tool::RustcPerf, ), Kind::Clippy => describe!( clippy::Std, @@ -945,7 +949,7 @@ impl<'a> Builder<'a> { Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), // special-cased in Build::build() - Kind::Format | Kind::Suggest => vec![], + Kind::Format | Kind::Suggest | Kind::Perf => vec![], } } @@ -1017,6 +1021,7 @@ impl<'a> Builder<'a> { path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)), ), Subcommand::Vendor { .. } => (Kind::Vendor, &paths[..]), + Subcommand::Perf { .. } => (Kind::Perf, &paths[..]), }; Self::new_internal(build, kind, paths.to_owned()) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 0438dee7241f..948f97e746f4 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2043,6 +2043,7 @@ impl Config { Subcommand::Bench { .. } => flags.stage.or(bench_stage).unwrap_or(2), Subcommand::Dist { .. } => flags.stage.or(dist_stage).unwrap_or(2), Subcommand::Install { .. } => flags.stage.or(install_stage).unwrap_or(2), + Subcommand::Perf { .. } => flags.stage.unwrap_or(1), // These are all bootstrap tools, which don't depend on the compiler. // The stage we pass shouldn't matter, but use 0 just in case. Subcommand::Clean { .. } @@ -2080,7 +2081,8 @@ impl Config { | Subcommand::Setup { .. } | Subcommand::Format { .. } | Subcommand::Suggest { .. } - | Subcommand::Vendor { .. } => {} + | Subcommand::Vendor { .. } + | Subcommand::Perf { .. } => {} } } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 83def0c6df0c..eb5152a38312 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -469,6 +469,9 @@ Arguments: #[arg(long)] versioned_dirs: bool, }, + /// Perform profiling and benchmarking of the compiler using the + /// `rustc-perf` benchmark suite. + Perf {}, } impl Subcommand { @@ -490,6 +493,7 @@ impl Subcommand { Subcommand::Setup { .. } => Kind::Setup, Subcommand::Suggest { .. } => Kind::Suggest, Subcommand::Vendor { .. } => Kind::Vendor, + Subcommand::Perf { .. } => Kind::Perf, } } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 449d8c128ec6..dfc30298c28d 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -23,7 +23,7 @@ use std::fmt::Display; use std::fs::{self, File}; use std::io; use std::path::{Path, PathBuf}; -use std::process::{Command, Output, Stdio}; +use std::process::{Command, Stdio}; use std::str; use std::sync::OnceLock; @@ -41,7 +41,7 @@ use crate::core::builder::Kind; use crate::core::config::{flags, LldMode}; use crate::core::config::{DryRun, Target}; use crate::core::config::{LlvmLibunwind, TargetSelection}; -use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, OutputMode}; +use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode}; use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir}; mod core; @@ -585,8 +585,8 @@ impl Build { BootstrapCommand::from(submodule_git().args(["diff-index", "--quiet", "HEAD"])) .allow_failure() .output_mode(match self.is_verbose() { - true => OutputMode::PrintAll, - false => OutputMode::PrintOutput, + true => OutputMode::All, + false => OutputMode::OnlyOutput, }), ); if has_local_modifications { @@ -659,6 +659,9 @@ impl Build { Subcommand::Suggest { run } => { return core::build_steps::suggest::suggest(&builder::Builder::new(self), *run); } + Subcommand::Perf { .. } => { + return core::build_steps::perf::perf(&builder::Builder::new(self)); + } _ => (), } @@ -958,73 +961,36 @@ impl Build { }) } - /// Runs a command, printing out nice contextual information if it fails. - fn run(&self, cmd: &mut Command) { - self.run_cmd(BootstrapCommand::from(cmd).fail_fast().output_mode( - match self.is_verbose() { - true => OutputMode::PrintAll, - false => OutputMode::PrintOutput, - }, - )); - } - - /// Runs a command, printing out contextual info if it fails, and delaying errors until the build finishes. - pub(crate) fn run_delaying_failure(&self, cmd: &mut Command) -> bool { - self.run_cmd(BootstrapCommand::from(cmd).delay_failure().output_mode( - match self.is_verbose() { - true => OutputMode::PrintAll, - false => OutputMode::PrintOutput, - }, - )) - } - - /// Runs a command, printing out nice contextual information if it fails. - fn run_quiet(&self, cmd: &mut Command) { - self.run_cmd( - BootstrapCommand::from(cmd).fail_fast().output_mode(OutputMode::SuppressOnSuccess), - ); - } - - /// Runs a command, printing out nice contextual information if it fails. - /// Exits if the command failed to execute at all, otherwise returns its - /// `status.success()`. - fn run_quiet_delaying_failure(&self, cmd: &mut Command) -> bool { - self.run_cmd( - BootstrapCommand::from(cmd).delay_failure().output_mode(OutputMode::SuppressOnSuccess), - ) - } - - /// A centralized function for running commands that do not return output. - pub(crate) fn run_cmd<'a, C: Into>>(&self, cmd: C) -> bool { + /// Execute a command and return its output. + fn run_tracked(&self, command: BootstrapCommand<'_>) -> CommandOutput { if self.config.dry_run() { - return true; + return CommandOutput::default(); } - let command = cmd.into(); self.verbose(|| println!("running: {command:?}")); - let (output, print_error) = match command.output_mode { - mode @ (OutputMode::PrintAll | OutputMode::PrintOutput) => ( - command.command.status().map(|status| Output { - status, - stdout: Vec::new(), - stderr: Vec::new(), - }), - matches!(mode, OutputMode::PrintAll), + let output_mode = command.output_mode.unwrap_or_else(|| match self.is_verbose() { + true => OutputMode::All, + false => OutputMode::OnlyOutput, + }); + let (output, print_error): (io::Result, bool) = match output_mode { + mode @ (OutputMode::All | OutputMode::OnlyOutput) => ( + command.command.status().map(|status| status.into()), + matches!(mode, OutputMode::All), ), - OutputMode::SuppressOnSuccess => (command.command.output(), true), + OutputMode::OnlyOnFailure => (command.command.output().map(|o| o.into()), true), }; let output = match output { Ok(output) => output, Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", command, e)), }; - let result = if !output.status.success() { + if !output.is_success() { if print_error { println!( "\n\nCommand did not execute successfully.\ - \nExpected success, got: {}", - output.status, + \nExpected success, got: {}", + output.status(), ); if !self.is_verbose() { @@ -1034,37 +1000,45 @@ impl Build { self.verbose(|| { println!( "\nSTDOUT ----\n{}\n\ - STDERR ----\n{}\n", - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) + STDERR ----\n{}\n", + output.stdout(), + output.stderr(), ) }); } - Err(()) - } else { - Ok(()) - }; - match result { - Ok(_) => true, - Err(_) => { - match command.failure_behavior { - BehaviorOnFailure::DelayFail => { - if self.fail_fast { - exit!(1); - } - - let mut failures = self.delayed_failures.borrow_mut(); - failures.push(format!("{command:?}")); - } - BehaviorOnFailure::Exit => { + match command.failure_behavior { + BehaviorOnFailure::DelayFail => { + if self.fail_fast { exit!(1); } - BehaviorOnFailure::Ignore => {} + + let mut failures = self.delayed_failures.borrow_mut(); + failures.push(format!("{command:?}")); } - false + BehaviorOnFailure::Exit => { + exit!(1); + } + BehaviorOnFailure::Ignore => {} } } + output + } + + /// Runs a command, printing out nice contextual information if it fails. + fn run(&self, cmd: &mut Command) { + self.run_cmd(BootstrapCommand::from(cmd).fail_fast().output_mode( + match self.is_verbose() { + true => OutputMode::All, + false => OutputMode::OnlyOutput, + }, + )); + } + + /// A centralized function for running commands that do not return output. + pub(crate) fn run_cmd<'a, C: Into>>(&self, cmd: C) -> bool { + let command = cmd.into(); + self.run_tracked(command).is_success() } /// Check if verbosity is greater than the `level` diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 0aede2022bad..e8c588b75b38 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -1,4 +1,4 @@ -use std::process::Command; +use std::process::{Command, ExitStatus, Output}; /// What should be done when the command fails. #[derive(Debug, Copy, Clone)] @@ -16,11 +16,11 @@ pub enum BehaviorOnFailure { pub enum OutputMode { /// Print both the output (by inheriting stdout/stderr) and also the command itself, if it /// fails. - PrintAll, + All, /// Print the output (by inheriting stdout/stderr). - PrintOutput, + OnlyOutput, /// Suppress the output if the command succeeds, otherwise print the output. - SuppressOnSuccess, + OnlyOnFailure, } /// Wrapper around `std::process::Command`. @@ -28,7 +28,7 @@ pub enum OutputMode { pub struct BootstrapCommand<'a> { pub command: &'a mut Command, pub failure_behavior: BehaviorOnFailure, - pub output_mode: OutputMode, + pub output_mode: Option, } impl<'a> BootstrapCommand<'a> { @@ -44,17 +44,62 @@ impl<'a> BootstrapCommand<'a> { Self { failure_behavior: BehaviorOnFailure::Ignore, ..self } } + /// Do not print the output of the command, unless it fails. + pub fn quiet(self) -> Self { + self.output_mode(OutputMode::OnlyOnFailure) + } + pub fn output_mode(self, output_mode: OutputMode) -> Self { - Self { output_mode, ..self } + Self { output_mode: Some(output_mode), ..self } } } impl<'a> From<&'a mut Command> for BootstrapCommand<'a> { fn from(command: &'a mut Command) -> Self { - Self { - command, - failure_behavior: BehaviorOnFailure::Exit, - output_mode: OutputMode::PrintAll, - } + Self { command, failure_behavior: BehaviorOnFailure::Exit, output_mode: None } + } +} + +/// Represents the output of an executed process. +#[allow(unused)] +pub struct CommandOutput(Output); + +impl CommandOutput { + pub fn is_success(&self) -> bool { + self.0.status.success() + } + + pub fn is_failure(&self) -> bool { + !self.is_success() + } + + pub fn status(&self) -> ExitStatus { + self.0.status + } + + pub fn stdout(&self) -> String { + String::from_utf8(self.0.stdout.clone()).expect("Cannot parse process stdout as UTF-8") + } + + pub fn stderr(&self) -> String { + String::from_utf8(self.0.stderr.clone()).expect("Cannot parse process stderr as UTF-8") + } +} + +impl Default for CommandOutput { + fn default() -> Self { + Self(Output { status: Default::default(), stdout: vec![], stderr: vec![] }) + } +} + +impl From for CommandOutput { + fn from(output: Output) -> Self { + Self(output) + } +} + +impl From for CommandOutput { + fn from(status: ExitStatus) -> Self { + Self(Output { status, stdout: vec![], stderr: vec![] }) } } diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 115ee69a5891..6db25ff1a809 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -112,7 +112,7 @@ def atomic_link(link: Path, target: Path): os.remove(tmp_file) -@dataclass(kw_only=True) +@dataclass class TestEnvironment: rust_build_dir: Path sdk_dir: Path diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md index 02a009d56d38..c262d3f6da1f 100644 --- a/src/doc/unstable-book/src/language-features/intrinsics.md +++ b/src/doc/unstable-book/src/language-features/intrinsics.md @@ -18,7 +18,7 @@ All intrinsic fallback bodies are automatically made cross-crate inlineable (lik by the codegen backend, but not the MIR inliner. ```rust -#![feature(rustc_attrs, effects)] +#![feature(rustc_attrs)] #![allow(internal_features)] #[rustc_intrinsic] @@ -28,7 +28,7 @@ const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} Since these are just regular functions, it is perfectly ok to create the intrinsic twice: ```rust -#![feature(rustc_attrs, effects)] +#![feature(rustc_attrs)] #![allow(internal_features)] #[rustc_intrinsic] diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 7343f3147eed..2072f76a4818 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -48,6 +48,7 @@ complete -c x.py -n "__fish_use_subcommand" -f -a "run" -d 'Run tools contained complete -c x.py -n "__fish_use_subcommand" -f -a "setup" -d 'Set up the environment for development' complete -c x.py -n "__fish_use_subcommand" -f -a "suggest" -d 'Suggest a subset of tests to run, based on modified files' complete -c x.py -n "__fish_use_subcommand" -f -a "vendor" -d 'Vendor dependencies' +complete -c x.py -n "__fish_use_subcommand" -f -a "perf" -d 'Perform profiling and benchmarking of the compiler using the `rustc-perf` benchmark suite' complete -c x.py -n "__fish_seen_subcommand_from build" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from build" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from build" -l build -d 'build target of the stage0 compiler' -r -f @@ -628,3 +629,37 @@ complete -c x.py -n "__fish_seen_subcommand_from vendor" -l llvm-profile-generat complete -c x.py -n "__fish_seen_subcommand_from vendor" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from vendor" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x.py -n "__fish_seen_subcommand_from vendor" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from perf" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -l skip -d 'build paths to skip' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from perf" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from perf" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" +complete -c x.py -n "__fish_seen_subcommand_from perf" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" +complete -c x.py -n "__fish_seen_subcommand_from perf" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from perf" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r +complete -c x.py -n "__fish_seen_subcommand_from perf" -l set -d 'override options in config.toml' -r -f +complete -c x.py -n "__fish_seen_subcommand_from perf" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from perf" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l enable-bolt-settings -d 'Enable BOLT link flags' +complete -c x.py -n "__fish_seen_subcommand_from perf" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_seen_subcommand_from perf" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index d9adb1778f2f..919382d441ff 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -75,6 +75,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files') [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies') + [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using the `rustc-perf` benchmark suite') break } 'x.py;build' { @@ -769,6 +770,47 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break } + 'x.py;perf' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'build paths to skip') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--dump-bootstrap-shims', 'dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--bypass-bootstrap-lock', 'bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') + [CompletionResult]::new('--skip-stage0-validation', 'skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } }) $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 6cb9e95c8c10..a4234905476a 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -45,6 +45,9 @@ _x.py() { bootstrap,miri) cmd="bootstrap__miri" ;; + bootstrap,perf) + cmd="bootstrap__perf" + ;; bootstrap,run) cmd="bootstrap__run" ;; @@ -67,7 +70,7 @@ _x.py() { case "${cmd}" in x.py) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1414,6 +1417,116 @@ _x.py() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + x.py__perf) + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --skip) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --reproducible-artifact) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; x.py__run) opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 24ddd1c4b7cc..bbebf8b892d1 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -788,6 +788,49 @@ _arguments "${_arguments_options[@]}" \ '--help[Print help (see more with '\''--help'\'')]' \ '*::paths -- paths for the subcommand:_files' \ && ret=0 +;; +(perf) +_arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \ +'--json-output[use message-format=json]' \ +'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'--skip-stage0-validation[Skip stage0 compiler validation]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 ;; esac ;; @@ -813,6 +856,7 @@ _x.py_commands() { 'setup:Set up the environment for development' \ 'suggest:Suggest a subset of tests to run, based on modified files' \ 'vendor:Vendor dependencies' \ +'perf:Perform profiling and benchmarking of the compiler using the \`rustc-perf\` benchmark suite' \ ) _describe -t commands 'x.py commands' commands "$@" } @@ -871,6 +915,11 @@ _x.py__miri_commands() { local commands; commands=() _describe -t commands 'x.py miri commands' commands "$@" } +(( $+functions[_x.py__perf_commands] )) || +_x.py__perf_commands() { + local commands; commands=() + _describe -t commands 'x.py perf commands' commands "$@" +} (( $+functions[_x.py__run_commands] )) || _x.py__run_commands() { local commands; commands=() diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index da41f974068e..22565ea40280 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3077,9 +3077,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( let def_id = item.owner_id.to_def_id(); cx.with_param_env(def_id, |cx| { let kind = match item.kind { - // FIXME(missing_unsafe_on_extern) handle safety of foreign fns. - // Safety was added as part of the implementation of unsafe extern blocks PR #124482 - hir::ForeignItemKind::Fn(decl, names, generics, _) => { + hir::ForeignItemKind::Fn(decl, names, generics, safety) => { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args let generics = clean_generics(generics, cx); @@ -3087,13 +3085,12 @@ fn clean_maybe_renamed_foreign_item<'tcx>( let decl = clean_fn_decl_with_args(cx, decl, None, args); (generics, decl) }); - ForeignFunctionItem(Box::new(Function { decl, generics })) - } - // FIXME(missing_unsafe_on_extern) handle safety of foreign statics. - // Safety was added as part of the implementation of unsafe extern blocks PR #124482 - hir::ForeignItemKind::Static(ty, mutability, _) => { - ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None }) + ForeignFunctionItem(Box::new(Function { decl, generics }), safety) } + hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem( + Static { type_: clean_ty(ty, cx), mutability, expr: None }, + safety, + ), hir::ForeignItemKind::Type => ForeignTypeItem, }; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 69678b727c11..c4020f2a450b 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -639,14 +639,14 @@ impl Item { hir::FnHeader { safety: sig.safety(), abi: sig.abi(), constness, asyncness } } let header = match *self.kind { - ItemKind::ForeignFunctionItem(_) => { + ItemKind::ForeignFunctionItem(_, safety) => { let def_id = self.def_id().unwrap(); let abi = tcx.fn_sig(def_id).skip_binder().abi(); hir::FnHeader { safety: if abi == Abi::RustIntrinsic { intrinsic_operation_unsafety(tcx, def_id.expect_local()) } else { - hir::Safety::Unsafe + safety }, abi, constness: if tcx.is_const_fn(def_id) @@ -842,9 +842,9 @@ pub(crate) enum ItemKind { StructFieldItem(Type), VariantItem(Variant), /// `fn`s from an extern block - ForeignFunctionItem(Box), + ForeignFunctionItem(Box, hir::Safety), /// `static`s from an extern block - ForeignStaticItem(Static), + ForeignStaticItem(Static, hir::Safety), /// `type`s from an extern block ForeignTypeItem, MacroItem(Macro), @@ -893,8 +893,8 @@ impl ItemKind { | TyMethodItem(_) | MethodItem(_, _) | StructFieldItem(_) - | ForeignFunctionItem(_) - | ForeignStaticItem(_) + | ForeignFunctionItem(_, _) + | ForeignStaticItem(_, _) | ForeignTypeItem | MacroItem(_) | ProcMacroItem(_) @@ -924,8 +924,8 @@ impl ItemKind { | StaticItem(_) | ConstantItem(_, _, _) | TraitAliasItem(_) - | ForeignFunctionItem(_) - | ForeignStaticItem(_) + | ForeignFunctionItem(_, _) + | ForeignStaticItem(_, _) | ForeignTypeItem | MacroItem(_) | ProcMacroItem(_) diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index c85b955d4c57..346e9a4e113a 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -84,8 +84,8 @@ pub(crate) trait DocFolder: Sized { | TyMethodItem(_) | MethodItem(_, _) | StructFieldItem(_) - | ForeignFunctionItem(_) - | ForeignStaticItem(_) + | ForeignFunctionItem(..) + | ForeignStaticItem(..) | ForeignTypeItem | MacroItem(_) | ProcMacroItem(_) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e1f79254b248..009738659152 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -254,7 +254,7 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf match &*item.kind { clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items), - clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => { + clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => { item_function(buf, cx, item, f) } clean::TraitItem(ref t) => item_trait(buf, cx, item, t), @@ -265,7 +265,8 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf clean::MacroItem(ref m) => item_macro(buf, cx, item, m), clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m), clean::PrimitiveItem(_) => item_primitive(buf, cx, item), - clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(buf, cx, item, i), + clean::StaticItem(ref i) => item_static(buf, cx, item, i, None), + clean::ForeignStaticItem(ref i, safety) => item_static(buf, cx, item, i, Some(*safety)), clean::ConstantItem(generics, ty, c) => item_constant(buf, cx, item, generics, ty, c), clean::ForeignTypeItem => item_foreign_type(buf, cx, item), clean::KeywordItem => item_keyword(buf, cx, item), @@ -491,11 +492,14 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: } let unsafety_flag = match *myitem.kind { - clean::FunctionItem(_) | clean::ForeignFunctionItem(_) + clean::FunctionItem(_) | clean::ForeignFunctionItem(..) if myitem.fn_header(tcx).unwrap().safety == hir::Safety::Unsafe => { "" } + clean::ForeignStaticItem(_, hir::Safety::Unsafe) => { + "" + } _ => "", }; @@ -1957,13 +1961,22 @@ fn item_fields( } } -fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { +fn item_static( + w: &mut impl fmt::Write, + cx: &mut Context<'_>, + it: &clean::Item, + s: &clean::Static, + safety: Option, +) { wrap_item(w, |buffer| { render_attributes_in_code(buffer, it, cx); write!( buffer, - "{vis}static {mutability}{name}: {typ}", + "{vis}{safe}static {mutability}{name}: {typ}", vis = visibility_print_with_space(it, cx), + safe = safety + .map(|safe| if safe == hir::Safety::Unsafe { "unsafe " } else { "" }) + .unwrap_or(""), mutability = s.mutability.print_with_space(), name = it.name.unwrap(), typ = s.type_.print(cx) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index afafb4fbe4b0..d099a97f1cba 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -310,14 +310,16 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { EnumItem(e) => ItemEnum::Enum(e.into_tcx(tcx)), VariantItem(v) => ItemEnum::Variant(v.into_tcx(tcx)), FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), tcx)), - ForeignFunctionItem(f) => ItemEnum::Function(from_function(f, false, header.unwrap(), tcx)), + ForeignFunctionItem(f, _) => { + ItemEnum::Function(from_function(f, false, header.unwrap(), tcx)) + } TraitItem(t) => ItemEnum::Trait((*t).into_tcx(tcx)), TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)), MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), tcx)), TyMethodItem(m) => ItemEnum::Function(from_function(m, false, header.unwrap(), tcx)), ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)), StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), - ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), + ForeignStaticItem(s, _) => ItemEnum::Static(s.into_tcx(tcx)), ForeignTypeItem => ItemEnum::ForeignType, TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_tcx(tcx)), OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)), diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index 0660037e4d83..b335dc5bd16b 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -33,8 +33,8 @@ pub(crate) trait DocVisitor: Sized { | TyMethodItem(_) | MethodItem(_, _) | StructFieldItem(_) - | ForeignFunctionItem(_) - | ForeignStaticItem(_) + | ForeignFunctionItem(..) + | ForeignStaticItem(..) | ForeignTypeItem | MacroItem(_) | ProcMacroItem(_) diff --git a/src/tools/cargo b/src/tools/cargo index 3ed207e416fb..bc89bffa5987 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 3ed207e416fb2f678a40cc79c02dcf4f936a21ce +Subproject commit bc89bffa5987d4af8f71011c7557119b39e44a65 diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr index 73255651abea..b15857c325ae 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr +++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr @@ -62,7 +62,7 @@ LL | } LL | match s.len() { LL ~ 10 => 2, LL | 20 => { - ... +... LL | if foo() { LL ~ return 20; LL | } diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr index 0cce718a1ac7..f25c02937545 100644 --- a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr @@ -212,7 +212,7 @@ help: check if the original Iterator contains an element instead of collecting t | LL ~ LL | - ... +... LL | // Do lint LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr index ce64861fa40a..de048091cfbe 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.stderr +++ b/src/tools/clippy/tests/ui/needless_late_init.stderr @@ -215,7 +215,7 @@ help: move the declaration `x` here | LL ~ LL | // types that should be considered insignificant - ... +... LL | let y = Box::new(4); LL ~ let x = SignificantDrop; | diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index bf5a89d8b75d..b49f199ba5ab 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -518,7 +518,7 @@ help: remove `return` | LL ~ 10 LL | }, - ... +... LL | }, LL ~ } | diff --git a/src/tools/miri/src/alloc_bytes.rs b/src/tools/miri/src/alloc_bytes.rs index 87579293001d..84225d83b6ae 100644 --- a/src/tools/miri/src/alloc_bytes.rs +++ b/src/tools/miri/src/alloc_bytes.rs @@ -112,4 +112,8 @@ impl AllocBytes for MiriAllocBytes { fn as_mut_ptr(&mut self) -> *mut u8 { self.ptr } + + fn as_ptr(&self) -> *const u8 { + self.ptr + } } diff --git a/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs b/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs index 888c548e49b5..fa7c0bf5c0cb 100644 --- a/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs +++ b/src/tools/miri/tests/fail/intrinsic_fallback_is_spec.rs @@ -1,4 +1,4 @@ -#![feature(rustc_attrs, effects)] +#![feature(rustc_attrs)] #[rustc_intrinsic] #[rustc_nounwind] diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index f4c101cf81c4..487132683e92 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -387,7 +387,7 @@ pub fn recursive_diff(dir1: impl AsRef, dir2: impl AsRef) { }); } -pub fn read_dir(dir: impl AsRef, callback: F) { +pub fn read_dir(dir: impl AsRef, mut callback: F) { for entry in fs_wrapper::read_dir(dir) { callback(&entry.unwrap().path()); } diff --git a/src/tools/rustfmt/.github/workflows/integration.yml b/src/tools/rustfmt/.github/workflows/integration.yml index 314ce0e84c61..f0dd0cf73bbd 100644 --- a/src/tools/rustfmt/.github/workflows/integration.yml +++ b/src/tools/rustfmt/.github/workflows/integration.yml @@ -19,7 +19,6 @@ jobs: matrix: integration: [ bitflags, - error-chain, log, mdbook, packed_simd, diff --git a/src/tools/rustfmt/CHANGELOG.md b/src/tools/rustfmt/CHANGELOG.md index ec4c682d2c4d..89e90fb17ddb 100644 --- a/src/tools/rustfmt/CHANGELOG.md +++ b/src/tools/rustfmt/CHANGELOG.md @@ -2,6 +2,99 @@ ## [Unreleased] +### Fixed + +- Fix an idempotency issue when rewriting where clauses in which rustfmt would continuously add a trailing comma `,` to the end of trailing line comments [#5941](https://github.com/rust-lang/rustfmt/issues/5941). +- Prevent enum variant attributes from wrapping one character early when using `version=Two` [#5801](https://github.com/rust-lang/rustfmt/issues/5801) +- Properly wrap macro matchers at the `max_width` when using `version=Two` and `format_macro_matchers=true` [#3805](https://github.com/rust-lang/rustfmt/issues/3805) +- Prevent panic when formatting trait declaration with non [Unicode Normalization Form] C (NFC) identifiers [#6069](https://github.com/rust-lang/rustfmt/issues/6069) + ```rust + // The ó below is two codepoints, ASCII o followed by U+0301 COMBINING ACUTE ACCENT. + // It NFC-normalizes to ó, U+00F3 LATIN SMALL LETTER O WITH ACUTE. + trait Foó: Bar {} + ``` + [unicode normalization form]: https://unicode.org/reports/tr15/ +- Ensure a space is added to a range expression, when the right hand side of the range expression is a binary expression that ends with a trailing period [#6059](https://github.com/rust-lang/rustfmt/issues/6059) + ```rust + let range = 3. / 2. ..4.; + ``` +- When using `version=Two`, comments in match arms that contain `=>` no longer prevent formatting [#5998](https://github.com/rust-lang/rustfmt/issues/5998) + ```rust + match a { + _ => + // comment with => + { + println!("A") + } + } + ``` +- Prevent panics when formatting input that contains the expanded form of `offset_of!` [#5885](https://github.com/rust-lang/rustfmt/issues/5885) [#6105](https://github.com/rust-lang/rustfmt/issues/6105) + ```rust + const _: () = builtin # offset_of(x, x); + ``` +- When using `version=Two` inner attributes in `match` expressions are correctly indented [#6147](https://github.com/rust-lang/rustfmt/issues/6147) + ```rust + pub fn main() { + match x { + #![attr1] + #![attr2] + _ => (), + } + } + ``` +- Output correct syntax for type ascription builtin [#6159](https://github.com/rust-lang/rustfmt/issues/6159) + ```rust + fn main() { + builtin # type_ascribe(10, usize) + } + ``` +- rustfmt no longer removes inner attributes from inline const blocks [#6158](https://github.com/rust-lang/rustfmt/issues/6158) + ```rust + fn main() { + const { + #![allow(clippy::assertions_on_constants)] + + assert!(1 < 2); + } + } + ``` +- rustfmt no longer removes `safe` and `unsafe` keywords from static items in extern blocks. + This helps support [`#![feature(unsafe_extern_blocks)]`](https://github.com/rust-lang/rust/issues/123743) [#6204](https://github.com/rust-lang/rustfmt/pull/6204) + ```rust + #![feature(unsafe_extern_blocks)] + + unsafe extern "C" { + safe static TEST1: i32; + unsafe static TEST2: i32; + } + ``` + + +### Changed + +- `hide_parse_errors` has been soft deprecated and it's been renamed to `show_parse_errors` [#5961](https://github.com/rust-lang/rustfmt/pull/5961). +- The diff output produced by `rustfmt --check` is more compatable with editors that support navigating directly to line numbers [#5971](https://github.com/rust-lang/rustfmt/pull/5971) +- When using `version=Two`, the `trace!` macro from the [log crate] is now formatted similarly to `debug!`, `info!`, `warn!`, and `error!` [#5987](https://github.com/rust-lang/rustfmt/issues/5987). + + [log crate]: https://crates.io/crates/log + + +### Added + +- `generated_marker_line_search_limit` is a new unstable configuration option that allows users to configure how many lines to search for an `@generated` marker when `format_generated_files=false` [#5658](https://github.com/rust-lang/rustfmt/issues/5658) + + +### Misc + +- Updating `dirs 4.0.0 -> 5.0.1` and `cargo_metadata 0.15.4 -> 0.18.0` [#6033] (https://github.com/rust-lang/rustfmt/issues/6033) + - For reference, here's the [dirs v5 changelog](https://github.com/dirs-dev/dirs-rs/blob/main/README.md#5) +- Updated [itertools v0.11 -> v0.12](https://github.com/rust-itertools/itertools/blob/v0.12.1/CHANGELOG.md#0120) [#6093](https://github.com/rust-lang/rustfmt/pull/6093) +- Addressed clap deprecations output when running `cargo check --features clap/deprecated` [#6101](https://github.com/rust-lang/rustfmt/pull/6101) +- Bumped bytecount `0.6.4` -> `0.6.8` to fix compilation issues with the `generic-simd` feature. See [bytecount#92] and [bytecount#93] + + [bytecount#92]: https://github.com/llogiq/bytecount/pull/92 + [bytecount#93]: https://github.com/llogiq/bytecount/pull/93 +- Replace the `lazy_static` dependency with `std::sync::OnceLock` [#6154](https://github.com/rust-lang/rustfmt/pull/6154) ## [1.7.0] 2023-10-22 @@ -27,7 +120,7 @@ } ``` - Prevent ICE when formatting `vec!{}` [#5735](https://github.com/rust-lang/rustfmt/issues/5735) -- Prevent internal trailing whitespace error when formatting an empty `macro_rules!` defintion e.g. `macro_rules! foo {}` [#5882](https://github.com/rust-lang/rustfmt/issues/5882) +- Prevent internal trailing whitespace error when formatting an empty `macro_rules!` definition e.g. `macro_rules! foo {}` [#5882](https://github.com/rust-lang/rustfmt/issues/5882) - Formatting doc comment lines that start with `.` or `)` won't be treated as ordered markdown lists because `.` or `)` must be preceded by a number to start an ordered markdown list [#5835](https://github.com/rust-lang/rustfmt/pull/5835) - Add parenthesis around closures when they're used as method receives, don't have a block body, and end with `.` [#4808](https://github.com/rust-lang/rustfmt/issues/4808) ```rust @@ -184,7 +277,7 @@ - Simplify the rustfmt help text by eliding the full path to the rustfmt binary path from the usage string when running `rustfmt --help` [#5214](https://github.com/rust-lang/rustfmt/issues/5214) -- Bumped the version for serveral dependencies. Most notably `dirs` `v2.0.1` -> `v4.0.0`. This changed the global user config directory on macOS from `$HOME/Library/Preferences` to `$HOME/Library/Application Support` [#5237](https://github.com/rust-lang/rustfmt/pull/5237) +- Bumped the version for several dependencies. Most notably `dirs` `v2.0.1` -> `v4.0.0`. This changed the global user config directory on macOS from `$HOME/Library/Preferences` to `$HOME/Library/Application Support` [#5237](https://github.com/rust-lang/rustfmt/pull/5237) ### Fixed @@ -942,7 +1035,7 @@ from formatting an attribute #3665 ### Fixed -- Do not remove path disambiugator inside macro #3142 +- Do not remove path disambiguator inside macro #3142 - Improve handling of Windows newlines #3141 - Fix alignment of a struct's fields (`struct_field_align_threshold` option) with the Visual `indent_style` #3165 - Fix a bug in formatting markdown lists within comments #3172 @@ -1031,7 +1124,7 @@ from formatting an attribute #3665 ### Changed -- Replace '--conifig-help' with '--config=help' cb10e06 +- Replace '--config-help' with '--config=help' cb10e06 - Improve formatting of slice patterns #2912 ### Fixed @@ -1075,7 +1168,7 @@ from formatting an attribute #3665 - Add max_width option for all heuristics c2ae39e - Add config option `format_macro_matchers` to format the metavariable matching patterns in macros 79c5ee8 - Add config option `format_macro_bodies` to format the bodies of macros 79c5ee8 -- Format exitential type fc307ff +- Format existential type fc307ff - Support raw identifiers in struct expressions f121b1a - Format Async block and async function 0b25f60 @@ -1131,7 +1224,7 @@ from formatting an attribute #3665 ### Changed -- Update rustc-ap-syntax to 128.0.0 and ustc-ap-rustc_target to 128.0.0 195395f +- Update rustc-ap-syntax to 128.0.0 and rustc-ap-rustc_target to 128.0.0 195395f - Put operands on its own line when each fits in a single line f8439ce - Improve CLI options 55ac062 1869888 798bffb 4d9de48 eca7796 8396da1 5d9f5aa @@ -1195,7 +1288,7 @@ from formatting an attribute #3665 - Do not collapse block around expr with condition on match arm 5b9b7d5 - Use vertical layout for complex attributes c77708f - Format array using heuristics for function calls 98c6f7b -- Implement stable ordering for impl items with the the following item priority: type, const, macro, then method fa80ddf +- Implement stable ordering for impl items with the following item priority: type, const, macro, then method fa80ddf - Reorder imports by default 164cf7d - Group `extern crate` by default 3a138a2 - Make `error_on_line_overflow` false by default f146711 diff --git a/src/tools/rustfmt/Cargo.lock b/src/tools/rustfmt/Cargo.lock index 8fcefa97489d..2a1fffa50fed 100644 --- a/src/tools/rustfmt/Cargo.lock +++ b/src/tools/rustfmt/Cargo.lock @@ -98,12 +98,9 @@ dependencies = [ [[package]] name = "bytecount" -version = "0.6.4" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad152d03a2c813c80bb94fedbf3a3f02b28f793e39e7c214c8a0bcc196343de7" -dependencies = [ - "packed_simd", -] +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "camino" @@ -125,9 +122,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.4" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +checksum = "fb9ac64500cc83ce4b9f8dafa78186aa008c8dea77a09b94cd307fd0cd5022a8" dependencies = [ "camino", "cargo-platform", @@ -217,9 +214,9 @@ checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] @@ -236,13 +233,14 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.7" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys", ] [[package]] @@ -343,9 +341,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -368,12 +366,6 @@ version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - [[package]] name = "log" version = "0.4.16" @@ -408,38 +400,24 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", - "libm", -] - [[package]] name = "once_cell" version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" -[[package]] -name = "packed_simd" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f9f08af0c877571712e2e3e686ad79efad9657dbf0f7c3c8ba943ff6c38932d" -dependencies = [ - "cfg-if", - "num-traits", -] - [[package]] name = "pin-project-lite" version = "0.2.9" @@ -521,7 +499,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.7.0" +version = "1.7.1" dependencies = [ "annotate-snippets", "anyhow", @@ -534,7 +512,6 @@ dependencies = [ "getopts", "ignore", "itertools", - "lazy_static", "regex", "rustfmt-config_proc_macro", "serde", diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml index 032b9b548104..a16620ed99bc 100644 --- a/src/tools/rustfmt/Cargo.toml +++ b/src/tools/rustfmt/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustfmt-nightly" -version = "1.7.0" +version = "1.7.1" description = "Tool to find and fix Rust formatting issues" repository = "https://github.com/rust-lang/rustfmt" readme = "README.md" @@ -35,16 +35,15 @@ generic-simd = ["bytecount/generic-simd"] [dependencies] annotate-snippets = { version = "0.9", features = ["color"] } anyhow = "1.0" -bytecount = "0.6.4" -cargo_metadata = "0.15.4" +bytecount = "0.6.8" +cargo_metadata = "0.18" clap = { version = "4.4.2", features = ["derive"] } clap-cargo = "0.12.0" diff = "0.1" -dirs = "4.0" +dirs = "5.0" getopts = "0.2" ignore = "0.4" -itertools = "0.11" -lazy_static = "1.4" +itertools = "0.12" regex = "1.7" serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0" diff --git a/src/tools/rustfmt/Configurations.md b/src/tools/rustfmt/Configurations.md index ac5747800b25..f52c25731549 100644 --- a/src/tools/rustfmt/Configurations.md +++ b/src/tools/rustfmt/Configurations.md @@ -1,6 +1,6 @@ # Configuring Rustfmt -Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well. +Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/5.0.1/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well. A possible content of `rustfmt.toml` or `.rustfmt.toml` might look like this: @@ -1050,8 +1050,8 @@ Max width for code snippets included in doc comments. Only used if [`format_code ## `format_generated_files` -Format generated files. A file is considered generated -if any of the first five lines contain a `@generated` comment marker. +Format generated files. A file is considered generated if any of the first several lines contain a `@generated` comment marker. The number of lines to check is configured by `generated_marker_line_search_limit`. + By default, generated files are reformatted, i. e. `@generated` marker is ignored. This option is currently ignored for stdin (`@generated` in stdin is ignored.) @@ -1059,6 +1059,16 @@ This option is currently ignored for stdin (`@generated` in stdin is ignored.) - **Possible values**: `true`, `false` - **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080)) +## `generated_marker_line_search_limit` + +Number of lines to check for a `@generated` pragma header, starting from the top of the file. Setting this value to `0` will treat all files as non-generated. When`format_generated_files` is `true`, this option has no effect. + +- **Default value**: `5` +- **Possible values**: any positive integer +- **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080)) + +See also [format_generated_files](#format_generated_files) link here. + ## `format_macro_matchers` Format the metavariable matching patterns in macros. @@ -1098,7 +1108,7 @@ See also [`format_macro_bodies`](#format_macro_bodies). ## `format_macro_bodies` -Format the bodies of macros. +Format the bodies of declarative macro definitions. - **Default value**: `true` - **Possible values**: `true`, `false` @@ -1248,12 +1258,20 @@ Control the case of the letters in hexadecimal literal values ## `hide_parse_errors` -Do not show parse errors if the parser failed to parse files. +This option is deprecated and has been renamed to `show_parse_errors` to avoid confusion around the double negative default of `hide_parse_errors=false`. - **Default value**: `false` - **Possible values**: `true`, `false` - **Stable**: No (tracking issue: [#3390](https://github.com/rust-lang/rustfmt/issues/3390)) +## `show_parse_errors` + +Show parse errors if the parser failed to parse files. + +- **Default value**: `true` +- **Possible values**: `true`, `false` +- **Stable**: No (tracking issue: [#5977](https://github.com/rust-lang/rustfmt/issues/5977)) + ## `ignore` Skip formatting files and directories that match the specified pattern. @@ -1288,6 +1306,15 @@ If you want to ignore every file under the directory where you put your rustfmt. ignore = ["/"] ``` +If you want to allow specific paths that would otherwise be ignored, prefix those paths with a `!`: + +```toml +ignore = ["bar_dir/*", "!bar_dir/*/what.rs"] +``` + +In this case, all files under `bar_dir` will be ignored, except files like `bar_dir/sub/what.rs` +or `bar_dir/another/what.rs`. + ## `imports_indent` Indent style of imports @@ -1655,7 +1682,7 @@ use core::slice; Controls whether arm bodies are wrapped in cases where the first line of the body cannot fit on the same line as the `=>` operator. -The Style Guide requires that bodies are block wrapped by default if a line break is required after the `=>`, but this option can be used to disable that behavior to prevent wrapping arm bodies in that event, so long as the body does not contain multiple statements nor line comments. +The Style Guide requires that bodies are block wrapped by default if a line break is required after the `=>`, but this option can be used to disable that behavior to prevent wrapping arm bodies in that event, so long as the body contains neither multiple statements nor line comments. - **Default value**: `true` - **Possible values**: `true`, `false` diff --git a/src/tools/rustfmt/Contributing.md b/src/tools/rustfmt/Contributing.md index 69a2c76369f9..2f2ccfb175a9 100644 --- a/src/tools/rustfmt/Contributing.md +++ b/src/tools/rustfmt/Contributing.md @@ -59,7 +59,7 @@ example, the `issue-1111.rs` test file is configured by the file ## Debugging Some `rewrite_*` methods use the `debug!` macro for printing useful information. -These messages can be printed by using the environment variable `RUSTFMT_LOG=rustfmt=DEBUG`. +These messages can be printed by using the environment variable `RUSTFMT_LOG=debug`. These traces can be helpful in understanding which part of the code was used and get a better grasp on the execution flow. diff --git a/src/tools/rustfmt/Processes.md b/src/tools/rustfmt/Processes.md index 61abc87eec9f..64ef20a9bd76 100644 --- a/src/tools/rustfmt/Processes.md +++ b/src/tools/rustfmt/Processes.md @@ -16,7 +16,7 @@ In this Section, we describe how to stabilise an option of the rustfmt's configu Open a pull request that closes the tracking issue. The tracking issue is listed beside the option in `Configurations.md`. - Update the `Config` enum marking the option as stable. -- Update the the `Configuration.md` file marking the option as stable. +- Update the `Configuration.md` file marking the option as stable. - Update `CHANGELOG.md` marking the option as stable. ## After the stabilisation diff --git a/src/tools/rustfmt/build.rs b/src/tools/rustfmt/build.rs index e7b1e1b854c0..9a8bb77a8ed1 100644 --- a/src/tools/rustfmt/build.rs +++ b/src/tools/rustfmt/build.rs @@ -40,7 +40,7 @@ fn channel() -> String { fn commit_hash() -> Option { Command::new("git") - .args(&["rev-parse", "--short", "HEAD"]) + .args(["rev-parse", "--short", "HEAD"]) .output() .ok() .and_then(|r| String::from_utf8(r.stdout).ok()) @@ -48,7 +48,7 @@ fn commit_hash() -> Option { fn commit_date() -> Option { Command::new("git") - .args(&["log", "-1", "--date=short", "--pretty=format:%cd"]) + .args(["log", "-1", "--date=short", "--pretty=format:%cd"]) .output() .ok() .and_then(|r| String::from_utf8(r.stdout).ok()) diff --git a/src/tools/rustfmt/check_diff/.gitignore b/src/tools/rustfmt/check_diff/.gitignore new file mode 100644 index 000000000000..ea8c4bf7f35f --- /dev/null +++ b/src/tools/rustfmt/check_diff/.gitignore @@ -0,0 +1 @@ +/target diff --git a/src/tools/rustfmt/check_diff/Cargo.lock b/src/tools/rustfmt/check_diff/Cargo.lock new file mode 100644 index 000000000000..6716ccdf9a08 --- /dev/null +++ b/src/tools/rustfmt/check_diff/Cargo.lock @@ -0,0 +1,237 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "check_diff" +version = "0.1.0" +dependencies = [ + "clap", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "proc-macro2" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/src/tools/rustfmt/check_diff/Cargo.toml b/src/tools/rustfmt/check_diff/Cargo.toml new file mode 100644 index 000000000000..a1ed154481a9 --- /dev/null +++ b/src/tools/rustfmt/check_diff/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "check_diff" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.4.2", features = ["derive"] } diff --git a/src/tools/rustfmt/check_diff/src/main.rs b/src/tools/rustfmt/check_diff/src/main.rs new file mode 100644 index 000000000000..6d07c1b0df65 --- /dev/null +++ b/src/tools/rustfmt/check_diff/src/main.rs @@ -0,0 +1,25 @@ +use clap::Parser; +/// Inputs for the check_diff script +#[derive(Parser)] +struct CliInputs { + /// Git url of a rustfmt fork to compare against the latest master rustfmt + remote_repo_url: String, + /// Name of the feature branch on the forked repo + feature_branch: String, + /// Optional commit hash from the feature branch + #[arg(short, long)] + commit_hash: Option, + /// Optional comma separated list of rustfmt config options to + /// pass when running the feature branch + #[arg(value_delimiter = ',', short, long, num_args = 1..)] + rustfmt_config: Option>, +} + +fn main() { + let args = CliInputs::parse(); + println!( + "remote_repo_url: {:?}, feature_branch: {:?}, + optional_commit_hash: {:?}, optional_rustfmt_config: {:?}", + args.remote_repo_url, args.feature_branch, args.commit_hash, args.rustfmt_config + ); +} diff --git a/src/tools/rustfmt/ci/check_diff.sh b/src/tools/rustfmt/ci/check_diff.sh index 50c58b1f4925..2a29cb138ef7 100755 --- a/src/tools/rustfmt/ci/check_diff.sh +++ b/src/tools/rustfmt/ci/check_diff.sh @@ -2,9 +2,6 @@ set -e -# https://github.com/rust-lang/rustfmt/issues/5675 -export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH - function print_usage() { echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]" } @@ -31,7 +28,7 @@ function clone_repo() { GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2 } -# Initialize Git submoduels for the repo. +# Initialize Git submodules for the repo. # # Parameters # $1: list of directories to initialize @@ -46,7 +43,7 @@ function init_submodules() { # $2: Output file path for the diff # $3: Any additional configuration options to pass to rustfmt # -# Globlas: +# Globals: # $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 function create_diff() { local config; @@ -67,7 +64,7 @@ function create_diff() { # Parameters # $1: Name of the repository (used for logging) # -# Globlas: +# Globals: # $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt` # $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt` # $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 @@ -90,7 +87,7 @@ function check_diff() { ) if [ -z "$diff" ]; then - echo "no diff detected between rustfmt and the feture branch" + echo "no diff detected between rustfmt and the feature branch" return 0 else echo "$diff" @@ -104,7 +101,7 @@ function check_diff() { # Parameters: # $1: Directory where rustfmt will be cloned # -# Globlas: +# Globals: # $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test # $FEATURE_BRANCH: Name of the feature branch # $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided @@ -114,15 +111,42 @@ function compile_rustfmt() { git remote add feature $REMOTE_REPO git fetch feature $FEATURE_BRANCH - cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt + CARGO_VERSION=$(cargo --version) + echo -e "\ncompiling with $CARGO_VERSION\n" + + # Because we're building standalone binaries we need to set `LD_LIBRARY_PATH` so each + # binary can find it's runtime dependencies. See https://github.com/rust-lang/rustfmt/issues/5675 + # This will prepend the `LD_LIBRARY_PATH` for the master rustfmt binary + export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH + + echo "Building rustfmt from src" + cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt + if [ -z "$OPTIONAL_COMMIT_HASH" ] || [ "$FEATURE_BRANCH" = "$OPTIONAL_COMMIT_HASH" ]; then git switch $FEATURE_BRANCH else git switch $OPTIONAL_COMMIT_HASH --detach fi - cargo build --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt + + # This will prepend the `LD_LIBRARY_PATH` for the feature branch rustfmt binary. + # In most cases the `LD_LIBRARY_PATH` should be the same for both rustfmt binaries that we build + # in `compile_rustfmt`, however, there are scenarios where each binary has different runtime + # dependencies. For example, during subtree syncs we bump the nightly toolchain required to build + # rustfmt, and therefore the feature branch relies on a newer set of runtime dependencies. + export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH + + echo "Building feature rustfmt from src" + cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt + + echo -e "\nRuntime dependencies for rustfmt -- LD_LIBRARY_PATH: $LD_LIBRARY_PATH" + RUSFMT_BIN=$1/rustfmt + RUSTFMT_VERSION=$($RUSFMT_BIN --version) + echo -e "\nRUSFMT_BIN $RUSTFMT_VERSION\n" + FEATURE_BIN=$1/feature_rustfmt + FEATURE_VERSION=$($FEATURE_BIN --version) + echo -e "FEATURE_BIN $FEATURE_VERSION\n" } # Check the diff for running rustfmt and the feature branch on all the .rs files in the repo. @@ -155,7 +179,7 @@ function check_repo() { STATUSES+=($?) set -e - echo "removing tmp_dir $tmp_dir" + echo -e "removing tmp_dir $tmp_dir\n\n" rm -rf $tmp_dir cd $WORKDIR } diff --git a/src/tools/rustfmt/ci/integration.sh b/src/tools/rustfmt/ci/integration.sh index 19d502bc5c7b..ea96e4be1305 100755 --- a/src/tools/rustfmt/ci/integration.sh +++ b/src/tools/rustfmt/ci/integration.sh @@ -104,7 +104,7 @@ case ${INTEGRATION} in check_fmt_with_all_tests cd - ;; - error-chain | tempdir) + tempdir) git clone --depth=1 https://github.com/rust-lang-deprecated/${INTEGRATION}.git cd ${INTEGRATION} show_head diff --git a/src/tools/rustfmt/config_proc_macro/src/attrs.rs b/src/tools/rustfmt/config_proc_macro/src/attrs.rs index d8de9aae088d..e7534b813d70 100644 --- a/src/tools/rustfmt/config_proc_macro/src/attrs.rs +++ b/src/tools/rustfmt/config_proc_macro/src/attrs.rs @@ -68,7 +68,11 @@ fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option { match &attr.meta { syn::Meta::NameValue(syn::MetaNameValue { path, - value: syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit_str), .. }), + value: + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit_str), + .. + }), .. }) if path.is_ident(name) => Some(lit_str.value()), _ => None, diff --git a/src/tools/rustfmt/docs/index.html b/src/tools/rustfmt/docs/index.html index ee0339bc50da..5e588d1db545 100644 --- a/src/tools/rustfmt/docs/index.html +++ b/src/tools/rustfmt/docs/index.html @@ -3,13 +3,33 @@ Rustfmt - - - - + + + + + + - -