diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4a4887f19702f..163170a1d1aa0 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -19,7 +19,7 @@ extern crate tracing; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::vec_map::VecMap; -use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{Diagnostic, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::ChunkedBitSet; @@ -192,13 +192,13 @@ fn do_mir_borrowck<'tcx>( } } - let mut errors = error::BorrowckErrors::new(); + let mut errors = error::BorrowckErrors::new(infcx.tcx); // Gather the upvars of a closure, if any. let tables = tcx.typeck_opt_const_arg(def); - if let Some(ErrorGuaranteed { .. }) = tables.tainted_by_errors { - infcx.set_tainted_by_errors(); - errors.set_tainted_by_errors(); + if let Some(e) = tables.tainted_by_errors { + infcx.set_tainted_by_errors(e); + errors.set_tainted_by_errors(e); } let upvars: Vec<_> = tables .closure_min_captures_flattened(def.did) @@ -2260,6 +2260,7 @@ mod error { use super::*; pub struct BorrowckErrors<'tcx> { + tcx: TyCtxt<'tcx>, /// This field keeps track of move errors that are to be reported for given move indices. /// /// There are situations where many errors can be reported for a single move out (see #53807) @@ -2282,19 +2283,24 @@ mod error { tainted_by_errors: Option, } - impl BorrowckErrors<'_> { - pub fn new() -> Self { + impl<'tcx> BorrowckErrors<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { BorrowckErrors { + tcx, buffered_move_errors: BTreeMap::new(), buffered: Default::default(), tainted_by_errors: None, } } - // FIXME(eddyb) this is a suboptimal API because `tainted_by_errors` is - // set before any emission actually happens (weakening the guarantee). pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_, ErrorGuaranteed>) { - self.tainted_by_errors = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); + if let None = self.tainted_by_errors { + self.tainted_by_errors = Some( + self.tcx + .sess + .delay_span_bug(t.span.clone(), "diagnostic buffered but not emitted"), + ) + } t.buffer(&mut self.buffered); } @@ -2302,8 +2308,8 @@ mod error { t.buffer(&mut self.buffered); } - pub fn set_tainted_by_errors(&mut self) { - self.tainted_by_errors = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); + pub fn set_tainted_by_errors(&mut self, e: ErrorGuaranteed) { + self.tainted_by_errors = Some(e); } } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index f8856b56d140b..4a12e1b1b92e0 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -303,7 +303,10 @@ pub(crate) fn compute_regions<'cx, 'tcx>( if !nll_errors.is_empty() { // Suppress unhelpful extra errors in `infer_opaque_types`. - infcx.set_tainted_by_errors(); + infcx.set_tainted_by_errors(infcx.tcx.sess.delay_span_bug( + body.span, + "`compute_regions` tainted `infcx` with errors but did not emit any errors", + )); } let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index b2db77944fd1e..b9885952a893c 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -219,8 +219,8 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { instantiated_ty: OpaqueHiddenType<'tcx>, origin: OpaqueTyOrigin, ) -> Ty<'tcx> { - if self.is_tainted_by_errors() { - return self.tcx.ty_error(); + if let Some(e) = self.tainted_by_errors() { + return self.tcx.ty_error_with_guaranteed(e); } let definition_ty = instantiated_ty diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 99059e788a074..1e22537c2ba42 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -22,7 +22,19 @@ fn clif_sig_from_fn_abi<'tcx>( default_call_conv: CallConv, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> Signature { - let call_conv = match fn_abi.conv { + let call_conv = conv_to_call_conv(fn_abi.conv, default_call_conv); + + let inputs = fn_abi.args.iter().map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()).flatten(); + + let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx); + // Sometimes the first param is an pointer to the place where the return value needs to be stored. + let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect(); + + Signature { params, returns, call_conv } +} + +pub(crate) fn conv_to_call_conv(c: Conv, default_call_conv: CallConv) -> CallConv { + match c { Conv::Rust | Conv::C => default_call_conv, Conv::RustCold => CallConv::Cold, Conv::X86_64SysV => CallConv::SystemV, @@ -38,15 +50,8 @@ fn clif_sig_from_fn_abi<'tcx>( | Conv::X86VectorCall | Conv::AmdGpuKernel | Conv::AvrInterrupt - | Conv::AvrNonBlockingInterrupt => todo!("{:?}", fn_abi.conv), - }; - let inputs = fn_abi.args.iter().map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()).flatten(); - - let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx); - // Sometimes the first param is an pointer to the place where the return value needs to be stored. - let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect(); - - Signature { params, returns, call_conv } + | Conv::AvrNonBlockingInterrupt => todo!("{:?}", c), + } } pub(crate) fn get_function_sig<'tcx>( diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index cae6312a60735..f7434633ea442 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -63,10 +63,14 @@ pub(crate) fn maybe_create_entry_wrapper( AbiParam::new(m.target_config().pointer_type()), ], returns: vec![AbiParam::new(m.target_config().pointer_type() /*isize*/)], - call_conv: CallConv::triple_default(m.isa().triple()), + call_conv: crate::conv_to_call_conv( + tcx.sess.target.options.entry_abi, + CallConv::triple_default(m.isa().triple()), + ), }; - let cmain_func_id = m.declare_function("main", Linkage::Export, &cmain_sig).unwrap(); + let entry_name = tcx.sess.target.options.entry_name.as_ref(); + let cmain_func_id = m.declare_function(entry_name, Linkage::Export, &cmain_sig).unwrap(); let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx); diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 62a61eb8548da..2e71c3665daa7 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -425,8 +425,9 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } fn declare_c_main(&self, fn_type: Self::Type) -> Option { - if self.get_declared_value("main").is_none() { - Some(self.declare_cfn("main", fn_type)) + let entry_name = self.sess().target.entry_name.as_ref(); + if self.get_declared_value(entry_name).is_none() { + Some(self.declare_entry_fn(entry_name, fn_type, ())) } else { // If the symbol already exists, it is an error: for example, the user wrote diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs index a619e2f771252..eae77508c973a 100644 --- a/compiler/rustc_codegen_gcc/src/declare.rs +++ b/compiler/rustc_codegen_gcc/src/declare.rs @@ -65,13 +65,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { global } - pub fn declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> RValue<'gcc> { + pub fn declare_entry_fn(&self, name: &str, _fn_type: Type<'gcc>, callconv: () /*llvm::CCallConv*/) -> RValue<'gcc> { // TODO(antoyo): use the fn_type parameter. let const_string = self.context.new_type::().make_pointer().make_pointer(); let return_type = self.type_i32(); let variadic = false; self.linkage.set(FunctionType::Exported); - let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic); + let func = declare_raw_fn(self, name, callconv, return_type, &[self.type_i32(), const_string], variadic); // NOTE: it is needed to set the current_func here as well, because get_fn() is not called // for the main function. *self.current_func.borrow_mut() = Some(func); diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index d478efc863a9e..a6fd2a7de6bd0 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -398,23 +398,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } fn llvm_cconv(&self) -> llvm::CallConv { - match self.conv { - Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv, - Conv::RustCold => llvm::ColdCallConv, - Conv::AmdGpuKernel => llvm::AmdGpuKernel, - Conv::AvrInterrupt => llvm::AvrInterrupt, - Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, - Conv::ArmAapcs => llvm::ArmAapcsCallConv, - Conv::Msp430Intr => llvm::Msp430Intr, - Conv::PtxKernel => llvm::PtxKernel, - Conv::X86Fastcall => llvm::X86FastcallCallConv, - Conv::X86Intr => llvm::X86_Intr, - Conv::X86Stdcall => llvm::X86StdcallCallConv, - Conv::X86ThisCall => llvm::X86_ThisCall, - Conv::X86VectorCall => llvm::X86_VectorCall, - Conv::X86_64SysV => llvm::X86_64_SysV, - Conv::X86_64Win64 => llvm::X86_64_Win64, - } + self.conv.into() } fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) { @@ -596,3 +580,25 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { llvm::get_param(self.llfn(), index as c_uint) } } + +impl From for llvm::CallConv { + fn from(conv: Conv) -> Self { + match conv { + Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv, + Conv::RustCold => llvm::ColdCallConv, + Conv::AmdGpuKernel => llvm::AmdGpuKernel, + Conv::AvrInterrupt => llvm::AvrInterrupt, + Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, + Conv::ArmAapcs => llvm::ArmAapcsCallConv, + Conv::Msp430Intr => llvm::Msp430Intr, + Conv::PtxKernel => llvm::PtxKernel, + Conv::X86Fastcall => llvm::X86FastcallCallConv, + Conv::X86Intr => llvm::X86_Intr, + Conv::X86Stdcall => llvm::X86StdcallCallConv, + Conv::X86ThisCall => llvm::X86_ThisCall, + Conv::X86VectorCall => llvm::X86_VectorCall, + Conv::X86_64SysV => llvm::X86_64_SysV, + Conv::X86_64Win64 => llvm::X86_64_Win64, + } + } +} diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index eaa2ccfc835c5..4dcc7cd54477d 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -576,8 +576,14 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn declare_c_main(&self, fn_type: Self::Type) -> Option { - if self.get_declared_value("main").is_none() { - Some(self.declare_cfn("main", llvm::UnnamedAddr::Global, fn_type)) + let entry_name = self.sess().target.entry_name.as_ref(); + if self.get_declared_value(entry_name).is_none() { + Some(self.declare_entry_fn( + entry_name, + self.sess().target.entry_abi.into(), + llvm::UnnamedAddr::Global, + fn_type, + )) } else { // If the symbol already exists, it is an error: for example, the user wrote // #[no_mangle] extern "C" fn main(..) {..} diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index f79ef11720df9..dc21a02cec44a 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -90,6 +90,28 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type) } + /// Declare an entry Function + /// + /// The ABI of this function can change depending on the target (although for now the same as + /// `declare_cfn`) + /// + /// If there’s a value with the same name already declared, the function will + /// update the declaration and return existing Value instead. + pub fn declare_entry_fn( + &self, + name: &str, + callconv: llvm::CallConv, + unnamed: llvm::UnnamedAddr, + fn_type: &'ll Type, + ) -> &'ll Value { + let visibility = if self.tcx.sess.target.default_hidden_visibility { + llvm::Visibility::Hidden + } else { + llvm::Visibility::Default + }; + declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type) + } + /// Declare a Rust function. /// /// If there’s a value with the same name already declared, the function will diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 752f6b1ef40c9..22f534d909ab6 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -180,7 +180,8 @@ fn exported_symbols_provider_local<'tcx>( .collect(); if tcx.entry_fn(()).is_some() { - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, "main")); + let exported_symbol = + ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref())); symbols.push(( exported_symbol, diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index ed69d8554d2cc..f59f34b874c19 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -23,7 +23,7 @@ use super::{ MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, PointerArithmetic, Provenance, Scalar, StackPopJump, }; -use crate::transform::validate::equal_up_to_regions; +use crate::util; pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// Stores the `Machine` instance. @@ -354,8 +354,8 @@ pub(super) fn mir_assign_valid_types<'tcx>( // Type-changing assignments can happen when subtyping is used. While // all normal lifetimes are erased, higher-ranked types with their // late-bound lifetimes are still around and can lead to type - // differences. So we compare ignoring lifetimes. - if equal_up_to_regions(tcx, param_env, src.ty, dest.ty) { + // differences. + if util::is_subtype(tcx, param_env, src.ty, dest.ty) { // Make sure the layout is equal, too -- just to be safe. Miri really // needs layout equality. For performance reason we skip this check when // the types are equal. Equal types *can* have different layouts when diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 81b82a21fa1a7..860dee5898057 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -2,7 +2,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_index::bit_set::BitSet; -use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; use rustc_middle::mir::visit::{PlaceContext, Visitor}; @@ -12,8 +11,7 @@ use rustc_middle::mir::{ ProjectionElem, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK, }; -use rustc_middle::ty::fold::BottomUpFolder; -use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypeVisitable}; +use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitable}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{Analysis, ResultsCursor}; @@ -70,44 +68,6 @@ impl<'tcx> MirPass<'tcx> for Validator { } } -/// Returns whether the two types are equal up to lifetimes. -/// All lifetimes, including higher-ranked ones, get ignored for this comparison. -/// (This is unlike the `erasing_regions` methods, which keep higher-ranked lifetimes for soundness reasons.) -/// -/// The point of this function is to approximate "equal up to subtyping". However, -/// the approximation is incorrect as variance is ignored. -pub fn equal_up_to_regions<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - src: Ty<'tcx>, - dest: Ty<'tcx>, -) -> bool { - // Fast path. - if src == dest { - return true; - } - - // Normalize lifetimes away on both sides, then compare. - let normalize = |ty: Ty<'tcx>| { - tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty).fold_with( - &mut BottomUpFolder { - tcx, - // FIXME: We erase all late-bound lifetimes, but this is not fully correct. - // If you have a type like ` fn(&'a u32) as SomeTrait>::Assoc`, - // this is not necessarily equivalent to `::Assoc`, - // since one may have an `impl SomeTrait for fn(&32)` and - // `impl SomeTrait for fn(&'static u32)` at the same time which - // specify distinct values for Assoc. (See also #56105) - lt_op: |_| tcx.lifetimes.re_erased, - // Leave consts and types unchanged. - ct_op: |ct| ct, - ty_op: |ty| ty, - }, - ) - }; - tcx.infer_ctxt().build().can_eq(param_env, normalize(src), normalize(dest)).is_ok() -} - struct TypeChecker<'a, 'tcx> { when: &'a str, body: &'a Body<'tcx>, @@ -183,22 +143,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return true; } - // Normalize projections and things like that. - // Type-changing assignments can happen when subtyping is used. While - // all normal lifetimes are erased, higher-ranked types with their - // late-bound lifetimes are still around and can lead to type - // differences. So we compare ignoring lifetimes. - - // First, try with reveal_all. This might not work in some cases, as the predicates - // can be cleared in reveal_all mode. We try the reveal first anyways as it is used - // by some other passes like inlining as well. - let param_env = self.param_env.with_reveal_all_normalized(self.tcx); - if equal_up_to_regions(self.tcx, param_env, src, dest) { - return true; - } - - // If this fails, we can try it without the reveal. - equal_up_to_regions(self.tcx, self.param_env, src, dest) + crate::util::is_subtype(self.tcx, self.param_env, src, dest) } } diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs new file mode 100644 index 0000000000000..a9cb191cc593f --- /dev/null +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -0,0 +1,63 @@ +//! Routines to check for relations between fully inferred types. +//! +//! FIXME: Move this to a more general place. The utility of this extends to +//! other areas of the compiler as well. + +use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; +use rustc_infer::traits::ObligationCause; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_trait_selection::traits::ObligationCtxt; + +/// Returns whether the two types are equal up to subtyping. +/// +/// This is used in case we don't know the expected subtyping direction +/// and still want to check whether anything is broken. +pub fn is_equal_up_to_subtyping<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + src: Ty<'tcx>, + dest: Ty<'tcx>, +) -> bool { + // Fast path. + if src == dest { + return true; + } + + // Check for subtyping in either direction. + is_subtype(tcx, param_env, src, dest) || is_subtype(tcx, param_env, dest, src) +} + +/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`. +/// +/// This mostly ignores opaque types as it can be used in constraining contexts +/// while still computing the final underlying type. +pub fn is_subtype<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + src: Ty<'tcx>, + dest: Ty<'tcx>, +) -> bool { + if src == dest { + return true; + } + + let mut builder = + tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble); + let infcx = builder.build(); + let ocx = ObligationCtxt::new(&infcx); + let cause = ObligationCause::dummy(); + let src = ocx.normalize(cause.clone(), param_env, src); + let dest = ocx.normalize(cause.clone(), param_env, dest); + match ocx.sub(&cause, param_env, src, dest) { + Ok(()) => {} + Err(_) => return false, + }; + let errors = ocx.select_all_or_error(); + // With `Reveal::All`, opaque types get normalized away, with `Reveal::UserFacing` + // we would get unification errors because we're unable to look into opaque types, + // even if they're constrained in our current function. + // + // It seems very unlikely that this hides any bugs. + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + errors.is_empty() +} diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 4d0f81a406008..76ea5a24e69ed 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -2,6 +2,7 @@ pub mod aggregate; mod alignment; mod call_kind; pub mod collect_writes; +mod compare_types; mod find_self_call; mod might_permit_raw_init; mod type_name; @@ -9,6 +10,7 @@ mod type_name; pub use self::aggregate::expand_aggregate; pub use self::alignment::is_disaligned; pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind}; +pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype}; pub use self::find_self_call::find_self_call; pub use self::might_permit_raw_init::might_permit_raw_init; pub use self::type_name::type_name; diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 95fff929d46fe..04fe6c4007e94 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1436,7 +1436,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool { let crate_matches = if c.starts_with("allsorts-rental") { true } else { - let mut version = c.trim_start_matches("rental-").split("."); + let mut version = c.trim_start_matches("rental-").split('.'); version.next() == Some("0") && version.next() == Some("5") && version diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 16c40cf1299cb..83b95fe0e911e 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -115,7 +115,7 @@ pub trait AstConv<'tcx> { /// (e.g., resolve) that is translated into a ty-error. This is /// used to help suppress derived errors typeck might otherwise /// report. - fn set_tainted_by_errors(&self); + fn set_tainted_by_errors(&self, e: ErrorGuaranteed); fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span); } @@ -2620,8 +2620,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } Res::Err => { - self.set_tainted_by_errors(); - self.tcx().ty_error() + let e = self + .tcx() + .sess + .delay_span_bug(path.span, "path with `Res:Err` but no error emitted"); + self.set_tainted_by_errors(e); + self.tcx().ty_error_with_guaranteed(e) } _ => span_bug!(span, "unexpected resolution: {:?}", path.res), } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f76b282fa76d5..b4805de961889 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -449,8 +449,8 @@ fn check_opaque_meets_bounds<'tcx>( let misc_cause = traits::ObligationCause::misc(span, hir_id); - match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_ty) { - Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok), + match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) { + Ok(()) => {} Err(ty_err) => { tcx.sess.delay_span_bug( span, diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index 5a222031c5610..0b9209771cd32 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -402,10 +402,8 @@ pub fn collect_trait_impl_trait_tys<'tcx>( unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()), ); - match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) { - Ok(infer::InferOk { value: (), obligations }) => { - ocx.register_obligations(obligations); - } + match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) { + Ok(()) => {} Err(terr) => { let mut diag = struct_span_err!( tcx.sess, @@ -442,10 +440,8 @@ pub fn collect_trait_impl_trait_tys<'tcx>( // the lifetimes of the return type, but do this after unifying just the // return types, since we want to avoid duplicating errors from // `compare_predicate_entailment`. - match infcx.at(&cause, param_env).eq(trait_fty, impl_fty) { - Ok(infer::InferOk { value: (), obligations }) => { - ocx.register_obligations(obligations); - } + match ocx.eq(&cause, param_env, trait_fty, impl_fty) { + Ok(()) => {} Err(terr) => { // This function gets called during `compare_predicate_entailment` when normalizing a // signature that contains RPITIT. When the method signatures don't match, we have to diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 2f64a88f03afe..a738ee4a14887 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -518,7 +518,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { ty } - fn set_tainted_by_errors(&self) { + fn set_tainted_by_errors(&self, _: ErrorGuaranteed) { // There's no obvious place to track this, so just let it go. } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index c1e4ab600f34f..af0b7f62ae319 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1561,7 +1561,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // Mark that we've failed to coerce the types here to suppress // any superfluous errors we might encounter while trying to // emit or provide suggestions on how to fix the initial error. - fcx.set_tainted_by_errors(); + fcx.set_tainted_by_errors( + fcx.tcx.sess.delay_span_bug(cause.span, "coercion error but no error emitted"), + ); let (expected, found) = if label_expression_as_expected { // In the case where this is a "forced unit", like // `break`, we want to call the `()` "expected" diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 9ca7730daa68d..5a34ab401749f 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -154,7 +154,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(e) => e, }; - self.set_tainted_by_errors(); + self.set_tainted_by_errors(self.tcx.sess.delay_span_bug( + expr.span, + "`TypeError` when attempting coercion but no error emitted", + )); let expr = expr.peel_drop_temps(); let cause = self.misc(expr.span); let expr_ty = self.resolve_vars_with_obligations(checked_ty); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 13a03b33de815..752d2e0ff7858 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -527,12 +527,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span); let ty = match res { Res::Err => { - self.set_tainted_by_errors(); - tcx.ty_error() + let e = + self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); + self.set_tainted_by_errors(e); + tcx.ty_error_with_guaranteed(e) } Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => { - report_unexpected_variant_res(tcx, res, qpath, expr.span); - tcx.ty_error() + let e = report_unexpected_variant_res(tcx, res, qpath, expr.span); + tcx.ty_error_with_guaranteed(e) } _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, }; @@ -1962,7 +1964,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_span: Span, ) { if variant.is_recovered() { - self.set_tainted_by_errors(); + self.set_tainted_by_errors( + self.tcx + .sess + .delay_span_bug(expr_span, "parser recovered but no error was emitted"), + ); return; } let mut err = self.err_ctxt().type_error_struct_with_diag( diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 5d44092a5f68e..ac6b0924ab572 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -104,7 +104,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // type, `?T` is not considered unsolved, but `?I` is. The // same is true for float variables.) let fallback = match ty.kind() { - _ if self.is_tainted_by_errors() => self.tcx.ty_error(), + _ if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error_with_guaranteed(e), ty::Infer(ty::IntVar(_)) => self.tcx.types.i32, ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, _ => match diverging_fallback.get(&ty) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index c826a886ca641..b85a23257286b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -140,8 +140,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("write_ty({:?}, {:?}) in fcx {}", id, self.resolve_vars_if_possible(ty), self.tag()); self.typeck_results.borrow_mut().node_types_mut().insert(id, ty); - if ty.references_error() { - self.set_tainted_by_errors(); + if let Err(e) = ty.error_reported() { + self.set_tainted_by_errors(e); } } @@ -528,7 +528,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { match self.typeck_results.borrow().node_types().get(id) { Some(&t) => t, - None if self.is_tainted_by_errors() => self.tcx.ty_error(), + None if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error_with_guaranteed(e), None => { bug!( "no type for node {}: {} in fcx {}", @@ -543,7 +543,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn node_ty_opt(&self, id: hir::HirId) -> Option> { match self.typeck_results.borrow().node_types().get(id) { Some(&t) => Some(t), - None if self.is_tainted_by_errors() => Some(self.tcx.ty_error()), + None if let Some(e) = self.tainted_by_errors() => Some(self.tcx.ty_error_with_guaranteed(e)), None => None, } } @@ -1148,9 +1148,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { explicit_late_bound = ExplicitLateBound::Yes; } - if let Err(GenericArgCountMismatch { reported: Some(_), .. }) = arg_count.correct { + if let Err(GenericArgCountMismatch { reported: Some(e), .. }) = arg_count.correct { infer_args_for_err.insert(index); - self.set_tainted_by_errors(); // See issue #53251. + self.set_tainted_by_errors(e); // See issue #53251. } } @@ -1440,12 +1440,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !ty.is_ty_var() { ty } else { - if !self.is_tainted_by_errors() { + let e = self.tainted_by_errors().unwrap_or_else(|| { self.err_ctxt() .emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true) - .emit(); - } - let err = self.tcx.ty_error(); + .emit() + }); + let err = self.tcx.ty_error_with_guaranteed(e); self.demand_suptype(sp, err, ty); err } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c3833b4872d99..a31ab9c8b23b8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -511,8 +511,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var()) } - self.set_tainted_by_errors(); let tcx = self.tcx; + // FIXME: taint after emitting errors and pass through an `ErrorGuaranteed` + self.set_tainted_by_errors( + tcx.sess.delay_span_bug(call_span, "no errors reported for args"), + ); // Get the argument span in the context of the call span so that // suggestions and labels are (more) correct when an arg is a @@ -1207,7 +1210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); let variant = match def { Res::Err => { - self.set_tainted_by_errors(); + self.set_tainted_by_errors( + self.tcx.sess.delay_span_bug(path_span, "`Res::Err` but no error emitted"), + ); return None; } Res::Def(DefKind::Variant, _) => match ty.kind() { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index d5e4b6de581c3..177d521d2804c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -4,6 +4,7 @@ mod checks; mod suggestions; pub use _impl::*; +use rustc_errors::ErrorGuaranteed; pub use suggestions::*; use crate::coercion::DynamicCoerceMany; @@ -289,8 +290,8 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } } - fn set_tainted_by_errors(&self) { - self.infcx.set_tainted_by_errors() + fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { + self.infcx.set_tainted_by_errors(e) } fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 6fd609aeaa060..334d6d0aa6c20 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -53,7 +53,7 @@ use crate::check::check_fn; use crate::coercion::DynamicCoerceMany; use crate::gather_locals::GatherLocalsVisitor; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{struct_span_err, MultiSpan}; +use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit::Visitor; @@ -344,7 +344,7 @@ fn typeck_with_fallback<'tcx>( fcx.select_all_obligations_or_error(); - if !fcx.infcx.is_tainted_by_errors() { + if let None = fcx.infcx.tainted_by_errors() { fcx.check_transmutes(); } @@ -428,7 +428,12 @@ impl<'tcx> EnclosingBreakables<'tcx> { } } -fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) { +fn report_unexpected_variant_res( + tcx: TyCtxt<'_>, + res: Res, + qpath: &hir::QPath<'_>, + span: Span, +) -> ErrorGuaranteed { struct_span_err!( tcx.sess, span, @@ -437,7 +442,7 @@ fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<' res.descr(), rustc_hir_pretty::qpath_to_string(qpath), ) - .emit(); + .emit() } /// Controls whether the arguments are tupled. This is used for the call diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 362f1c3430041..0b5dc946c1def 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } fn is_tainted_by_errors(&self) -> bool { - self.infcx.is_tainted_by_errors() + self.infcx.tainted_by_errors().is_some() } fn resolve_type_vars_or_error( diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index e2c5edd0e8833..4ac4914bd4479 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let report_candidates = |span: Span, err: &mut Diagnostic, sources: &mut Vec, - sugg_span: Span| { + sugg_span: Option| { sources.sort(); sources.dedup(); // Dynamic limit to avoid hiding just one candidate, which is silly. @@ -175,7 +175,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.note(¬e_str); } - if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) { + if let Some(sugg_span) = sugg_span + && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) { let path = self.tcx.def_path_str(trait_ref.def_id); let ty = match item.kind { @@ -224,20 +225,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_note(item_span, msg); None }; - let path = self.tcx.def_path_str(trait_did); - print_disambiguation_help( - item_name, - args, - err, - path, - rcvr_ty, - item.kind, - item.def_id, - sugg_span, - idx, - self.tcx.sess.source_map(), - item.fn_has_self_parameter, - ); + if let Some(sugg_span) = sugg_span { + let path = self.tcx.def_path_str(trait_did); + print_disambiguation_help( + item_name, + args, + err, + path, + rcvr_ty, + item.kind, + item.def_id, + sugg_span, + idx, + self.tcx.sess.source_map(), + item.fn_has_self_parameter, + ); + } } } } @@ -407,9 +410,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg_span, ); - report_candidates(span, &mut err, &mut static_candidates, sugg_span); + report_candidates(span, &mut err, &mut static_candidates, None); } else if static_candidates.len() > 1 { - report_candidates(span, &mut err, &mut static_candidates, sugg_span); + report_candidates(span, &mut err, &mut static_candidates, Some(sugg_span)); } let mut bound_spans = vec![]; @@ -1015,7 +1018,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(item_name.span, format!("multiple `{}` found", item_name)); - report_candidates(span, &mut err, &mut sources, sugg_span); + report_candidates(span, &mut err, &mut sources, Some(sugg_span)); err.emit(); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index eb10f3e2c107f..a62d43561302b 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -839,12 +839,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (res, opt_ty, segments) = path_resolution; match res { Res::Err => { - self.set_tainted_by_errors(); - return tcx.ty_error(); + let e = tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); + self.set_tainted_by_errors(e); + return tcx.ty_error_with_guaranteed(e); } Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fictive | CtorKind::Fn), _) => { - report_unexpected_variant_res(tcx, res, qpath, pat.span); - return tcx.ty_error(); + let e = report_unexpected_variant_res(tcx, res, qpath, pat.span); + return tcx.ty_error_with_guaranteed(e); } Res::SelfCtor(..) | Res::Def( @@ -985,9 +986,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let on_error = || { + let on_error = |e| { for pat in subpats { - self.check_pat(pat, tcx.ty_error(), def_bm, ti); + self.check_pat(pat, tcx.ty_error_with_guaranteed(e), def_bm, ti); } }; let report_unexpected_res = |res: Res| { @@ -1014,36 +1015,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(pat.span, "not a tuple variant or struct"); } } - err.emit(); - on_error(); + let e = err.emit(); + on_error(e); + e }; // Resolve the path and check the definition for errors. let (res, opt_ty, segments) = self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span); if res == Res::Err { - self.set_tainted_by_errors(); - on_error(); - return self.tcx.ty_error(); + let e = tcx.sess.delay_span_bug(pat.span, "`Res:Err` but no error emitted"); + self.set_tainted_by_errors(e); + on_error(e); + return tcx.ty_error_with_guaranteed(e); } // Type-check the path. let (pat_ty, res) = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id); if !pat_ty.is_fn() { - report_unexpected_res(res); - return tcx.ty_error(); + let e = report_unexpected_res(res); + return tcx.ty_error_with_guaranteed(e); } let variant = match res { Res::Err => { - self.set_tainted_by_errors(); - on_error(); - return tcx.ty_error(); + let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted"); + self.set_tainted_by_errors(e); + on_error(e); + return tcx.ty_error_with_guaranteed(e); } Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => { - report_unexpected_res(res); - return tcx.ty_error(); + let e = report_unexpected_res(res); + return tcx.ty_error_with_guaranteed(e); } Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res), _ => bug!("unexpected pattern resolution: {:?}", res), @@ -1082,9 +1086,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } else { // Pattern has wrong number of fields. - self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err); - on_error(); - return tcx.ty_error(); + let e = self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err); + on_error(e); + return tcx.ty_error_with_guaranteed(e); } pat_ty } @@ -1098,7 +1102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [ty::FieldDef], expected: Ty<'tcx>, had_err: bool, - ) { + ) -> ErrorGuaranteed { let subpats_ending = pluralize!(subpats.len()); let fields_ending = pluralize!(fields.len()); @@ -1245,7 +1249,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - err.emit(); + err.emit() } fn check_pat_tuple( diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 2eca40d678a84..6c2ee35fa50da 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -83,10 +83,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.typeck_results.treat_byte_string_as_slice = mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice); - if self.is_tainted_by_errors() { - // FIXME(eddyb) keep track of `ErrorGuaranteed` from where the error was emitted. - wbcx.typeck_results.tainted_by_errors = - Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); + if let Some(e) = self.tainted_by_errors() { + wbcx.typeck_results.tainted_by_errors = Some(e); } debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results); @@ -674,10 +672,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // We may have introduced e.g. `ty::Error`, if inference failed, make sure // to mark the `TypeckResults` as tainted in that case, so that downstream // users of the typeck results don't produce extra errors, or worse, ICEs. - if resolver.replaced_with_error { - // FIXME(eddyb) keep track of `ErrorGuaranteed` from where the error was emitted. - self.typeck_results.tainted_by_errors = - Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); + if let Some(e) = resolver.replaced_with_error { + self.typeck_results.tainted_by_errors = Some(e); } x @@ -708,8 +704,8 @@ struct Resolver<'cx, 'tcx> { span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, - /// Set to `true` if any `Ty` or `ty::Const` had to be replaced with an `Error`. - replaced_with_error: bool, + /// Set to `Some` if any `Ty` or `ty::Const` had to be replaced with an `Error`. + replaced_with_error: Option, } impl<'cx, 'tcx> Resolver<'cx, 'tcx> { @@ -718,12 +714,14 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, ) -> Resolver<'cx, 'tcx> { - Resolver { tcx: fcx.tcx, infcx: fcx, span, body, replaced_with_error: false } + Resolver { tcx: fcx.tcx, infcx: fcx, span, body, replaced_with_error: None } } - fn report_error(&self, p: impl Into>) { - if !self.tcx.sess.has_errors().is_some() { - self.infcx + fn report_error(&self, p: impl Into>) -> ErrorGuaranteed { + match self.tcx.sess.has_errors() { + Some(e) => e, + None => self + .infcx .err_ctxt() .emit_inference_failure_err( Some(self.body.id()), @@ -732,7 +730,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { E0282, false, ) - .emit(); + .emit(), } } } @@ -773,9 +771,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); - self.report_error(t); - self.replaced_with_error = true; - self.tcx().ty_error() + let e = self.report_error(t); + self.replaced_with_error = Some(e); + self.tcx().ty_error_with_guaranteed(e) } } } @@ -790,9 +788,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { Ok(ct) => self.tcx.erase_regions(ct), Err(_) => { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); - self.report_error(ct); - self.replaced_with_error = true; - self.tcx().const_error(ct.ty()) + let e = self.report_error(ct); + self.replaced_with_error = Some(e); + self.tcx().const_error_with_guaranteed(ct.ty(), e) } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index fd3b3e4d59fa6..b9ed6b28c220d 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -34,7 +34,7 @@ pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid}; use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use std::cell::{Cell, RefCell}; use std::fmt; @@ -1208,7 +1208,8 @@ impl<'tcx> InferCtxt<'tcx> { /// reporting errors that often occur as a result of earlier /// errors, but where it's hard to be 100% sure (e.g., unresolved /// inference variables, regionck errors). - pub fn is_tainted_by_errors(&self) -> bool { + #[must_use = "this method does not have any side effects"] + pub fn tainted_by_errors(&self) -> Option { debug!( "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ tainted_by_errors={})", @@ -1217,19 +1218,25 @@ impl<'tcx> InferCtxt<'tcx> { self.tainted_by_errors.get().is_some() ); + if let Some(e) = self.tainted_by_errors.get() { + return Some(e); + } + if self.tcx.sess.err_count() > self.err_count_on_creation { - return true; // errors reported since this infcx was made + // errors reported since this infcx was made + let e = self.tcx.sess.has_errors().unwrap(); + self.set_tainted_by_errors(e); + return Some(e); } - self.tainted_by_errors.get().is_some() + + None } /// Set the "tainted by errors" flag to true. We call this when we /// observe an error from a prior pass. - pub fn set_tainted_by_errors(&self) { - debug!("set_tainted_by_errors()"); - self.tainted_by_errors.set(Some( - self.tcx.sess.delay_span_bug(DUMMY_SP, "`InferCtxt` incorrectly tainted by errors"), - )); + pub fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { + debug!("set_tainted_by_errors(ErrorGuaranteed)"); + self.tainted_by_errors.set(Some(e)); } pub fn skip_region_resolution(&self) { @@ -1270,7 +1277,7 @@ impl<'tcx> InferCtxt<'tcx> { let mut inner = self.inner.borrow_mut(); let inner = &mut *inner; assert!( - self.is_tainted_by_errors() || inner.region_obligations.is_empty(), + self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(), "region_obligations not empty: {:#?}", inner.region_obligations ); @@ -1707,7 +1714,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) { let errors = self.resolve_regions(outlives_env); - if !self.is_tainted_by_errors() { + if let None = self.tainted_by_errors() { // As a heuristic, just skip reporting region errors // altogether if other errors have been reported while // this infcx was in use. This is totally hokey but diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 600f94f095eac..167a82d4499a1 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -556,8 +556,9 @@ where self.ambient_variance_info = self.ambient_variance_info.xform(info); debug!(?self.ambient_variance); - - let r = self.relate(a, b)?; + // In a bivariant context this always succeeds. + let r = + if self.ambient_variance == ty::Variance::Bivariant { a } else { self.relate(a, b)? }; self.ambient_variance = old_ambient_variance; diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 8c8445a4d9eb8..bd3c5780b891b 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -116,9 +116,9 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { Ok(a) } - (&ty::Error(_), _) | (_, &ty::Error(_)) => { - infcx.set_tainted_by_errors(); - Ok(self.tcx().ty_error()) + (&ty::Error(e), _) | (_, &ty::Error(e)) => { + infcx.set_tainted_by_errors(e); + Ok(self.tcx().ty_error_with_guaranteed(e)) } (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 50f9cb0b56f6d..cdf279313a672 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -582,7 +582,7 @@ trait UnusedDelimLint { let sm = cx.sess().source_map(); let lo_replace = if keep_space.0 && - let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(" ") { + let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') { " ".to_string() } else { "".to_string() @@ -590,7 +590,7 @@ trait UnusedDelimLint { let hi_replace = if keep_space.1 && - let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(" ") { + let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(' ') { " ".to_string() } else { "".to_string() diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index ba06f61299f37..dff088b9bdfa6 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -830,5 +830,5 @@ pub(super) fn should_generate_set_arg(field: &Field) -> bool { } pub(super) fn is_doc_comment(attr: &Attribute) -> bool { - attr.path.segments.last().unwrap().ident.to_string() == "doc" + attr.path.segments.last().unwrap().ident == "doc" } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 48e803597b02e..93d6850560d7c 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2194,11 +2194,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { define_scoped_cx!(self); - let possible_names = - ('a'..='z').rev().map(|s| Symbol::intern(&format!("'{s}"))).collect::>(); + let possible_names = ('a'..='z').rev().map(|s| Symbol::intern(&format!("'{s}"))); let mut available_names = possible_names - .into_iter() .filter(|name| !self.used_region_names.contains(&name)) .collect::>(); debug!(?available_names); diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index db4b0a3deda9d..cc69a1bb02db1 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -899,7 +899,7 @@ fn debug_with_context_rec( let info_elem = map.places[child].proj_elem.unwrap(); let child_place_str = match info_elem { TrackElem::Field(field) => { - if place_str.starts_with("*") { + if place_str.starts_with('*') { format!("({}).{}", place_str, field.index()) } else { format!("{}.{}", place_str, field.index()) diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 780b91d9215d5..d7dd5fc852845 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1,7 +1,6 @@ //! Inlining pass for MIR functions use crate::deref_separator::deref_finder; use rustc_attr::InlineAttr; -use rustc_const_eval::transform::validate::equal_up_to_regions; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -14,7 +13,8 @@ use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; -use super::simplify::{remove_dead_blocks, CfgSimplifier}; +use crate::simplify::{remove_dead_blocks, CfgSimplifier}; +use crate::util; use crate::MirPass; use std::iter; use std::ops::{Range, RangeFrom}; @@ -180,7 +180,7 @@ impl<'tcx> Inliner<'tcx> { let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty; let output_type = callee_body.return_ty(); - if !equal_up_to_regions(self.tcx, self.param_env, output_type, destination_ty) { + if !util::is_subtype(self.tcx, self.param_env, output_type, destination_ty) { trace!(?output_type, ?destination_ty); return Err("failed to normalize return type"); } @@ -200,7 +200,7 @@ impl<'tcx> Inliner<'tcx> { arg_tuple_tys.iter().zip(callee_body.args_iter().skip(skipped_args)) { let input_type = callee_body.local_decls[input].ty; - if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) { + if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) { trace!(?arg_ty, ?input_type); return Err("failed to normalize tuple argument type"); } @@ -209,7 +209,7 @@ impl<'tcx> Inliner<'tcx> { for (arg, input) in args.iter().zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; let arg_ty = arg.ty(&caller_body.local_decls, self.tcx); - if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) { + if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) { trace!(?arg_ty, ?input_type); return Err("failed to normalize argument type"); } @@ -847,7 +847,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { let parent = Place { local, projection: self.tcx.intern_place_elems(proj_base) }; let parent_ty = parent.ty(&self.callee_body.local_decls, self.tcx); let check_equal = |this: &mut Self, f_ty| { - if !equal_up_to_regions(this.tcx, this.param_env, ty, f_ty) { + if !util::is_equal_up_to_subtyping(this.tcx, this.param_env, ty, f_ty) { trace!(?ty, ?f_ty); this.validation = Err("failed to normalize projection type"); return; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 350b270cc3dfe..2558ac801addd 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1660,14 +1660,14 @@ impl<'a> Parser<'a> { let left = begin_par_sp; let right = self.prev_token.span; let left_snippet = if let Ok(snip) = sm.span_to_prev_source(left) && - !snip.ends_with(" ") { + !snip.ends_with(' ') { " ".to_string() } else { "".to_string() }; let right_snippet = if let Ok(snip) = sm.span_to_next_source(right) && - !snip.starts_with(" ") { + !snip.starts_with(' ') { " ".to_string() } else { "".to_string() diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 6b8cd0713732d..acb9bd8e78a4a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -353,7 +353,7 @@ impl CheckAttrVisitor<'_> { attr.span, OnlyHasEffectOn { attr_name: attr.name_or_empty(), - target_name: allowed_target.name().replace(" ", "_"), + target_name: allowed_target.name().replace(' ', "_"), }, ); } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index d4722234a8f1e..5d0224c35f364 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -772,7 +772,7 @@ impl<'tcx> DeadVisitor<'tcx> { self.tcx.emit_spanned_lint( lint, tcx.hir().local_def_id_to_hir_id(first_id), - MultiSpan::from_spans(spans.clone()), + MultiSpan::from_spans(spans), diag, ); } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 103521983578b..d602acec53e32 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -562,7 +562,10 @@ impl Session { if self.err_count() == old_count { Ok(result) } else { - Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()) + Err(self.delay_span_bug( + rustc_span::DUMMY_SP, + "`self.err_count()` changed but an error was not emitted", + )) } } #[allow(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index c5a6f9893b6f9..0c559ec04a413 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -3,6 +3,7 @@ use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout}; use crate::spec::{self, HasTargetSpec}; use rustc_span::Symbol; use std::fmt; +use std::str::FromStr; mod aarch64; mod amdgpu; @@ -737,6 +738,33 @@ impl<'a, Ty> FnAbi<'a, Ty> { } } +impl FromStr for Conv { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "C" => Ok(Conv::C), + "Rust" => Ok(Conv::Rust), + "RustCold" => Ok(Conv::Rust), + "ArmAapcs" => Ok(Conv::ArmAapcs), + "CCmseNonSecureCall" => Ok(Conv::CCmseNonSecureCall), + "Msp430Intr" => Ok(Conv::Msp430Intr), + "PtxKernel" => Ok(Conv::PtxKernel), + "X86Fastcall" => Ok(Conv::X86Fastcall), + "X86Intr" => Ok(Conv::X86Intr), + "X86Stdcall" => Ok(Conv::X86Stdcall), + "X86ThisCall" => Ok(Conv::X86ThisCall), + "X86VectorCall" => Ok(Conv::X86VectorCall), + "X86_64SysV" => Ok(Conv::X86_64SysV), + "X86_64Win64" => Ok(Conv::X86_64Win64), + "AmdGpuKernel" => Ok(Conv::AmdGpuKernel), + "AvrInterrupt" => Ok(Conv::AvrInterrupt), + "AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt), + _ => Err(format!("'{}' is not a valid value for entry function call convetion.", s)), + } + } +} + // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] mod size_asserts { diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index b5d9263521228..75bb76a9de087 100644 --- a/compiler/rustc_target/src/json.rs +++ b/compiler/rustc_target/src/json.rs @@ -89,3 +89,28 @@ impl ToJson for Option { } } } + +impl ToJson for crate::abi::call::Conv { + fn to_json(&self) -> Json { + let s = match self { + Self::C => "C", + Self::Rust => "Rust", + Self::RustCold => "RustCold", + Self::ArmAapcs => "ArmAapcs", + Self::CCmseNonSecureCall => "CCmseNonSecureCall", + Self::Msp430Intr => "Msp430Intr", + Self::PtxKernel => "PtxKernel", + Self::X86Fastcall => "X86Fastcall", + Self::X86Intr => "X86Intr", + Self::X86Stdcall => "X86Stdcall", + Self::X86ThisCall => "X86ThisCall", + Self::X86VectorCall => "X86VectorCall", + Self::X86_64SysV => "X86_64SysV", + Self::X86_64Win64 => "X86_64Win64", + Self::AmdGpuKernel => "AmdGpuKernel", + Self::AvrInterrupt => "AvrInterrupt", + Self::AvrNonBlockingInterrupt => "AvrNonBlockingInterrupt", + }; + Json::String(s.to_owned()) + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 664592b02a124..6d936d2cb9ff0 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -34,6 +34,7 @@ //! the target's settings, though `target-feature` and `link-args` will *add* //! to the list specified by the target, rather than replace. +use crate::abi::call::Conv; use crate::abi::Endian; use crate::json::{Json, ToJson}; use crate::spec::abi::{lookup as lookup_abi, Abi}; @@ -1668,6 +1669,14 @@ pub struct TargetOptions { /// Whether the target supports stack canary checks. `true` by default, /// since this is most common among tier 1 and tier 2 targets. pub supports_stack_protector: bool, + + // The name of entry function. + // Default value is "main" + pub entry_name: StaticCow, + + // The ABI of entry function. + // Default value is `Conv::C`, i.e. C call convention + pub entry_abi: Conv, } /// Add arguments for the given flavor and also for its "twin" flavors @@ -1884,6 +1893,8 @@ impl Default for TargetOptions { c_enum_min_bits: 32, generate_arange_section: true, supports_stack_protector: true, + entry_name: "main".into(), + entry_abi: Conv::C, } } } @@ -2404,6 +2415,18 @@ impl Target { } } } ); + ($key_name:ident, Conv) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { + match Conv::from_str(s) { + Ok(c) => { + base.$key_name = c; + Some(Ok(())) + } + Err(e) => Some(Err(e)) + } + })).unwrap_or(Ok(())) + } ); } if let Some(j) = obj.remove("target-endian") { @@ -2523,6 +2546,8 @@ impl Target { key!(c_enum_min_bits, u64); key!(generate_arange_section, bool); key!(supports_stack_protector, bool); + key!(entry_name); + key!(entry_abi, Conv)?; if base.is_builtin { // This can cause unfortunate ICEs later down the line. @@ -2773,6 +2798,8 @@ impl ToJson for Target { target_option_val!(c_enum_min_bits); target_option_val!(generate_arange_section); target_option_val!(supports_stack_protector); + target_option_val!(entry_name); + target_option_val!(entry_abi); if let Some(abi) = self.default_adjusted_cabi { d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json()); diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index ae29c9f561791..f8346e515d70c 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -125,6 +125,21 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } + /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`. + pub fn sub>( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'tcx>> { + self.infcx + .at(cause, param_env) + .sup(expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + + /// Checks whether `expected` is a supertype of `actual`: `expected :> actual`. pub fn sup>( &self, cause: &ObligationCause<'tcx>, @@ -132,13 +147,10 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { expected: T, actual: T, ) -> Result<(), TypeError<'tcx>> { - match self.infcx.at(cause, param_env).sup(expected, actual) { - Ok(InferOk { obligations, value: () }) => { - self.register_obligations(obligations); - Ok(()) - } - Err(e) => Err(e), - } + self.infcx + .at(cause, param_env) + .sup(expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } pub fn select_where_possible(&self) -> Vec> { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f087afa20baca..ad0785d3817e1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -532,9 +532,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { root_obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>, ) { - self.set_tainted_by_errors(); let tcx = self.tcx; let mut span = obligation.cause.span; + // FIXME: statically guarantee this by tainting after the diagnostic is emitted + self.set_tainted_by_errors( + tcx.sess.delay_span_bug(span, "`report_selection_error` did not emit an error"), + ); let mut err = match *error { SelectionError::Unimplemented => { @@ -2060,7 +2063,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // check upstream for type errors and don't add the obligations to // begin with in those cases. if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { - if !self.is_tainted_by_errors() { + if let None = self.tainted_by_errors() { self.emit_inference_failure_err( body_id, span, @@ -2115,16 +2118,16 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if impls.len() > 1 && impls.len() < 5 && has_non_region_infer { self.annotate_source_of_ambiguity(&mut err, &impls, predicate); } else { - if self.is_tainted_by_errors() { - err.delay_as_bug(); + if self.tainted_by_errors().is_some() { + err.cancel(); return; } err.note(&format!("cannot satisfy `{}`", predicate)); } } _ => { - if self.is_tainted_by_errors() { - err.delay_as_bug(); + if self.tainted_by_errors().is_some() { + err.cancel(); return; } err.note(&format!("cannot satisfy `{}`", predicate)); @@ -2226,7 +2229,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ] = path.segments && data.trait_ref.def_id == *trait_id && self.tcx.trait_of_item(*item_id) == Some(*trait_id) - && !self.is_tainted_by_errors() + && let None = self.tainted_by_errors() { let (verb, noun) = match self.tcx.associated_item(item_id).kind { ty::AssocKind::Const => ("refer to the", "constant"), @@ -2295,7 +2298,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // with error messages. if arg.references_error() || self.tcx.sess.has_errors().is_some() - || self.is_tainted_by_errors() + || self.tainted_by_errors().is_some() { return; } @@ -2306,7 +2309,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::PredicateKind::Subtype(data) => { if data.references_error() || self.tcx.sess.has_errors().is_some() - || self.is_tainted_by_errors() + || self.tainted_by_errors().is_some() { // no need to overload user in such cases return; @@ -2317,7 +2320,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282, true) } ty::PredicateKind::Projection(data) => { - if predicate.references_error() || self.is_tainted_by_errors() { + if predicate.references_error() || self.tainted_by_errors().is_some() { return; } let subst = data @@ -2351,7 +2354,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ty::PredicateKind::ConstEvaluatable(data) => { - if predicate.references_error() || self.is_tainted_by_errors() { + if predicate.references_error() || self.tainted_by_errors().is_some() { return; } let subst = data.walk().find(|g| g.is_non_region_infer()); @@ -2378,7 +2381,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } _ => { - if self.tcx.sess.has_errors().is_some() || self.is_tainted_by_errors() { + if self.tcx.sess.has_errors().is_some() || self.tainted_by_errors().is_some() { return; } let mut err = struct_span_err!( @@ -2422,7 +2425,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { post.sort(); post.dedup(); - if self.is_tainted_by_errors() + if self.tainted_by_errors().is_some() && (crate_names.len() == 1 && spans.len() == 0 && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str()) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c369c5de52bb1..b05942353a343 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -33,7 +33,7 @@ use crate::traits::ProjectionCacheKey; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{Diagnostic, ErrorGuaranteed}; +use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::LateBoundRegionConversionTime; @@ -1089,10 +1089,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if !self.infcx.tcx.recursion_limit().value_within_limit(depth) { match self.query_mode { TraitQueryMode::Standard => { - if self.infcx.is_tainted_by_errors() { - return Err(OverflowError::Error( - ErrorGuaranteed::unchecked_claim_error_was_emitted(), - )); + if let Some(e) = self.infcx.tainted_by_errors() { + return Err(OverflowError::Error(e)); } self.infcx.err_ctxt().report_overflow_error(error_obligation, true); } diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 7844be5f783a9..b355d94ce4976 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -4,6 +4,10 @@ use crate::ops::Deref; /// A value which is initialized on the first access. /// +/// For a thread-safe version of this struct, see [`std::sync::LazyLock`]. +/// +/// [`std::sync::LazyLock`]: ../../std/sync/struct.LazyLock.html +/// /// # Examples /// /// ``` diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 3c39394dd8c8e..8c01643c7ac17 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -4,8 +4,14 @@ use crate::mem; /// A cell which can be written to only once. /// -/// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value. -/// Unlike `Cell`, a `OnceCell` doesn't require copying or replacing the value to access it. +/// Unlike [`RefCell`], a `OnceCell` only provides shared `&T` references to its value. +/// Unlike [`Cell`], a `OnceCell` doesn't require copying or replacing the value to access it. +/// +/// For a thread-safe version of this struct, see [`std::sync::OnceLock`]. +/// +/// [`RefCell`]: crate::cell::RefCell +/// [`Cell`]: crate::cell::Cell +/// [`std::sync::OnceLock`]: ../../std/sync/struct.OnceLock.html /// /// # Examples /// diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 4127c4056f24e..4e30076246314 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -880,7 +880,9 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asinh(self) -> f32 { - (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self) + let ax = self.abs(); + let ix = 1.0 / ax; + (ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self) } /// Inverse hyperbolic cosine function. @@ -900,7 +902,11 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acosh(self) -> f32 { - if self < 1.0 { Self::NAN } else { (self + ((self * self) - 1.0).sqrt()).ln() } + if self < 1.0 { + Self::NAN + } else { + (self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln() + } } /// Inverse hyperbolic tangent function. diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs index 4ec16c84aa916..6ee295de6163f 100644 --- a/library/std/src/f32/tests.rs +++ b/library/std/src/f32/tests.rs @@ -587,6 +587,11 @@ fn test_asinh() { assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); // regression test for the catastrophic cancellation fixed in 72486 assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f32, 60.0f32.sinh().asinh()); + // mul needed for approximate comparison to be meaningful + assert_approx_eq!(1.0f32, 1e-15f32.sinh().asinh() * 1e15f32); } #[test] @@ -602,6 +607,9 @@ fn test_acosh() { assert!(nan.acosh().is_nan()); assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f32, 60.0f32.cosh().acosh()); } #[test] diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index cc64258da60d1..ec67fdad4f726 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -882,7 +882,9 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asinh(self) -> f64 { - (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self) + let ax = self.abs(); + let ix = 1.0 / ax; + (ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self) } /// Inverse hyperbolic cosine function. @@ -902,7 +904,11 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acosh(self) -> f64 { - if self < 1.0 { Self::NAN } else { (self + ((self * self) - 1.0).sqrt()).ln() } + if self < 1.0 { + Self::NAN + } else { + (self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln() + } } /// Inverse hyperbolic tangent function. diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs index 12baa68f49b76..5b039d445ce14 100644 --- a/library/std/src/f64/tests.rs +++ b/library/std/src/f64/tests.rs @@ -575,6 +575,11 @@ fn test_asinh() { assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); // regression test for the catastrophic cancellation fixed in 72486 assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f64, 60.0f64.sinh().asinh()); + // mul needed for approximate comparison to be meaningful + assert_approx_eq!(1.0f64, 1e-15f64.sinh().asinh() * 1e15f64); } #[test] @@ -590,6 +595,9 @@ fn test_acosh() { assert!(nan.acosh().is_nan()); assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); + + // test for low accuracy from issue 104548 + assert_approx_eq!(60.0f64, 60.0f64.cosh().acosh()); } #[test] diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 535cc1c42fcfd..c8d3289ca4a06 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -6,7 +6,9 @@ use crate::sync::OnceLock; /// A value which is initialized on the first access. /// -/// This type is a thread-safe `Lazy`, and can be used in statics. +/// This type is a thread-safe [`LazyCell`], and can be used in statics. +/// +/// [`LazyCell`]: crate::cell::LazyCell /// /// # Examples /// diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 37413ec62a717..16d1fd2a576b9 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -7,7 +7,9 @@ use crate::sync::Once; /// A synchronization primitive which can be written to only once. /// -/// This type is a thread-safe `OnceCell`. +/// This type is a thread-safe [`OnceCell`], and can be used in statics. +/// +/// [`OnceCell`]: crate::cell::OnceCell /// /// # Examples /// @@ -33,7 +35,7 @@ use crate::sync::Once; #[unstable(feature = "once_cell", issue = "74465")] pub struct OnceLock { once: Once, - // Whether or not the value is initialized is tracked by `state_and_queue`. + // Whether or not the value is initialized is tracked by `once.is_completed()`. value: UnsafeCell>, /// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl. /// diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 789dd398be50d..e0cdb86d9d1dc 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -418,7 +418,7 @@ impl Options { ) { Ok(p) => p, Err(e) => { - diag.struct_err(&e.to_string()).emit(); + diag.struct_err(e).emit(); return Err(1); } }; @@ -561,7 +561,7 @@ impl Options { ) { Ok(p) => p, Err(e) => { - diag.struct_err(&e.to_string()).emit(); + diag.struct_err(e).emit(); return Err(1); } }; diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index b4d4150cddbb8..1f87f95563ad5 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -58,7 +58,7 @@ pub(crate) fn suffix_path(filename: &str, suffix: &str) -> PathBuf { } pub(crate) fn static_filename(filename: &str, contents: &[u8]) -> PathBuf { - let filename = filename.rsplit("/").next().unwrap(); + let filename = filename.rsplit('/').next().unwrap(); suffix_path(filename, &static_suffix(contents)) } diff --git a/src/test/ui/coherence/issue-100191-2.rs b/src/test/ui/coherence/issue-100191-2.rs deleted file mode 100644 index 1c8316f87fa07..0000000000000 --- a/src/test/ui/coherence/issue-100191-2.rs +++ /dev/null @@ -1,12 +0,0 @@ -//~ ERROR overflow evaluating the requirement `T: Trait<_>` - -#![feature(specialization, with_negative_coherence)] -#![allow(incomplete_features)] - -pub trait Trait {} - -default impl Trait for U {} - -impl Trait<::Item> for T {} - -fn main() {} diff --git a/src/test/ui/coherence/issue-100191.rs b/src/test/ui/coherence/issue-100191.rs deleted file mode 100644 index e8597fde54d3b..0000000000000 --- a/src/test/ui/coherence/issue-100191.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![crate_type = "lib"] -#![feature(specialization, with_negative_coherence)] -#![allow(incomplete_features)] - -trait X {} -trait Y: X {} -trait Z { - type Assoc: Y; -} -struct A(T); - -impl Y for T where T: X {} -impl Z for A { - type Assoc = T; -} - -// this impl is invalid, but causes an ICE anyway -impl From< as Z>::Assoc> for T {} -//~^ ERROR type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) - -fn main() {} diff --git a/src/test/ui/issues/issue-52262.rs b/src/test/ui/issues/issue-52262.rs index 2195b89555791..547643f0d6e20 100644 --- a/src/test/ui/issues/issue-52262.rs +++ b/src/test/ui/issues/issue-52262.rs @@ -1,4 +1,3 @@ -// compile-flags:-Ztreat-err-as-bug=5 #[derive(Debug)] enum MyError { NotFound { key: Vec }, diff --git a/src/test/ui/issues/issue-52262.stderr b/src/test/ui/issues/issue-52262.stderr index c0bde4b2321f1..ef41f078b8037 100644 --- a/src/test/ui/issues/issue-52262.stderr +++ b/src/test/ui/issues/issue-52262.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `*key` which is behind a shared reference - --> $DIR/issue-52262.rs:16:35 + --> $DIR/issue-52262.rs:15:35 | LL | String::from_utf8(*key).unwrap() | ^^^^ move occurs because `*key` has type `Vec`, which does not implement the `Copy` trait diff --git a/src/test/ui/mir/important-higher-ranked-regions.rs b/src/test/ui/mir/important-higher-ranked-regions.rs new file mode 100644 index 0000000000000..cadfb3b66f297 --- /dev/null +++ b/src/test/ui/mir/important-higher-ranked-regions.rs @@ -0,0 +1,26 @@ +// check-pass +// compile-flags: -Zvalidate-mir + +// This test checks that bivariant parameters are handled correctly +// in the mir. +#![allow(coherence_leak_check)] +trait Trait { + type Assoc; +} + +struct Foo(T) +where + T: Trait; + +impl Trait for for<'a> fn(&'a ()) { + type Assoc = u32; +} +impl Trait for fn(&'static ()) { + type Assoc = String; +} + +fn foo(x: Foo fn(&'a ()), u32>) -> Foo { + x +} + +fn main() {} diff --git a/src/test/ui/specialization/issue-43037.stderr b/src/test/ui/specialization/issue-43037.current.stderr similarity index 94% rename from src/test/ui/specialization/issue-43037.stderr rename to src/test/ui/specialization/issue-43037.current.stderr index 4249cd8947716..26db9d7c99749 100644 --- a/src/test/ui/specialization/issue-43037.stderr +++ b/src/test/ui/specialization/issue-43037.current.stderr @@ -1,5 +1,5 @@ error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) - --> $DIR/issue-43037.rs:17:6 + --> $DIR/issue-43037.rs:19:6 | LL | impl From< as Z>::Assoc> for T {} | ^ type parameter `T` must be used as the type parameter for some local type diff --git a/src/test/ui/coherence/issue-100191.stderr b/src/test/ui/specialization/issue-43037.negative.stderr similarity index 94% rename from src/test/ui/coherence/issue-100191.stderr rename to src/test/ui/specialization/issue-43037.negative.stderr index 1adb0f1e4fa7b..26db9d7c99749 100644 --- a/src/test/ui/coherence/issue-100191.stderr +++ b/src/test/ui/specialization/issue-43037.negative.stderr @@ -1,5 +1,5 @@ error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) - --> $DIR/issue-100191.rs:18:6 + --> $DIR/issue-43037.rs:19:6 | LL | impl From< as Z>::Assoc> for T {} | ^ type parameter `T` must be used as the type parameter for some local type diff --git a/src/test/ui/specialization/issue-43037.rs b/src/test/ui/specialization/issue-43037.rs index c49119f9c095b..a1e3f998b2370 100644 --- a/src/test/ui/specialization/issue-43037.rs +++ b/src/test/ui/specialization/issue-43037.rs @@ -1,4 +1,6 @@ +// revisions: current negative #![feature(specialization)] +#![cfg_attr(negative, feature(with_negative_coherence))] #![allow(incomplete_features)] trait X {} diff --git a/src/test/ui/specialization/issue-45814.stderr b/src/test/ui/specialization/issue-45814.current.stderr similarity index 94% rename from src/test/ui/specialization/issue-45814.stderr rename to src/test/ui/specialization/issue-45814.current.stderr index 419345addc2fc..5013559b80ea9 100644 --- a/src/test/ui/specialization/issue-45814.stderr +++ b/src/test/ui/specialization/issue-45814.current.stderr @@ -2,7 +2,7 @@ error[E0275]: overflow evaluating the requirement `T: Trait<_>` | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_45814`) note: required for `T` to implement `Trait<_>` - --> $DIR/issue-45814.rs:8:20 + --> $DIR/issue-45814.rs:9:20 | LL | default impl Trait for U {} | ^^^^^^^^ ^ diff --git a/src/test/ui/coherence/issue-100191-2.stderr b/src/test/ui/specialization/issue-45814.negative.stderr similarity index 81% rename from src/test/ui/coherence/issue-100191-2.stderr rename to src/test/ui/specialization/issue-45814.negative.stderr index d50c220bcfd48..5013559b80ea9 100644 --- a/src/test/ui/coherence/issue-100191-2.stderr +++ b/src/test/ui/specialization/issue-45814.negative.stderr @@ -1,8 +1,8 @@ error[E0275]: overflow evaluating the requirement `T: Trait<_>` | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_100191_2`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_45814`) note: required for `T` to implement `Trait<_>` - --> $DIR/issue-100191-2.rs:8:20 + --> $DIR/issue-45814.rs:9:20 | LL | default impl Trait for U {} | ^^^^^^^^ ^ diff --git a/src/test/ui/specialization/issue-45814.rs b/src/test/ui/specialization/issue-45814.rs index 8ee5d3e2e58da..fce236390c2b0 100644 --- a/src/test/ui/specialization/issue-45814.rs +++ b/src/test/ui/specialization/issue-45814.rs @@ -1,6 +1,7 @@ //~ ERROR overflow evaluating the requirement `T: Trait<_>` - +// revisions: current negative #![feature(specialization)] +#![cfg_attr(negative, feature(with_negative_coherence))] #![allow(incomplete_features)] pub trait Trait {} diff --git a/src/test/ui/suggestions/issue-102354.stderr b/src/test/ui/suggestions/issue-102354.stderr index b17c4dc5dfb50..08d4b99559031 100644 --- a/src/test/ui/suggestions/issue-102354.stderr +++ b/src/test/ui/suggestions/issue-102354.stderr @@ -2,7 +2,10 @@ error[E0599]: no method named `func` found for type `i32` in the current scope --> $DIR/issue-102354.rs:9:7 | LL | x.func(); - | ^^^^ this is an associated function, not a method + | --^^^^-- + | | | + | | this is an associated function, not a method + | help: use associated function syntax instead: `i32::func()` | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `Trait` @@ -10,14 +13,6 @@ note: the candidate is defined in the trait `Trait` | LL | fn func() {} | ^^^^^^^^^ -help: use associated function syntax instead - | -LL | i32::func(); - | ~~~~~~~~~~~ -help: disambiguate the associated function for the candidate - | -LL | ::func(x); - | ~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/tools/miropt-test-tools/src/lib.rs b/src/tools/miropt-test-tools/src/lib.rs index 96819d3547b29..cfba7d583b138 100644 --- a/src/tools/miropt-test-tools/src/lib.rs +++ b/src/tools/miropt-test-tools/src/lib.rs @@ -11,7 +11,7 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec< let test_file_contents = fs::read_to_string(&testfile).unwrap(); let test_dir = testfile.parent().unwrap(); - let test_crate = testfile.file_stem().unwrap().to_str().unwrap().replace("-", "_"); + let test_crate = testfile.file_stem().unwrap().to_str().unwrap().replace('-', "_"); let bit_width = if test_file_contents.lines().any(|l| l == "// EMIT_MIR_FOR_EACH_BIT_WIDTH") { format!(".{}bit", bit_width)