diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 23aeb1e06463c..ee0cef350b42f 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -22,7 +22,7 @@ use rustc_target::asm::*; use crate::builder::Builder; use crate::callee::get_fn; use crate::context::CodegenCx; -use crate::errors::{NulBytesInAsm, UnwindingInlineAsm}; +use crate::diagnostics::{NulBytesInAsm, UnwindingInlineAsm}; use crate::type_of::LayoutGccExt; // Rust asm! and GCC Extended Asm semantics differ substantially. diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 7166ad8b1f17f..98f9abdb05c4c 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -35,7 +35,7 @@ use rustc_log::tracing::info; use tempfile::{TempDir, tempdir}; use crate::back::write::{codegen, save_temp_bitcode}; -use crate::errors::LtoBitcodeFromRlib; +use crate::diagnostics::LtoBitcodeFromRlib; use crate::{GccCodegenBackend, GccContext, LtoMode, to_gcc_opt_level}; struct LtoData { diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 8fd38a2efd600..cf5514412f745 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -12,7 +12,7 @@ use rustc_session::config::OutputType; use rustc_target::spec::SplitDebuginfo; use crate::base::add_pic_option; -use crate::errors::CopyBitcode; +use crate::diagnostics::CopyBitcode; use crate::{GccContext, LtoMode}; pub(crate) fn codegen( diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 7671d2e026b03..a407362638f10 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -36,7 +36,7 @@ use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; use crate::abi::FnAbiGccExt; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; -use crate::errors; +use crate::diagnostics; use crate::intrinsic::llvm; use crate::type_of::LayoutGccExt; @@ -1803,7 +1803,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _instance: Option>, ) { // FIXME: implement support for explicit tail calls like rustc_codegen_llvm. - self.tcx.dcx().emit_fatal(errors::ExplicitTailCallsUnsupported); + self.tcx.dcx().emit_fatal(diagnostics::ExplicitTailCallsUnsupported); } fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/diagnostics.rs similarity index 100% rename from compiler/rustc_codegen_gcc/src/errors.rs rename to compiler/rustc_codegen_gcc/src/diagnostics.rs diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 4cc4a2d258d14..55c721a9706a6 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -59,7 +59,7 @@ mod context; mod coverageinfo; mod debuginfo; mod declare; -mod errors; +mod diagnostics; mod gcc_util; mod int; mod intrinsic; diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 1f00e47a89927..a4176a8feb0f9 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -16,7 +16,7 @@ use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, Stack use smallvec::SmallVec; use crate::context::SimpleCx; -use crate::errors::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte}; +use crate::diagnostics::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte}; use crate::llvm::AttributePlace::Function; use crate::llvm::{ self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects, Value, diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 70d48def59e91..4883eb1087be3 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -28,7 +28,7 @@ use crate::back::write::{ self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, codegen, save_temp_bitcode, }; -use crate::errors::{LlvmError, LtoBitcodeFromRlib}; +use crate::diagnostics::{LlvmError, LtoBitcodeFromRlib}; use crate::llvm::{self, build_string}; use crate::{LlvmCodegenBackend, ModuleLlvm}; diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 65cf4cad24bd6..350d4ce9ee331 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; use rustc_data_structures::small_c_str::SmallCStr; -use crate::errors::LlvmError; +use crate::diagnostics::LlvmError; use crate::llvm; /// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions. diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 6a0f4fa6d54d2..94883a94f089a 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -34,7 +34,7 @@ use crate::back::profiling::{ use crate::builder::SBuilder; use crate::builder::gpu_offload::scalar_width; use crate::common::AsCCharPtr; -use crate::errors::{ +use crate::diagnostics::{ CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, ParseTargetMachineConfig, UnsupportedCompression, WithLlvmError, WriteBytecode, }; @@ -819,7 +819,7 @@ pub(crate) unsafe fn llvm_optimize( device_out_c.as_ptr(), ); if !ok || !device_out.exists() { - dcx.emit_err(crate::errors::OffloadBundleImagesFailed); + dcx.emit_err(crate::diagnostics::OffloadBundleImagesFailed); } } } @@ -837,15 +837,15 @@ pub(crate) unsafe fn llvm_optimize( { let device_pathbuf = PathBuf::from(device_path); if device_pathbuf.is_relative() { - dcx.emit_err(crate::errors::OffloadWithoutAbsPath); + dcx.emit_err(crate::diagnostics::OffloadWithoutAbsPath); } else if device_pathbuf .file_name() .and_then(|n| n.to_str()) .is_some_and(|n| n != "device.bin") { - dcx.emit_err(crate::errors::OffloadWrongFileName); + dcx.emit_err(crate::diagnostics::OffloadWrongFileName); } else if !device_pathbuf.exists() { - dcx.emit_err(crate::errors::OffloadNonexistingPath); + dcx.emit_err(crate::diagnostics::OffloadNonexistingPath); } let host_path = cgcx.output_filenames.path(OutputType::Object); let host_dir = host_path.parent().unwrap(); @@ -859,7 +859,7 @@ pub(crate) unsafe fn llvm_optimize( let ok = unsafe { llvm::LLVMRustOffloadEmbedBufferInModule(llmod2, device_bin_c.as_ptr()) }; if !ok { - dcx.emit_err(crate::errors::OffloadEmbedFailed); + dcx.emit_err(crate::diagnostics::OffloadEmbedFailed); } write_output_file( dcx, diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 55bb6f1abeb96..b8e2b0029167a 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -44,6 +44,7 @@ use crate::type_of::LayoutLlvmExt; pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow>> { pub llbuilder: &'ll mut llvm::Builder<'ll>, pub cx: &'a GenericCx<'ll, CX>, + pub span: rustc_span::Span, } pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SCx<'ll>>; @@ -94,7 +95,7 @@ impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { fn with_cx(scx: &'a GenericCx<'ll, CX>) -> Self { // Create a fresh builder from the simple context. let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.deref().borrow().llcx) }; - GenericBuilder { llbuilder, cx: scx } + GenericBuilder { llbuilder, cx: scx, span: rustc_span::DUMMY_SP } } pub(crate) fn append_block( @@ -304,7 +305,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMGetInsertBlock(self.llbuilder) } } - fn set_span(&mut self, _span: Span) {} + fn set_span(&mut self, span: rustc_span::Span) { + self.span = span; + } fn append_block(cx: &'a CodegenCx<'ll, 'tcx>, llfn: &'ll Value, name: &str) -> &'ll BasicBlock { unsafe { @@ -1564,6 +1567,51 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { pub(crate) fn llfn(&self) -> &'ll Value { unsafe { llvm::LLVMGetBasicBlockParent(self.llbb()) } } + + fn generate_ubsan_cfi_diag_data( + &mut self, + span: rustc_span::Span, + expected_ty: String, + check_kind: u8, + ) -> &'ll Value { + let cx = self.cx(); + let tcx = cx.tcx; + + let loc = tcx.sess.source_map().lookup_char_pos(span.lo()); + + let filename_str = format!("{}\0", loc.file.name.prefer_local_unconditionally()); + let filename_val = cx.const_bytes(filename_str.as_bytes()); + let filename_ptr = cx.static_addr_of_impl(filename_val, Align::ONE, None); + + // SourceLocation UBSan struct: { const char *filename, uint32_t line, uint32_t column } + let source_location = cx.const_struct( + &[ + filename_ptr, + cx.const_u32(loc.line as u32), + // UBSan columns are 1-based + cx.const_u32(loc.col.0 as u32 + 1), + ], + false, // packed = false + ); + + let ty_name = format!("{}\0", expected_ty); + let ty_name_val = cx.const_bytes(ty_name.as_bytes()); + + // TypeDescriptor UBSan struct: { uint16_t TypeKind, uint16_t TypeInfo, const char *TypeName } + let type_descriptor = + cx.const_struct(&[cx.const_i16(0xffffu16 as i16), cx.const_i16(0), ty_name_val], false); + + let type_descriptor_ptr = + cx.static_addr_of_impl(type_descriptor, Align::from_bytes(2).unwrap(), None); + + // CFICheckFailData UBSan struct: { uint8_t CheckKind, SourceLocation Loc, TypeDescriptor *Type } + let cfi_check_fail_data = cx + .const_struct(&[cx.const_u8(check_kind), source_location, type_descriptor_ptr], false); + let align = tcx.data_layout.aggregate_align; + + // Returns the final opaque pointer to the struct to be passed to __ubsan_handle_cfi_check_fail + cx.static_addr_of_mut(cfi_check_fail_data, align, Some("__ubsan_cfi_check_fail_data")) + } } impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { @@ -1983,8 +2031,64 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { if let Some(dbg_loc) = dbg_loc { self.set_dbg_loc(dbg_loc); } - self.abort(); - self.unreachable(); + + let is_diag = self.tcx.sess.opts.unstable_opts.sanitizer_cfi_diag.unwrap_or(false); + let is_recover = + self.tcx.sess.opts.unstable_opts.sanitizer_cfi_recover.unwrap_or(false); + + if is_diag || is_recover { + let fty = self.cx.type_func( + &[self.cx.type_ptr(), self.cx.type_isize(), self.cx.type_isize()], + self.cx.type_void(), + ); + let ubsan_handler = self.declare_cfn( + if is_recover { + "__ubsan_handle_cfi_check_fail" + } else { + "__ubsan_handle_cfi_check_fail_abort" + }, + llvm::UnnamedAddr::Global, + fty, + ); + + let mut expected_ty = String::from("fn("); + for (i, arg) in fn_abi.args.iter().enumerate() { + if i > 0 { + expected_ty.push_str(", "); + } + use std::fmt::Write; + write!(&mut expected_ty, "{}", arg.layout.ty).unwrap(); + } + expected_ty.push(')'); + if !fn_abi.ret.layout.ty.is_unit() { + use std::fmt::Write; + write!(&mut expected_ty, " -> {}", fn_abi.ret.layout.ty).unwrap(); + } + + // 4 for cfi-icall (indirect call) + let check_kind = 4; + let diag_data = + self.generate_ubsan_cfi_diag_data(self.span, expected_ty, check_kind); + + let function_address = self.ptrtoint(llfn, self.cx.type_isize()); + self.call( + fty, + None, + None, + ubsan_handler, + &[diag_data, function_address, self.const_usize(0)], + None, + None, + ); + if is_recover { + self.br(bb_pass); + } else { + self.unreachable(); + } + } else { + self.abort(); + self.unreachable(); + } self.switch_to_block(bb_pass); if let Some(dbg_loc) = dbg_loc { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 8f87acaf675a4..ee752373ceca4 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -21,7 +21,7 @@ use rustc_target::spec::Arch; use tracing::{debug, instrument, trace}; use crate::common::CodegenCx; -use crate::errors::SymbolAlreadyDefined; +use crate::diagnostics::SymbolAlreadyDefined; use crate::llvm::{self, Type, Value, const_ptr_auth}; use crate::type_of::LayoutLlvmExt; use crate::{base, debuginfo}; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 8f1910eaced13..89d9be451ebf4 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -238,7 +238,7 @@ pub(crate) unsafe fn create_module<'ll>( .expect("got a non-UTF8 data-layout from LLVM"); if target_data_layout != llvm_data_layout { - tcx.dcx().emit_err(crate::errors::MismatchedDataLayout { + tcx.dcx().emit_err(crate::diagnostics::MismatchedDataLayout { rustc_target: sess.opts.target_triple.to_string().as_str(), rustc_layout: target_data_layout.as_str(), llvm_target: sess.target.llvm_target.borrow(), diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs similarity index 100% rename from compiler/rustc_codegen_llvm/src/errors.rs rename to compiler/rustc_codegen_llvm/src/diagnostics.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index edf943c81a755..4ae85af897527 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -39,7 +39,7 @@ use crate::builder::gpu_offload::{ }; use crate::context::CodegenCx; use crate::declare::declare_raw_fn; -use crate::errors::{ +use crate::diagnostics::{ AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch, OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic, }; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 1dd460c409737..3ec0495956c4c 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -59,7 +59,7 @@ mod context; mod coverageinfo; mod debuginfo; mod declare; -mod errors; +mod diagnostics; mod intrinsic; mod llvm; mod llvm_util; @@ -233,10 +233,11 @@ impl CodegenBackend for LlvmCodegenBackend { match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { Ok(_) => {} Err(llvm::EnzymeLibraryError::NotFound { err }) => { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentMissing { err }); + sess.dcx().emit_fatal(crate::diagnostics::AutoDiffComponentMissing { err }); } Err(llvm::EnzymeLibraryError::LoadFailed { err }) => { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { err }); + sess.dcx() + .emit_fatal(crate::diagnostics::AutoDiffComponentUnavailable { err }); } } enable_autodiff_settings(&sess.opts.unstable_opts.autodiff); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 87d8676cd8018..9ad14925afb14 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -21,7 +21,7 @@ use rustc_target::spec::{ use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; -use crate::{errors, llvm}; +use crate::{diagnostics, llvm}; static INIT: Once = Once::new(); @@ -636,7 +636,8 @@ fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { // -Zfixed-x18 if sess.opts.unstable_opts.fixed_x18 { if sess.target.arch != Arch::AArch64 { - sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: sess.target.arch.desc() }); + sess.dcx() + .emit_fatal(diagnostics::FixedX18InvalidArch { arch: sess.target.arch.desc() }); } else { features.push("+reserve-x18".into()); } diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index b746bab643a34..19d43797a875d 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -19,7 +19,7 @@ use tracing::debug; use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::context::CodegenCx; -use crate::errors::SymbolAlreadyDefined; +use crate::diagnostics::SymbolAlreadyDefined; use crate::type_of::LayoutLlvmExt; use crate::{base, llvm}; diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 0a9af492b1f45..43d33d36704d3 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1600,6 +1600,12 @@ fn add_sanitizer_libraries( if sanitizer.contains(SanitizerSet::REALTIME) { link_sanitizer_runtime(sess, flavor, linker, "rtsan"); } + if sanitizer.contains(SanitizerSet::CFI) + && (sess.opts.unstable_opts.sanitizer_cfi_diag.unwrap_or(false) + || sess.opts.unstable_opts.sanitizer_cfi_recover.unwrap_or(false)) + { + link_sanitizer_runtime(sess, flavor, linker, "ubsan"); + } } fn link_sanitizer_runtime( diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 1db2321f7b249..9a4bc46f165c9 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -82,6 +82,8 @@ pub struct ModuleConfig { pub instrument_coverage: bool, pub sanitizer: SanitizerSet, + pub sanitizer_cfi_diag: Option, + pub sanitizer_cfi_recover: Option, pub sanitizer_recover: SanitizerSet, pub sanitizer_dataflow_abilist: Vec, pub sanitizer_memory_track_origins: usize, @@ -182,6 +184,8 @@ impl ModuleConfig { instrument_coverage: if_regular!(sess.instrument_coverage(), false), sanitizer: if_regular!(sess.sanitizers(), SanitizerSet::empty()), + sanitizer_cfi_diag: if_regular!(sess.opts.unstable_opts.sanitizer_cfi_diag, None), + sanitizer_cfi_recover: if_regular!(sess.opts.unstable_opts.sanitizer_cfi_recover, None), sanitizer_dataflow_abilist: if_regular!( sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(), Vec::new() diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 33ec40c5790db..cc48f418d03db 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -161,12 +161,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { location.val } - // va_end uses the fallback body (a no-op). - sym::va_start => { - bx.va_start(args[0].immediate()); - OperandValue::ZeroSized - } - sym::size_of_val => { let tp_ty = fn_args.type_at(0); let (_, meta) = args[0].val.pointer_parts(); diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index b9c0011d1a4ff..2d56f2f1542ab 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -16,6 +16,7 @@ use rustc_span::sym; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; +use crate::check::missing_items_must_implement_one_of_err; use crate::diagnostics; use crate::hir::def_id::{DefId, LocalDefId}; @@ -394,11 +395,12 @@ fn check_drop_xor_pin_drop<'tcx>( match (drop_span, pin_drop_span) { (None, None) => { if tcx.features().pin_ergonomics() { - return Err(tcx.dcx().emit_err(crate::diagnostics::MissingOneOfTraitItem { - span: tcx.def_span(drop_impl_did), - note: None, - missing_items_msg: "drop`, `pin_drop".to_string(), - })); + return Err(missing_items_must_implement_one_of_err( + tcx, + drop_impl_did, + [sym::drop, sym::pin_drop].into_iter(), + None, + )); } else { return Err(tcx .dcx() diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 26d289a0fc70c..1b2e496d6a23c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1436,19 +1436,13 @@ fn check_impl_items_against_trait<'tcx>( } if !missing_items.is_empty() { - let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id)); - missing_items_err(tcx, impl_id, &missing_items, full_impl_span); + missing_items_err(tcx, impl_id, &missing_items); } if let Some(missing_items) = must_implement_one_of { let attr_span = find_attr!(tcx, trait_ref.def_id, RustcMustImplementOneOf {attr_span, ..} => *attr_span); - - missing_items_must_implement_one_of_err( - tcx, - tcx.def_span(impl_id), - missing_items, - attr_span, - ); + let missing_items = missing_items.into_iter().map(|i| i.name); + missing_items_must_implement_one_of_err(tcx, impl_id, missing_items, attr_span); } } } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 9dd7bb8058afc..cb6bf2cc7d623 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -659,9 +659,7 @@ pub(crate) fn check_intrinsic_type( (0, 0, vec![va_list_ref_ty], va_list_ty) } - sym::va_start | sym::va_end => { - (0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit) - } + sym::va_end => (0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit), sym::va_arg => (1, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], param(0)), diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 451db9fd64aca..0d45703e17fbd 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -103,6 +103,9 @@ use tracing::debug; use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys; use self::region::region_scope_tree; +use crate::diagnostics::{ + MissingTraitItemLabel, MissingTraitItemSuggestion, MissingTraitItemSuggestionNone, +}; use crate::{check_c_variadic_abi, diagnostics}; /// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`] @@ -203,11 +206,30 @@ pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDef } } -fn missing_items_err( +fn impl_suggestion_span(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) -> Span { + let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_def_id)); + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span) + && snippet.ends_with("}") + { + // `Span` before impl block closing brace. + let hi = full_impl_span.hi() - BytePos(1); + // Point at the place right before the closing brace of the relevant `impl` to suggest + // adding the associated item at the end of its body. + full_impl_span.with_lo(hi).with_hi(hi) + } else { + full_impl_span.shrink_to_hi() + } +} + +fn missing_items_suggestions( tcx: TyCtxt<'_>, impl_def_id: LocalDefId, missing_items: &[ty::AssocItem], - full_impl_span: Span, +) -> ( + String, + Vec, + Vec, + Vec, ) { let missing_items = missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait()); @@ -218,17 +240,7 @@ fn missing_items_err( .collect::>() .join("`, `"); - let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span) - && snippet.ends_with("}") - { - // `Span` before impl block closing brace. - let hi = full_impl_span.hi() - BytePos(1); - // Point at the place right before the closing brace of the relevant `impl` to suggest - // adding the associated item at the end of its body. - full_impl_span.with_lo(hi).with_hi(hi) - } else { - full_impl_span.shrink_to_hi() - }; + let sugg_sp = impl_suggestion_span(tcx, impl_def_id); // Obtain the level of indentation ending in `sugg_sp`. let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new); @@ -259,6 +271,13 @@ fn missing_items_err( } } + (missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label) +} + +fn missing_items_err(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, missing_items: &[ty::AssocItem]) { + let (missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label) = + missing_items_suggestions(tcx, impl_def_id, missing_items); + tcx.dcx().emit_err(diagnostics::MissingTraitItem { span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(), missing_items_msg, @@ -270,18 +289,29 @@ fn missing_items_err( fn missing_items_must_implement_one_of_err( tcx: TyCtxt<'_>, - impl_span: Span, - missing_items: &[Ident], + impl_def_id: LocalDefId, + missing_items: impl Iterator, annotation_span: Option, -) { - let missing_items_msg = - missing_items.iter().map(Ident::to_string).collect::>().join("`, `"); +) -> ErrorGuaranteed { + // Look up the associated items so we can use them to emit better errors. + let trait_def_id = tcx.impl_trait_id(impl_def_id); + let assoc_items = tcx.associated_items(trait_def_id); + let missing_items = missing_items + .flat_map(|s| assoc_items.filter_by_name_unhygienic_and_kind(s, ty::AssocTag::Fn)) + .cloned() + .collect::>(); + + let (missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label) = + missing_items_suggestions(tcx, impl_def_id, &missing_items); tcx.dcx().emit_err(diagnostics::MissingOneOfTraitItem { - span: impl_span, + span: tcx.def_span(impl_def_id), note: annotation_span, missing_items_msg, - }); + missing_trait_item_label, + missing_trait_item, + missing_trait_item_none, + }) } fn default_body_is_unstable( diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index 0ea353cf14cee..eb0dcb3a346b2 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -966,6 +966,12 @@ pub(crate) struct MissingOneOfTraitItem { pub span: Span, #[note("required because of this annotation")] pub note: Option, + #[subdiagnostic] + pub missing_trait_item_label: Vec, + #[subdiagnostic] + pub missing_trait_item: Vec, + #[subdiagnostic] + pub missing_trait_item_none: Vec, pub missing_items_msg: String, } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index c5fb813274992..6f9b6a4f14ce9 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -614,7 +614,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - if let ty::FnDef(did, _) = *ty.kind() { + if let ty::FnDef(did, args) = *ty.kind() { let fn_sig = ty.fn_sig(tcx); if tcx.is_intrinsic(did, sym::transmute) { @@ -631,6 +631,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // be known if explicitly specified via turbofish). self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id)); } + if tcx.is_intrinsic(did, sym::offload) { + let args = args.skip_binder(); + let f = args.type_at(0); + let t = args.type_at(1); + let r = args.type_at(2); + // Defer offload checks to check generics later once types are fully inferred. + self.deferred_offload_checks.borrow_mut().push((f, t, r, expr.hir_id)); + } if !tcx.features().unsized_fn_params() { // We want to remove some Sized bounds from std functions, // but don't want to expose the removal to stable Rust. diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 430f4d828b91f..e009be599e36c 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -140,6 +140,109 @@ fn check_transmute<'tcx>( } } +fn check_offload<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + kernel_ty: Ty<'tcx>, + args_ty: Ty<'tcx>, + ret_ty: Ty<'tcx>, + hir_id: HirId, +) -> Result<(), ErrorGuaranteed> { + let span = tcx.hir_span(hir_id); + let ty::FnDef(kernel_def_id, kernel_args) = *kernel_ty.kind() else { + let err = tcx + .sess + .dcx() + .struct_span_err( + span, + format!("expected a function item for the offload kernel, found `{}`", kernel_ty), + ) + .emit(); + return Err(err); + }; + + let kernel_sig = + tcx.fn_sig(kernel_def_id).instantiate(tcx, kernel_args.skip_binder()).skip_norm_wip(); + let kernel_sig = tcx.instantiate_bound_regions_with_erased(kernel_sig); + + let ty::Tuple(tuple_fields) = *args_ty.kind() else { + let err = tcx + .sess + .dcx() + .struct_span_err( + span, + format!("expected a tuple for the offload arguments, found `{}`", args_ty), + ) + .emit(); + return Err(err); + }; + + if kernel_sig.inputs().len() != tuple_fields.len() { + let err = tcx + .sess + .dcx() + .struct_span_err( + span, + format!( + "offload kernel expects {} arguments, but {} arguments were provided", + kernel_sig.inputs().len(), + tuple_fields.len() + ), + ) + .emit(); + return Err(err); + } + + let normalize = |ty| { + if let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)) { + ty + } else { + Ty::new_error_with_message( + tcx, + span, + format!("tried to normalize non-wf type {ty:#?} in check_offload"), + ) + } + }; + + let mut result = Ok(()); + + for (i, (&input_ty, arg_ty)) in kernel_sig.inputs().iter().zip(tuple_fields.iter()).enumerate() + { + let norm_input_ty = normalize(input_ty); + let norm_arg_ty = normalize(arg_ty); + if norm_input_ty != norm_arg_ty { + let err = tcx + .sess + .dcx() + .struct_span_err( + span, + format!( + "type mismatch in offload kernel argument {}: expected `{}`, found `{}`", + i, norm_input_ty, norm_arg_ty + ), + ) + .emit(); + result = Err(err); + } + } + + let norm_kernel_ret = normalize(kernel_sig.output()); + let norm_offload_ret = normalize(ret_ty); + if norm_kernel_ret != norm_offload_ret { + let err = tcx.sess.dcx().struct_span_err( + span, + format!( + "offload kernel return type mismatch: kernel returns `{}`, but offload call expects `{}`", + norm_kernel_ret, norm_offload_ret + ) + ).emit(); + result = Err(err); + } + + result +} + pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) -> Result<(), ErrorGuaranteed> { assert!(!tcx.is_typeck_child(owner.to_def_id())); let typeck_results = tcx.typeck(owner); @@ -154,3 +257,18 @@ pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) -> Result<(), } result } + +pub(crate) fn check_offloads(tcx: TyCtxt<'_>, owner: LocalDefId) -> Result<(), ErrorGuaranteed> { + assert!(!tcx.is_typeck_child(owner.to_def_id())); + let typeck_results = tcx.typeck(owner); + if let Some(e) = typeck_results.tainted_by_errors { + return Err(e); + }; + + let typing_env = ty::TypingEnv::codegen(tcx, owner); + let mut result = Ok(()); + for &(kernel_ty, args_ty, ret_ty, hir_id) in &typeck_results.offloads_to_check { + result = result.and(check_offload(tcx, typing_env, kernel_ty, args_ty, ret_ty, hir_id)); + } + result +} diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index dce7f0bd67794..5c5bf77609ce2 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -721,6 +721,7 @@ pub fn provide(providers: &mut Providers) { typeck_root, used_trait_imports, check_transmutes: intrinsicck::check_transmutes, + check_offloads: intrinsicck::check_offloads, ..*providers }; } diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index e4dcead1f7954..a475d073f452d 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -57,6 +57,8 @@ pub(crate) struct TypeckRootCtxt<'tcx> { pub(super) deferred_transmute_checks: RefCell, Ty<'tcx>, HirId)>>, + pub(super) deferred_offload_checks: RefCell, Ty<'tcx>, Ty<'tcx>, HirId)>>, + pub(super) deferred_asm_checks: RefCell, HirId)>>, pub(super) deferred_repeat_expr_checks: @@ -97,6 +99,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { deferred_call_resolutions: RefCell::new(Default::default()), deferred_cast_checks: RefCell::new(Vec::new()), deferred_transmute_checks: RefCell::new(Vec::new()), + deferred_offload_checks: RefCell::new(Vec::new()), deferred_asm_checks: RefCell::new(Vec::new()), deferred_repeat_expr_checks: RefCell::new(Vec::new()), diverging_type_vars: RefCell::new(Default::default()), diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 4161975d88ea9..7b1f38f882747 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -76,6 +76,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_user_provided_sigs(); wbcx.visit_coroutine_interior(); wbcx.visit_transmutes(); + wbcx.visit_offloads(); wbcx.visit_offset_of_container_types(); wbcx.visit_potentially_region_dependent_goals(); @@ -544,6 +545,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + fn visit_offloads(&mut self) { + let tcx = self.tcx(); + let fcx_typeck_results = self.fcx.typeck_results.borrow(); + assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); + for &(kernel_ty, args_ty, ret_ty, hir_id) in + self.fcx.deferred_offload_checks.borrow().iter() + { + let span = tcx.hir_span(hir_id); + let kernel_ty = self.resolve(kernel_ty, &span); + let args_ty = self.resolve(args_ty, &span); + let ret_ty = self.resolve(ret_ty, &span); + self.typeck_results.offloads_to_check.push((kernel_ty, args_ty, ret_ty, hir_id)); + } + } + fn visit_opaque_types_next(&mut self) { let mut fcx_typeck_results = self.fcx.typeck_results.borrow_mut(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 20e2fc833c88d..b9ad57ac9d309 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1154,6 +1154,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { if not_typeck_child { tcx.ensure_ok().mir_borrowck(def_id); tcx.ensure_ok().check_transmutes(def_id); + tcx.ensure_ok().check_offloads(def_id); } tcx.ensure_ok().has_ffi_unwind_calls(def_id); tcx.ensure_ok().check_liveness(def_id); diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index d455abeaf23ac..28a35013b6516 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -1137,6 +1137,11 @@ rustc_queries! { desc { "check transmute calls inside `{}`", tcx.def_path_str(key) } } + /// Unsafety-check this `LocalDefId`. + query check_offloads(key: LocalDefId) -> Result<(), ErrorGuaranteed> { + desc { "check offload calls inside `{}`", tcx.def_path_str(key) } + } + /// Unsafety-check this `LocalDefId`. query check_unsafety(key: LocalDefId) { desc { "unsafety-checking `{}`", tcx.def_path_str(key) } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 6ea5a91672418..a0f38dcb50cb4 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -223,6 +223,9 @@ pub struct TypeckResults<'tcx> { /// computation. pub transmutes_to_check: Vec<(Ty<'tcx>, Ty<'tcx>, HirId)>, + /// Stores the types involved in calls to `offload` intrinsic. + pub offloads_to_check: Vec<(Ty<'tcx>, Ty<'tcx>, Ty<'tcx>, HirId)>, + /// Container types and field indices of `offset_of!` expressions offset_of_data: ItemLocalMap, VariantIdx, FieldIdx)>>, } @@ -256,6 +259,7 @@ impl<'tcx> TypeckResults<'tcx> { potentially_region_dependent_goals: Default::default(), closure_size_eval: Default::default(), transmutes_to_check: Default::default(), + offloads_to_check: Default::default(), offset_of_data: Default::default(), } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 4ce07ffe45ed7..ad00003af9482 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -41,7 +41,8 @@ use crate::ref_mut::CmCell; use crate::{ BindingKey, Decl, DeclData, DeclKind, DelayedVisResolutionError, ExternModule, ExternPreludeEntry, Finalize, IdentKey, LocalModule, Module, ModuleKind, ModuleOrUniformRoot, - ParentScope, PathResult, Res, Resolver, Segment, Used, VisResolutionError, diagnostics, + ParentScope, PathResult, Res, ResolutionTable, Resolver, Segment, Used, VisResolutionError, + diagnostics, }; impl<'ra, 'tcx> Resolver<'ra, 'tcx> { @@ -279,7 +280,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { res, )) }; - match self.cm().resolve_path( + match self.cm_mut().resolve_path( &segments, None, parent_scope, @@ -336,7 +337,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn build_reduced_graph_external( &self, module: ExternModule<'ra>, - ) -> FxIndexMap> { + ) -> ResolutionTable<'ra> { let mut resolutions = FxIndexMap::default(); let def_id = module.def_id(); let children = self.tcx.module_children(def_id); diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index cbc84540fcdef..212629395c98b 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -782,7 +782,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// This takes the error provided, combines it with the span and any additional spans inside the /// error and emits it. pub(crate) fn report_error( - &mut self, + &self, span: Span, resolution_error: ResolutionError<'ra>, ) -> ErrorGuaranteed { @@ -790,7 +790,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn into_struct_error( - &mut self, + &self, span: Span, resolution_error: ResolutionError<'ra>, ) -> Diag<'_> { @@ -1459,7 +1459,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn add_scope_set_candidates( - &mut self, + &self, suggestions: &mut Vec, scope_set: ScopeSet<'ra>, ps: &ParentScope<'ra>, @@ -1560,7 +1560,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Lookup typo candidate in scope for a macro or import. fn early_lookup_typo_candidate( - &mut self, + &self, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, ident: Ident, @@ -1828,7 +1828,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// N.B., the method does not look into imports, but this is not a problem, /// since we report the definitions (thus, the de-aliased imports). pub(crate) fn lookup_import_candidates( - &mut self, + &self, lookup_ident: Ident, namespace: Namespace, parent_scope: &ParentScope<'ra>, @@ -3310,7 +3310,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// ``` #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_self_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { @@ -3330,7 +3330,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// ``` #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_crate_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { @@ -3362,7 +3362,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// ``` #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_super_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { @@ -3385,7 +3385,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// name as the first part of path. #[instrument(level = "debug", skip(self, parent_scope))] fn make_external_crate_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 1c94779a6009a..3f34af1d01d83 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -346,7 +346,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag_metadata, ))); } else if let RibKind::Block(Some(module)) = rib.kind - && let Ok(binding) = self.cm().resolve_ident_in_scope_set( + && let Ok(binding) = self.cm_mut().resolve_ident_in_scope_set( ident, ScopeSet::Module(ns, module.to_module()), parent_scope, @@ -362,7 +362,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let parent_scope = &ParentScope { module: module.to_module(), ..*parent_scope }; let finalize = finalize.map(|f| Finalize { stage: Stage::Late, ..f }); return self - .cm() + .cm_mut() .resolve_ident_in_scope_set( orig_ident, ScopeSet::All(ns), @@ -1457,7 +1457,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Validate a local resolution (from ribs). #[instrument(level = "debug", skip(self, all_ribs))] fn validate_res_from_ribs( - &mut self, + &self, rib_index: usize, rib_ident: Ident, res: Res, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 3f2e24995deab..c00eb97f4c3d6 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -34,9 +34,9 @@ use crate::diagnostics::{ }; use crate::ref_mut::{CmCell, CmRefCell}; use crate::{ - AmbiguityError, BindingKey, CmResolver, Decl, DeclData, DeclKind, Determinacy, Finalize, - IdentKey, ImportSuggestion, ImportSummary, LocalModule, ModuleOrUniformRoot, ParentScope, - PathResult, PerNS, Res, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, + AmbiguityError, BindingKey, Decl, DeclData, DeclKind, Determinacy, Finalize, IdentKey, + ImportSuggestion, ImportSummary, LocalModule, ModuleOrUniformRoot, ParentScope, PathResult, + PerNS, Res, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, }; @@ -735,7 +735,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let dummy_decl = self.dummy_decl; let dummy_decl = self.new_import_decl(dummy_decl, import); - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { let ident = IdentKey::new(target); // This can fail, dummies are inserted only in non-occupied slots. let _ = this.try_plant_decl_into_local_module(ident, target.span, ns, dummy_decl); @@ -782,13 +782,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut imports_to_resolve = mem::take(&mut self.indeterminate_imports); self.assert_speculative = true; - let cm_resolver = self.cm(); - rustc_data_structures::sync::par_for_each_slice( &mut imports_to_resolve, |(import, resolution, indeterminate_count)| { - (*resolution, *indeterminate_count) = - cm_resolver.reborrow_ref().resolve_import(*import); + (*resolution, *indeterminate_count) = self.resolve_import(*import); }, ); self.assert_speculative = false; @@ -835,7 +832,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ImportKind::Single { target, decls, .. }, ImportResolutionKind::Single(import_decls), ) => { - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { match import_decls[ns] { PendingDecl::Ready(Some(decl)) => { // We need the `target`, `source` can be extracted. @@ -1116,10 +1113,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// - Other values mean that indeterminate exists under certain namespaces. /// /// Meanwhile, if resolution is successful, its result is returned. - fn resolve_import<'r>( - mut self: CmResolver<'r, 'ra, 'tcx>, - import: Import<'ra>, - ) -> (Option>, usize) { + fn resolve_import(&self, import: Import<'ra>) -> (Option>, usize) { debug!( "(resolving import for module) resolving import `{}::{}` in `{}`", Segment::names_to_string(&import.module_path), @@ -1129,7 +1123,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let module = if let Some(module) = import.imported_module.get() { module } else { - let path_res = self.reborrow().maybe_resolve_path( + let path_res = self.cm().maybe_resolve_path( &import.module_path, None, &import.parent_scope, @@ -1157,11 +1151,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut decls = PerNS::default(); let mut indeterminate_count = 0; - self.per_ns_cm(|mut this, ns| { + self.per_ns(|this, ns| { if bindings[ns].get() != PendingDecl::Pending { return; }; - let binding_result = this.reborrow().maybe_resolve_ident_in_module( + let binding_result = this.cm().maybe_resolve_ident_in_module( module, source, ns, @@ -1202,7 +1196,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We'll provide more context to the privacy errors later, up to `len`. let privacy_errors_len = self.privacy_errors.len(); - let path_res = self.cm().resolve_path( + let path_res = self.cm_mut().resolve_path( &import.module_path, None, &import.parent_scope, @@ -1370,14 +1364,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // importing it if available. let mut path = import.module_path.clone(); path.push(Segment::from_ident(ident)); - if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.cm().resolve_path( - &path, - None, - &import.parent_scope, - Some(finalize), - ignore_decl, - None, - ) { + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self + .cm_mut() + .resolve_path(&path, None, &import.parent_scope, Some(finalize), ignore_decl, None) + { let res = module.res().map(|r| (r, ident)); for error in &mut self.privacy_errors[privacy_errors_len..] { error.outermost_res = res; @@ -1407,8 +1397,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let mut all_ns_err = true; - self.per_ns(|this, ns| { - let binding = this.cm().resolve_ident_in_module( + self.per_ns_mut(|this, ns| { + let binding = this.cm_mut().resolve_ident_in_module( module, ident, ns, @@ -1472,8 +1462,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if all_ns_err { let mut all_ns_failed = true; - self.per_ns(|this, ns| { - let binding = this.cm().resolve_ident_in_module( + self.per_ns_mut(|this, ns| { + let binding = this.cm_mut().resolve_ident_in_module( module, ident, ns, @@ -1632,7 +1622,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(ident)); - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { if let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) { this.lint_if_path_starts_with_module(finalize, &full_path, Some(binding)); } @@ -1642,7 +1632,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { if let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) { this.owners.get_mut(&import_id).unwrap().import_res[ns] = Some(binding.res()); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 535d11d00d718..f30e6844c861c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1581,7 +1581,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { finalize: Option, source: PathSource<'_, 'ast, 'ra>, ) -> PathResult<'ra> { - self.r.cm().resolve_path_with_ribs( + self.r.cm_mut().resolve_path_with_ribs( path, opt_ns, &self.parent_scope, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e26bfa6b96d51..f2ce21377acce 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2067,7 +2067,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn update_err_for_private_tuple_struct_fields( - &mut self, + &self, err: &mut Diag<'_>, source: &PathSource<'_, '_, '_>, def_id: DefId, @@ -2177,7 +2177,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } }; - let bad_struct_syntax_suggestion = |this: &mut Self, err: &mut Diag<'_>, def_id: DefId| { + let bad_struct_syntax_suggestion = |this: &Self, err: &mut Diag<'_>, def_id: DefId| { let (followed_by_brace, closing_brace) = this.followed_by_brace(span); match source { @@ -2629,7 +2629,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn suggest_alternative_construction_methods( - &mut self, + &self, def_id: DefId, err: &mut Diag<'_>, path_span: Span, @@ -2784,7 +2784,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn lookup_assoc_candidate( - &mut self, + &self, ident: Ident, ns: Namespace, filter_fn: FilterFn, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2dbf32dc20288..af62b136f60c5 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -24,7 +24,7 @@ use std::cell::Ref; use std::collections::BTreeSet; use std::ops::ControlFlow; -use std::sync::{Arc, Once}; +use std::sync::{Arc, OnceLock}; use std::{fmt, mem}; use diagnostics::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; @@ -633,7 +633,22 @@ impl BindingKey { } } -type Resolutions<'ra> = CmRefCell>>; +type ResolutionTable<'ra> = FxIndexMap>; + +enum Resolutions<'ra> { + Local(CmRefCell>), + Extern(OnceLock>>), +} + +impl<'ra> Resolutions<'ra> { + fn new(local: bool) -> Self { + if local { + Resolutions::Local(Default::default()) + } else { + Resolutions::Extern(Default::default()) + } + } +} /// One node in the tree of modules. /// @@ -655,8 +670,6 @@ struct ModuleData<'ra> { /// Mapping between names and their (possibly in-progress) resolutions in this module. /// Resolutions in modules from other crates are not populated until accessed. lazy_resolutions: Resolutions<'ra>, - /// True if this is a module from other crate that needs to be populated on access. - populate_on_access: Once, /// Used to disambiguate underscore items (`const _: T = ...`) in the module. underscore_disambiguator: CmCell, @@ -710,6 +723,7 @@ impl<'ra> ModuleData<'ra> { vis: Visibility, arenas: &'ra ResolverArenas<'ra>, ) -> Self { + let lazy_resolutions = Resolutions::new(kind.is_local()); let self_decl = match kind { ModuleKind::Def(def_kind, def_id, ..) => { let expn_id = expansion.as_local().unwrap_or(LocalExpnId::ROOT); @@ -720,8 +734,7 @@ impl<'ra> ModuleData<'ra> { ModuleData { parent, kind, - lazy_resolutions: Default::default(), - populate_on_access: Once::new(), + lazy_resolutions, underscore_disambiguator: CmCell::new(0), unexpanded_invocations: Default::default(), no_implicit_prelude, @@ -1990,27 +2003,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - /// Returns a conditionally mutable resolver. - /// - /// Currently only dependent on `assert_speculative`, if `assert_speculative` is false, - /// the resolver will allow mutation; otherwise, it will be immutable. - fn cm(&mut self) -> CmResolver<'_, 'ra, 'tcx> { - CmResolver::new(self, !self.assert_speculative) + /// Returns a conditionally mutable resolver that cannot be mutated. + fn cm(&self) -> CmResolver<'_, 'ra, 'tcx> { + CmResolver::Ref(self) + } + + /// Returns a conditionally mutable resolver that can be mutated. + /// Will panic if the `assert_speculative` field is true. + fn cm_mut(&mut self) -> CmResolver<'_, 'ra, 'tcx> { + assert!(!self.assert_speculative, "can't mutably borrow speculative resolver"); + CmResolver::Mut(self) } /// Runs the function on each namespace. - fn per_ns(&mut self, mut f: F) { + fn per_ns(&self, mut f: F) { f(self, TypeNS); f(self, ValueNS); f(self, MacroNS); } - fn per_ns_cm<'r, F: FnMut(CmResolver<'_, 'ra, 'tcx>, Namespace)>( - mut self: CmResolver<'r, 'ra, 'tcx>, - mut f: F, - ) { - f(self.reborrow(), TypeNS); - f(self.reborrow(), ValueNS); + fn per_ns_mut(&mut self, mut f: F) { + f(self, TypeNS); + f(self, ValueNS); f(self, MacroNS); } @@ -2080,7 +2094,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let scope_set = ScopeSet::All(TypeNS); let ctxt = Macros20NormalizedSyntaxContext::new(sp.ctxt()); - self.cm().visit_scopes(scope_set, parent_scope, ctxt, sp, None, |mut this, scope, _, _| { + let cmr = self.cm_mut(); + cmr.visit_scopes(scope_set, parent_scope, ctxt, sp, None, |mut this, scope, _, _| { match scope { Scope::ModuleNonGlobs(module, _) => { this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); @@ -2162,15 +2177,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.tcx.hir_arena.alloc_slice(&import_ids) } - fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> { - if !module.is_local() { - // as long as 1 thread is building this external table, all other threads will wait - module.populate_on_access.call_once(|| { - *module.lazy_resolutions.borrow_mut_unchecked() = - self.build_reduced_graph_external(module.expect_extern()); - }); + fn resolutions(&self, module: Module<'ra>) -> &'ra CmRefCell> { + match &module.0.0.lazy_resolutions { + Resolutions::Local(local_res) => local_res, + Resolutions::Extern(extern_res) => { + // as long as 1 thread is building this external table, all other threads will wait + extern_res.get_or_init(|| { + CmRefCell::new(self.build_reduced_graph_external(module.expect_extern())) + }) + } } - &module.0.0.lazy_resolutions } fn resolution( @@ -2464,7 +2480,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, /// just that an error occurred. fn resolve_rustdoc_path( - &mut self, + &self, path_str: &str, ns: Namespace, parent_scope: ParentScope<'ra>, @@ -2791,7 +2807,7 @@ pub fn provide(providers: &mut Providers) { /// /// `Cm` stands for "conditionally mutable". /// -/// Prefer constructing it through [`Resolver::cm`] to ensure correctness. +/// Prefer constructing it through `Resolver::cm(_mut)` to ensure correctness. type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; // FIXME: These are cells for caches that can be populated even during speculative resolution, @@ -2802,68 +2818,52 @@ use std::cell::{Cell as CacheCell, RefCell as CacheRefCell}; mod ref_mut { use std::cell::{BorrowMutError, Cell, Ref, RefCell, RefMut}; use std::fmt; - use std::marker::PhantomData; use std::ops::Deref; use crate::Resolver; - /// A wrapper around a mutable reference that conditionally allows mutable access. - pub(crate) struct RefOrMut<'a, T> { - // We keep a raw pointer because it makes `reborrow_ref` possible. It is always safe to - // cast this to a `&T` because `RefOrMut` is only created through `new` which takes - // a `&mut T`. - p: *mut T, - mutable: bool, - _marker: PhantomData<&'a mut T>, + /// A reference type that conditionally allows mutable access. + pub(crate) enum RefOrMut<'a, T> { + Ref(&'a T), + Mut(&'a mut T), } impl<'a, T> Deref for RefOrMut<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { - // SAFETY: `RefOrMUt` is only constructable through a `&mut T`. - unsafe { self.p.as_ref_unchecked() } + match self { + RefOrMut::Ref(r) => r, + RefOrMut::Mut(r) => r, + } } } impl<'a, T> AsRef for RefOrMut<'a, T> { fn as_ref(&self) -> &T { - // SAFETY: `RefOrMUt` is only constructable through a `&mut T`. - unsafe { self.p.as_ref_unchecked() } + &*self } } impl<'a, T> RefOrMut<'a, T> { - pub(crate) fn new(p: &'a mut T, mutable: bool) -> Self { - RefOrMut { p, mutable, _marker: PhantomData } - } - - pub(crate) fn reborrow_ref(&self) -> RefOrMut<'_, T> { - assert!( - !self.mutable, - "Tried to reborrow a mutable `RefOrMut` through shared reference." - ); - RefOrMut { p: self.p, mutable: self.mutable, _marker: PhantomData } - } - - /// This is needed because this wraps a `&mut T` and is therefore not `Copy`. + /// This is needed because the type may allow mutable access and is therefore not `Copy`. pub(crate) fn reborrow(&mut self) -> RefOrMut<'_, T> { - RefOrMut { p: self.p, mutable: self.mutable, _marker: PhantomData } + match self { + RefOrMut::Ref(r) => RefOrMut::Ref(r), + RefOrMut::Mut(r) => RefOrMut::Mut(r), + } } /// Returns a mutable reference to the inner value if allowed. /// /// # Panics /// - /// Panics if the `mutable` flag is false. + /// Panics if the wrapped reference is immutable. #[track_caller] pub(crate) fn get_mut(&mut self) -> &mut T { - match self.mutable { - false => panic!("can't mutably borrow speculative resolver"), - // SAFETY: - // - `RefOrMut` is only constructable through a `&mut T` and we - // have tested that it may indeed be used as a `&mut T` in this match. - true => unsafe { self.p.as_mut_unchecked() }, + match self { + RefOrMut::Ref(_) => panic!("can't mutably borrow an immutable reference"), + RefOrMut::Mut(r) => r, } } } @@ -2924,13 +2924,6 @@ mod ref_mut { CmRefCell(RefCell::new(value)) } - #[track_caller] - // FIXME: this should be eliminated in the process of migration - // to parallel name resolution. - pub(crate) fn borrow_mut_unchecked(&self) -> RefMut<'_, T> { - self.0.borrow_mut() - } - #[track_caller] pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> { if r.assert_speculative { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 54f9aa8e914ec..1e9d60ca21551 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -613,7 +613,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { invoc_in_mod_inert_attr: Option, suggestion_span: Option, ) -> Result<(&'ra Arc, Res), Indeterminate> { - let (ext, res) = match self.cm().resolve_macro_or_delegation_path( + let (ext, res) = match self.cm_mut().resolve_macro_or_delegation_path( path, kind, parent_scope, @@ -966,7 +966,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for seg in &mut path { seg.id = None; } - match self.cm().resolve_path( + match self.cm_mut().resolve_path( &path, Some(ns), &parent_scope, @@ -1063,7 +1063,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let macro_resolutions = self.single_segment_macro_resolutions.take(self); for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { - match self.cm().resolve_ident_in_scope_set( + match self.cm_mut().resolve_ident_in_scope_set( ident, ScopeSet::Macro(kind), &parent_scope, @@ -1117,7 +1117,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let builtin_attrs = mem::take(&mut self.builtin_attrs); for (ident, parent_scope) in builtin_attrs { - let _ = self.cm().resolve_ident_in_scope_set( + let _ = self.cm_mut().resolve_ident_in_scope_set( ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, @@ -1295,7 +1295,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn path_accessible( - &mut self, + &self, expn_id: LocalExpnId, path: &ast::Path, namespaces: &[Namespace], diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ecfff0e64baf1..06b261828ed40 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2795,6 +2795,10 @@ written to standard error output)"), "enable generalizing pointer types (default: no)"), sanitizer_cfi_normalize_integers: Option = (None, parse_opt_bool, [TRACKED] { TARGET_MODIFIER: SanitizerCfiNormalizeIntegers }, "enable normalizing integer types (default: no)"), + sanitizer_cfi_diag: Option = (None, parse_opt_bool, [TRACKED], + "enable CFI diagnostics (default: no)"), + sanitizer_cfi_recover: Option = (None, parse_opt_bool, [TRACKED], + "enable CFI recovery (default: no)"), sanitizer_dataflow_abilist: Vec = (Vec::new(), parse_comma_list, [TRACKED], "additional ABI list files that control how shadow parameters are passed (comma separated)"), sanitizer_kcfi_arity: Option = (None, parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ed12adf71cff2..8eb597fccad63 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2301,7 +2301,6 @@ symbols! { va_copy, va_end, va_list, - va_start, val, validity, value, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 0af41423b846a..57f1a9788c20c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1366,8 +1366,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if kind1 == kind2 && alias1 == alias2 && !self.tcx.sess.opts.verbose => { let mut strs = (DiagStyledString::new(), DiagStyledString::new()); - strs.0.push_normal(format!("_")); - strs.1.push_normal(format!("_")); + strs.0.push_normal("_"); + strs.1.push_normal("_"); strs } @@ -1376,14 +1376,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { match (alias1.kind, alias2.kind) { (ty::Projection { def_id: def_id1 }, ty::Projection { def_id: def_id2 }) => { // `::Name` - values.0.push_normal(format!("<")); - values.1.push_normal(format!("<")); + values.0.push_normal("<"); + values.1.push_normal("<"); let (trait_ref1, args1) = alias1.trait_ref_and_own_args(self.tcx); let (trait_ref2, args2) = alias2.trait_ref_and_own_args(self.tcx); self.recurse(trait_ref1.self_ty(), trait_ref2.self_ty(), &mut values); - values.0.push_normal(format!(" as ")); - values.1.push_normal(format!(" as ")); + values.0.push_normal(" as "); + values.1.push_normal(" as "); if trait_ref1.def_id == trait_ref2.def_id { if self.tcx.sess.opts.verbose { values @@ -1414,8 +1414,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .1 .push_highlighted(format!("{}", trait_ref2.print_trait_sugared())); } - values.0.push_normal(format!(">::")); - values.1.push_normal(format!(">::")); + values.0.push_normal(">::"); + values.1.push_normal(">::"); let name1 = self.tcx.item_name(def_id1); let name2 = self.tcx.item_name(def_id2); if def_id1 == def_id2 { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 81f19529418a5..60f4ca6a8759c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -285,27 +285,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { || self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id)) && (self.tcx.is_diagnostic_item(sym::From, leaf_trait_def_id) || self.tcx.is_diagnostic_item(sym::TryFrom, leaf_trait_def_id)) - { - let trait_ref = leaf_trait_predicate.skip_binder().trait_ref; - - if let Some(found_ty) = + && let Some(trait_ref) = + leaf_trait_predicate.no_bound_vars().map(|pred| pred.trait_ref) + && let Some(found_ty) = trait_ref.args.get(1).and_then(|arg| arg.as_type()) - { - let ty = main_trait_predicate.skip_binder().self_ty(); + && let Some(ty) = + main_trait_predicate.no_bound_vars().map(|pred| pred.self_ty()) + && let Some(cast_ty) = + self.find_explicit_cast_type(obligation.param_env, found_ty, ty) + { + let found_ty_str = self.tcx.short_string(found_ty, &mut long_ty_file); + let cast_ty_str = self.tcx.short_string(cast_ty, &mut long_ty_file); - if let Some(cast_ty) = - self.find_explicit_cast_type(obligation.param_env, found_ty, ty) - { - let found_ty_str = - self.tcx.short_string(found_ty, &mut long_ty_file); - let cast_ty_str = - self.tcx.short_string(cast_ty, &mut long_ty_file); - - err.help(format!( - "consider casting the `{found_ty_str}` value to `{cast_ty_str}`", - )); - } - } + err.help(format!( + "consider casting the `{found_ty_str}` value to `{cast_ty_str}`", + )); } *err.long_ty_path() = long_ty_file; diff --git a/library/alloc/src/io/buffered/bufwriter.rs b/library/alloc/src/io/buffered/bufwriter.rs index 4847c1605ac79..806e71c2772ae 100644 --- a/library/alloc/src/io/buffered/bufwriter.rs +++ b/library/alloc/src/io/buffered/bufwriter.rs @@ -490,6 +490,10 @@ impl BufWriter { /// # Example /// /// ``` +/// # // This test requires unwinding to work. +/// # // Disable it when unwinding isn't available. +/// # #[cfg(panic = "unwind")] +/// # fn main() { /// use std::io::{self, BufWriter, Write}; /// use std::panic::{catch_unwind, AssertUnwindSafe}; /// @@ -508,6 +512,9 @@ impl BufWriter { /// let (recovered_writer, buffered_data) = stream.into_parts(); /// assert!(matches!(recovered_writer, PanickingWriter)); /// assert_eq!(buffered_data.unwrap_err().into_inner(), b"some data"); +/// # } +/// # #[cfg(not(panic = "unwind"))] +/// # fn main() {} /// ``` pub struct WriterPanicked { buf: Vec, diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 1125f437c1538..8a5f72bac8c2f 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -138,27 +138,27 @@ impl_from!(i16 => isize, #[stable(feature = "lossless_iusize_conv", since = "1.2 // of the `f16`/`f128` impls can be used on stable as the `f16` and `f128` types are unstable). // signed integer -> float -impl_from!(i8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i8 => f16, #[unstable(feature = "f16", issue = "116909")], #[unstable_feature_bound(f16)]); impl_from!(i8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(i8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i8 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(i16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(i16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i16 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(i32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(i32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i32 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(i64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); // unsigned integer -> float -impl_from!(u8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u8 => f16, #[unstable(feature = "f16", issue = "116909")], #[unstable_feature_bound(f16)]); impl_from!(u8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(u8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u8 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(u16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(u16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u16 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(u32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u32 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(u64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); // float -> float @@ -170,20 +170,22 @@ impl_from!(u64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unsta // // See also . impl_from!(f16 => f32, #[unstable(feature = "f32_from_f16", issue = "154005")], #[unstable_feature_bound(f32_from_f16)]); -impl_from!(f16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(f16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(f16 => f64, #[unstable(feature = "f16", issue = "116909")], #[unstable_feature_bound(f16)]); +// Also #[unstable(feature = "f16", issue = "116909")]: +impl_from!(f16 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f16, f128)]); impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(f64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(f32 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); +impl_from!(f64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); macro_rules! impl_float_from_bool { ( + $(#[$attr:meta])* $float:ty $(; doctest_prefix: $(#[doc = $doctest_prefix:literal])* doctest_suffix: $(#[doc = $doctest_suffix:literal])* )? ) => { - #[stable(feature = "float_from_bool", since = "1.68.0")] + $(#[$attr])* #[rustc_const_unstable(feature = "const_convert", issue = "143773")] const impl From for $float { #[doc = concat!("Converts a [`bool`] to [`", stringify!($float),"`] losslessly.")] @@ -210,6 +212,8 @@ macro_rules! impl_float_from_bool { // boolean -> float impl_float_from_bool!( + #[unstable(feature = "f16", issue = "116909")] + #[unstable_feature_bound(f16)] f16; doctest_prefix: // rustdoc doesn't remove the conventional space after the `///` @@ -220,9 +224,17 @@ impl_float_from_bool!( doctest_suffix: ///# } ); -impl_float_from_bool!(f32); -impl_float_from_bool!(f64); impl_float_from_bool!( + #[stable(feature = "float_from_bool", since = "1.68.0")] + f32 +); +impl_float_from_bool!( + #[stable(feature = "float_from_bool", since = "1.68.0")] + f64 +); +impl_float_from_bool!( + #[unstable(feature = "f128", issue = "116909")] + #[unstable_feature_bound(f128)] f128; doctest_prefix: ///# #![allow(unused_features)] diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index ecd462c60eda3..3df2c70801644 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -56,6 +56,19 @@ where } } + #[inline] + fn count(mut self) -> usize { + if self.n == 0 { + return 0; + } + // Advancing consumes the same elements `next` would have yielded, + // while benefiting from the inner iterator's `advance_by` fast path. + match self.iter.advance_by(self.n) { + Ok(()) => self.n, + Err(remaining) => self.n - remaining.get(), + } + } + #[inline] fn size_hint(&self) -> (usize, Option) { if self.n == 0 { diff --git a/library/coretests/tests/iter/adapters/take.rs b/library/coretests/tests/iter/adapters/take.rs index b932059afec8a..700bd3f44a1d1 100644 --- a/library/coretests/tests/iter/adapters/take.rs +++ b/library/coretests/tests/iter/adapters/take.rs @@ -260,3 +260,66 @@ fn test_reverse_on_zip() { assert_eq!((1, 0), (one, zero)); } } + +#[test] +fn test_iterator_take_count() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + + // take shorter than, equal to, and longer than the underlying iterator + assert_eq!(xs.iter().take(0).count(), 0); + assert_eq!(xs.iter().take(5).count(), 5); + assert_eq!(xs.iter().take(10).count(), 10); + assert_eq!(xs.iter().take(11).count(), 10); + assert_eq!(xs.iter().take(usize::MAX).count(), 10); + + // partially consumed + let mut it = xs.iter().take(5); + it.next(); + it.next(); + assert_eq!(it.count(), 3); + + let mut it = xs.iter().take(20); + it.next(); + assert_eq!(it.count(), 9); + + // `count` must observe the same elements `next` would have yielded: + // a side-effecting inner iterator sees exactly min(n, len) closure calls. + let mut calls = 0; + let count = (0..10) + .map(|x| { + calls += 1; + x + }) + .take(3) + .count(); + assert_eq!(count, 3); + assert_eq!(calls, 3); + + // stateful filter: count agrees with the number of elements actually yielded + let mut budget = 7; + let yielded: Vec = (1..100) + .filter(|&x| { + if x <= budget { + budget -= 1; + true + } else { + false + } + }) + .take(10) + .collect(); + + let mut budget = 7; + let counted = (1..100) + .filter(|&x| { + if x <= budget { + budget -= 1; + true + } else { + false + } + }) + .take(10) + .count(); + assert_eq!(counted, yielded.len()); +} diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index d29ea81c67e6d..0d3732a83a9e9 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -1,6 +1,7 @@ -use crate::ffi::{CStr, OsStr, OsString, c_char}; +use crate::ffi::{CStr, OsStr, OsString}; use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; +use crate::mem::MaybeUninit; use crate::os::hermit::ffi::OsStringExt; use crate::os::hermit::hermit_abi::{ self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, @@ -12,9 +13,10 @@ use crate::sync::Arc; use crate::sys::fd::FileDesc; pub use crate::sys::fs::common::{Dir, copy, exists}; use crate::sys::helpers::run_path_with_cstr; +use crate::sys::io::DEFAULT_BUF_SIZE; use crate::sys::time::SystemTime; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, cvt, unsupported, unsupported_err}; -use crate::{fmt, mem}; +use crate::{cmp, fmt, mem, slice}; #[derive(Debug)] pub struct File(FileDesc); @@ -33,29 +35,75 @@ impl FileAttr { // all DirEntry's will have a reference to this struct struct InnerReadDir { root: PathBuf, - dir: Vec, -} - -impl InnerReadDir { - pub fn new(root: PathBuf, dir: Vec) -> Self { - Self { root, dir } - } } pub struct ReadDir { inner: Arc, + fd: FileDesc, + buf: GetdentsBuffer, +} + +/// A buffer containing [`dirent64`]s, filled with [`getdents64`]. +/// +/// This struct is roughly modeled after the `BufReader`'s `Buffer`. +struct GetdentsBuffer { + // The buffer. + buf: Box<[MaybeUninit]>, + // The current seek offset into `buf`, must always be <= `filled`. pos: usize, + // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are + // initialized with bytes from a read. + filled: usize, } -impl ReadDir { - fn new(inner: InnerReadDir) -> Self { - Self { inner: Arc::new(inner), pos: 0 } +impl GetdentsBuffer { + /// Creates a new buffer with at least `capacity` bytes for use with dirent. + fn with_capacity(capacity: usize) -> Self { + let buf = Box::new_uninit_slice(capacity.div_ceil(size_of::())); + Self { buf, pos: 0, filled: 0 } + } + + fn buffer(&self) -> &[u8] { + // SAFETY: self.pos and self.filled are valid, and self.filled >= self.pos, and + // that region is initialized because those are all invariants of this type. + unsafe { + let ptr = self.buf.as_ptr().cast::>().add(self.pos); + slice::from_raw_parts(ptr, self.filled - self.pos).assume_init_ref() + } + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.filled); + } + + fn fill_buf(&mut self, fd: BorrowedFd<'_>) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.filled { + debug_assert!(self.pos == self.filled); + + let result = unsafe { + cvt(hermit_abi::getdents64( + fd.as_raw_fd(), + self.buf.as_mut_ptr().cast(), + self.buf.len() * size_of::(), + )) + }; + + self.pos = 0; + self.filled = 0; + + self.filled = result? as usize; + } + + Ok(self.buffer()) } } pub struct DirEntry { - /// path to the entry - root: PathBuf, + dir: Arc, /// 64-bit inode number ino: u64, /// File type @@ -185,48 +233,59 @@ impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { - let mut counter: usize = 0; - let mut offset: usize = 0; - - // loop over all directory entries and search the entry for the current position loop { - // leave function, if the loop reaches the of the buffer (with all entries) - if offset >= self.inner.dir.len() { + let buf = match self.buf.fill_buf(self.fd.as_fd()) { + Ok(buf) => buf, + Err(err) => return Some(Err(err)), + }; + + if buf.len() == 0 { + // No more entries left. return None; } - let dir = unsafe { &*(self.inner.dir.as_ptr().add(offset) as *const dirent64) }; - - if counter == self.pos { - self.pos += 1; - - // After dirent64, the file name is stored. d_reclen represents the length of the dirent64 - // plus the length of the file name. Consequently, file name has a size of d_reclen minus - // the size of dirent64. The file name is always a C string and terminated by `\0`. - // Consequently, we are able to ignore the last byte. - let name_bytes = - unsafe { CStr::from_ptr(&dir.d_name as *const _ as *const c_char).to_bytes() }; - let entry = DirEntry { - root: self.inner.root.clone(), - ino: dir.d_ino, - type_: dir.d_type, - name: OsString::from_vec(name_bytes.to_vec()), - }; - - return Some(Ok(entry)); + let entry_ptr = buf.as_ptr().cast::(); + + // The dirent64 struct is a weird imaginary thing that isn't ever supposed + // to be worked with by value. Its trailing d_name field is declared + // variously as [c_char; 256] or [c_char; 1] on different systems but + // either way that size is meaningless; only the offset of d_name is + // meaningful. The dirent64 pointers that libc returns from getdents64 are + // allowed to point to allocations smaller _or_ LARGER than implied by the + // definition of the struct. + // + // As such, we need to be even more careful with dirent64 than if its + // contents were "simply" partially initialized data. + // + // Like for uninitialized contents, converting entry_ptr to `&dirent64` + // would not be legal. However, we can use `&raw const (*entry_ptr).d_name` + // to refer the fields individually, because that operation is equivalent + // to `byte_offset` and thus does not require the full extent of `*entry_ptr` + // to be in bounds of the same allocation, only the offset of the field + // being referenced. + + self.buf.consume(usize::from(unsafe { (*entry_ptr).d_reclen })); + + // d_name is guaranteed to be null-terminated. + let name = unsafe { CStr::from_ptr((&raw const (*entry_ptr).d_name).cast()) }; + let name_bytes = name.to_bytes(); + if name_bytes == b"." || name_bytes == b".." { + continue; } - counter += 1; - - // move to the next dirent64, which is directly stored after the previous one - offset = offset + usize::from(dir.d_reclen); + return Some(Ok(DirEntry { + dir: Arc::clone(&self.inner), + ino: unsafe { (*entry_ptr).d_ino }, + type_: unsafe { (*entry_ptr).d_type }, + name: OsString::from_vec(name_bytes.to_vec()), + })); } } } impl DirEntry { pub fn path(&self) -> PathBuf { - self.root.join(self.file_name_os_str()) + self.dir.root.join(self.file_name_os_str()) } pub fn file_name(&self) -> OsString { @@ -342,7 +401,7 @@ impl File { } let fd = unsafe { cvt(hermit_abi::open(path.as_ptr(), flags, mode))? }; - Ok(File(unsafe { FileDesc::from_raw_fd(fd as i32) })) + Ok(File(unsafe { FileDesc::from_raw_fd(fd) })) } pub fn file_attr(&self) -> io::Result { @@ -352,7 +411,7 @@ impl File { } pub fn fsync(&self) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn datasync(&self) -> io::Result<()> { @@ -380,7 +439,7 @@ impl File { } pub fn truncate(&self, _size: u64) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn read(&self, buf: &mut [u8]) -> io::Result { @@ -431,15 +490,15 @@ impl File { } pub fn duplicate(&self) -> io::Result { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } } @@ -516,42 +575,14 @@ pub fn readdir(path: &Path) -> io::Result { let fd_raw = run_path_with_cstr(path, &|path| { cvt(unsafe { hermit_abi::open(path.as_ptr(), O_RDONLY | O_DIRECTORY, 0) }) })?; - let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) }; - let root = path.to_path_buf(); - - // read all director entries - let mut vec: Vec = Vec::new(); - let mut sz = 512; - loop { - // reserve memory to receive all directory entries - vec.resize(sz, 0); - - let readlen = unsafe { - hermit_abi::getdents64(fd.as_raw_fd(), vec.as_mut_ptr() as *mut dirent64, sz) - }; - if readlen > 0 { - // shrink down to the minimal size - vec.resize(readlen.try_into().unwrap(), 0); - break; - } - - // if the buffer is too small, getdents64 returns EINVAL - // otherwise, getdents64 returns an error number - if readlen != (-hermit_abi::errno::EINVAL).into() { - return Err(Error::from_raw_os_error(readlen.try_into().unwrap())); - } + let fd = unsafe { FileDesc::from_raw_fd(fd_raw) }; - // we don't have enough memory => try to increase the vector size - sz = sz * 2; - - // 1 MB for directory entries should be enough - // stop here to avoid an endless loop - if sz > 0x100000 { - return Err(Error::from(ErrorKind::Uncategorized)); - } - } + let root = path.to_path_buf(); + let inner = Arc::new(InnerReadDir { root }); + let buf_size = usize::max(DEFAULT_BUF_SIZE, size_of::()); + let buf = GetdentsBuffer::with_capacity(buf_size); - Ok(ReadDir::new(InnerReadDir::new(root, vec))) + Ok(ReadDir { inner, fd, buf }) } pub fn unlink(path: &Path) -> io::Result<()> { @@ -563,7 +594,7 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { } pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_perm_nofollow(_p: &Path, _perm: FilePermissions) -> io::Result<()> { @@ -571,11 +602,11 @@ pub fn set_perm_nofollow(_p: &Path, _perm: FilePermissions) -> io::Result<()> { } pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn rmdir(path: &Path) -> io::Result<()> { diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index ba40da4035b6f..f43395ce8fd80 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -304,8 +304,8 @@ impl Socket { } pub fn take_error(&self) -> io::Result> { - let raw: c_int = unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)? }; - if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } + let raw = unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)? }; + if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw))) } } pub fn as_raw(&self) -> RawFd { diff --git a/library/std/src/sys/pal/windows/winsock.rs b/library/std/src/sys/pal/windows/winsock.rs index b110a43ef3aa8..7b2e7fe59171c 100644 --- a/library/std/src/sys/pal/windows/winsock.rs +++ b/library/std/src/sys/pal/windows/winsock.rs @@ -1,18 +1,17 @@ use super::c; use crate::ffi::c_int; -use crate::sync::atomic::Atomic; -use crate::sync::atomic::Ordering::{AcqRel, Relaxed}; +use crate::sync::Once; use crate::{io, mem}; -static WSA_STARTED: Atomic = Atomic::::new(false); +static WSA_INIT: Once = Once::new(); /// Checks whether the Windows socket interface has been started already, and /// if not, starts it. #[inline] pub fn startup() { - if !WSA_STARTED.load(Relaxed) { - wsa_startup(); - } + // Make sure to only call `WSAStartup` once, because it's not thread-safe + // on Wine: https://bugs.winehq.org/show_bug.cgi?id=60084. + WSA_INIT.call_once_force(|_| wsa_startup()); } #[cold] @@ -24,11 +23,6 @@ fn wsa_startup() { &mut data, ); assert_eq!(ret, 0); - if WSA_STARTED.swap(true, AcqRel) { - // If another thread raced with us and called WSAStartup first then call - // WSACleanup so it's as though WSAStartup was only called once. - c::WSACleanup(); - } } } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index ff96f341966b7..c77c312bf9aa9 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1525,10 +1525,14 @@ fn supported_sanitizers( let darwin_libs = |os: &str, components: &[&str]| -> Vec { components .iter() - .map(move |c| SanitizerRuntime { - cmake_target: format!("clang_rt.{c}_{os}_dynamic"), - path: out_dir.join(format!("build/lib/darwin/libclang_rt.{c}_{os}_dynamic.dylib")), - name: format!("librustc-{channel}_rt.{c}.dylib"), + .map(move |c| { + let cmake_c = if *c == "ubsan" { "ubsan_standalone" } else { *c }; + SanitizerRuntime { + cmake_target: format!("clang_rt.{cmake_c}_{os}_dynamic"), + path: out_dir + .join(format!("build/lib/darwin/libclang_rt.{cmake_c}_{os}_dynamic.dylib")), + name: format!("librustc-{channel}_rt.{c}.dylib"), + } }) .collect() }; @@ -1536,10 +1540,13 @@ fn supported_sanitizers( let common_libs = |os: &str, arch: &str, components: &[&str]| -> Vec { components .iter() - .map(move |c| SanitizerRuntime { - cmake_target: format!("clang_rt.{c}-{arch}"), - path: out_dir.join(format!("build/lib/{os}/libclang_rt.{c}-{arch}.a")), - name: format!("librustc-{channel}_rt.{c}.a"), + .map(move |c| { + let cmake_c = if *c == "ubsan" { "ubsan_standalone" } else { *c }; + SanitizerRuntime { + cmake_target: format!("clang_rt.{cmake_c}-{arch}"), + path: out_dir.join(format!("build/lib/{os}/libclang_rt.{cmake_c}-{arch}.a")), + name: format!("librustc-{channel}_rt.{c}.a"), + } }) .collect() }; @@ -1550,9 +1557,11 @@ fn supported_sanitizers( "aarch64-apple-ios-sim" => darwin_libs("iossim", &["asan", "tsan", "rtsan"]), "aarch64-apple-ios-macabi" => darwin_libs("osx", &["asan", "lsan", "tsan"]), "aarch64-unknown-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]), - "aarch64-unknown-linux-gnu" => { - common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan", "rtsan"]) - } + "aarch64-unknown-linux-gnu" => common_libs( + "linux", + "aarch64", + &["asan", "lsan", "msan", "tsan", "hwasan", "rtsan", "ubsan"], + ), "aarch64-unknown-linux-ohos" => { common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"]) } @@ -1572,7 +1581,7 @@ fn supported_sanitizers( "x86_64-unknown-linux-gnu" => common_libs( "linux", "x86_64", - &["asan", "dfsan", "lsan", "msan", "safestack", "tsan", "rtsan"], + &["asan", "dfsan", "lsan", "msan", "safestack", "tsan", "rtsan", "ubsan"], ), "x86_64-unknown-linux-gnuasan" => common_libs("linux", "x86_64", &["asan"]), "x86_64-unknown-linux-gnumsan" => common_libs("linux", "x86_64", &["msan"]), diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 6cc2811c15f3b..b3ed7d4c6beb7 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -607,7 +607,6 @@ impl Config { stack_protector: rust_stack_protector, strip: rust_strip, bootstrap_override_lld: rust_bootstrap_override_lld, - bootstrap_override_lld_legacy: rust_bootstrap_override_lld_legacy, std_features: rust_std_features, break_on_ice: rust_break_on_ice, rustflags: rust_rustflags, @@ -717,14 +716,7 @@ impl Config { let pgo_rustdoc = init_pgo(pgo_rustdoc, "rustdoc"); let pgo_cargo = init_pgo(pgo_cargo, "cargo"); - if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() { - panic!( - "Cannot use both `rust.use-lld` and `rust.bootstrap-override-lld`. Please use only `rust.bootstrap-override-lld`" - ); - } - - let bootstrap_override_lld = - rust_bootstrap_override_lld.or(rust_bootstrap_override_lld_legacy).unwrap_or_default(); + let bootstrap_override_lld = rust_bootstrap_override_lld.unwrap_or_default(); if rust_optimize.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { eprintln!( diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index d84315d87e45a..d179d0713fcda 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -252,16 +252,6 @@ fn rust_lld() { parse("rust.bootstrap-override-lld = false").bootstrap_override_lld, BootstrapOverrideLld::None )); - - // Also check the legacy options - assert!(matches!( - parse("rust.use-lld = true").bootstrap_override_lld, - BootstrapOverrideLld::External - )); - assert!(matches!( - parse("rust.use-lld = false").bootstrap_override_lld, - BootstrapOverrideLld::None - )); } #[test] diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index fa4573ef1734f..f8f383ef18e73 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -51,8 +51,6 @@ define_config! { llvm_bitcode_linker: Option = "llvm-bitcode-linker", lld: Option = "lld", bootstrap_override_lld: Option = "bootstrap-override-lld", - // FIXME: Remove this option in Spring 2026 - bootstrap_override_lld_legacy: Option = "use-lld", llvm_tools: Option = "llvm-tools", deny_warnings: Option = "deny-warnings", backtrace_on_ice: Option = "backtrace-on-ice", @@ -385,7 +383,6 @@ pub fn check_incompatible_options_for_ci_rustc( break_on_ice: _, parallel_frontend_threads: _, bootstrap_override_lld: _, - bootstrap_override_lld_legacy: _, rustflags: _, } = ci_rust_config; diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 062310cc351a7..8892832037ee2 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -661,4 +661,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Obsolete option `build.compiletest-use-stage0-libtest` has no effect and has been removed.", }, + ChangeInfo { + change_id: 160142, + severity: ChangeSeverity::Warning, + summary: "The `rust.use-lld` option has been removed. Use `rust.bootstrap-override-lld` instead.", + }, ]; diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index c7572029936b5..02f3bea8aef01 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -506,6 +506,15 @@ Calculating code examples follows these rules: * typedef 2. If one of the previously listed items has a code example, then it'll be counted. +If you use the `-o` option with it, it will generate the file into the given older name. For example: + +```shell +rustdoc foo.rs --show-coverage -o doc +``` + +Will generate a `foo.txt` into the `doc` folder. If the `-o` option isn't passed, it will display +on stdout. + ### JSON output When using `--output-format json` with this option, it will display the coverage information in diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/calculate_doc_coverage.rs similarity index 81% rename from src/librustdoc/passes/calculate_doc_coverage.rs rename to src/librustdoc/calculate_doc_coverage.rs index adf98afc46cc0..ae05e362f2383 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/calculate_doc_coverage.rs @@ -1,6 +1,8 @@ //! Calculates information used for the --show-coverage flag. use std::collections::BTreeMap; +use std::fs::{File, create_dir_all}; +use std::io::{self, BufWriter, Write, stdout}; use std::ops; use rustc_hir as hir; @@ -10,27 +12,39 @@ use rustc_span::{FileName, RemapPathScopeComponents}; use serde::Serialize; use tracing::debug; -use crate::clean; -use crate::config::OutputFormat; +use crate::config::{OutputFormat, RenderOptions}; use crate::core::DocContext; +use crate::docfs::PathError; +use crate::error::Error; use crate::html::markdown::{ErrorCodes, find_testable_code}; -use crate::passes::Pass; -use crate::passes::check_doc_test_visibility::{Tests, should_have_doc_example}; +use crate::passes::{Tests, should_have_doc_example}; use crate::visit::DocVisitor; - -pub(crate) const CALCULATE_DOC_COVERAGE: Pass = Pass { - name: "calculate-doc-coverage", - run: Some(calculate_doc_coverage), - description: "counts the number of items with and without documentation", -}; - -fn calculate_doc_coverage(krate: clean::Crate, ctx: &mut DocContext<'_>) -> clean::Crate { +use crate::{clean, try_err}; + +pub(crate) fn run( + krate: &clean::Crate, + ctx: &mut DocContext<'_>, + options: &RenderOptions, +) -> Result<(), Error> { + let is_json = ctx.output_format == OutputFormat::CoverageJson; + let tcx = ctx.tcx; let mut calc = CoverageCalculator { items: Default::default(), ctx }; calc.visit_crate(&krate); - calc.print_results(); - - krate + if options.output_to_stdout { + calc.print_results(BufWriter::new(stdout().lock())) + .map_err(|error| Error::new(error, "")) + } else { + let out_dir = &options.output; + try_err!(create_dir_all(out_dir), out_dir); + let name = krate.name(tcx); + let mut out_file = out_dir.join(name.as_str()); + out_file.set_extension(if is_json { "json" } else { "txt" }); + let buf = try_err!(File::create_buffered(&out_file), out_file); + calc.print_results(buf).map_err(|error| Error::new(error, &out_file))?; + println!("Generated output into {out_file:?}"); + Ok(()) + } } #[derive(Default, Copy, Clone, Serialize, Debug)] @@ -130,62 +144,66 @@ impl CoverageCalculator<'_, '_> { .expect("failed to convert JSON data to string") } - fn print_results(&self) { + fn print_results(&self, mut buf: impl Write) -> io::Result<()> { let output_format = self.ctx.output_format; if output_format == OutputFormat::CoverageJson { - println!("{}", self.to_json()); - return; + return writeln!(buf, "{}", self.to_json()); } let mut total = ItemCount::default(); - fn print_table_line() { - println!("+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", ""); + fn print_table_line(buf: &mut impl Write) -> io::Result<()> { + writeln!(buf, "+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", "") } fn print_table_record( + buf: &mut impl Write, name: &str, count: ItemCount, percentage: f64, examples_percentage: f64, - ) { - println!( + ) -> io::Result<()> { + writeln!( + buf, "| {name:<35} | {with_docs:>10} | {percentage:>9.1}% | {with_examples:>10} | \ - {examples_percentage:>9.1}% |", + {examples_percentage:>9.1}% |", with_docs = count.with_docs, with_examples = count.with_examples, - ); + ) } - print_table_line(); - println!( + print_table_line(&mut buf)?; + writeln!( + buf, "| {:<35} | {:>10} | {:>10} | {:>10} | {:>10} |", "File", "Documented", "Percentage", "Examples", "Percentage", - ); - print_table_line(); + )?; + print_table_line(&mut buf)?; for (file, &count) in &self.items { if let Some(percentage) = count.percentage() { print_table_record( + &mut buf, &limit_filename_len( file.display(RemapPathScopeComponents::COVERAGE).to_string(), ), count, percentage, count.examples_percentage().unwrap_or(0.), - ); + )?; total += count; } } - print_table_line(); + print_table_line(&mut buf)?; print_table_record( + &mut buf, "Total", total, total.percentage().unwrap_or(0.0), total.examples_percentage().unwrap_or(0.0), - ); - print_table_line(); + )?; + print_table_line(&mut buf) } } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 840f9d025c3cf..0a3cbf537e5f1 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -726,7 +726,14 @@ impl Options { output_to_stdout = out_dir == "-"; PathBuf::from(out_dir) } - (None, None) => PathBuf::from("doc"), + (None, None) => { + if show_coverage { + // If no `-o` option is given and we're in the `--show-coverage` mode, by + // default we print on the stdout. + output_to_stdout = true; + } + PathBuf::from("doc") + } }; let cfgs = matches.opt_strs("cfg"); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c1ae5f977cb89..af1024580c544 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -452,6 +452,13 @@ pub(crate) fn run_global_ctxt( } } + if show_coverage + && let Err(error) = crate::calculate_doc_coverage::run(&krate, &mut ctxt, &render_options) + { + eprintln!("{error}"); + std::process::exit(1); + } + tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc))); krate = diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index be830cad6c735..0fadd78fd30b1 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -105,6 +105,7 @@ macro_rules! map { }} } +mod calculate_doc_coverage; mod clean; mod config; mod core; @@ -955,14 +956,14 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate); } - cache.crate_version = crate_version; - if show_coverage { // if we ran coverage, bail early, we don't need to also generate docs at this point // (also we didn't load in any of the useful passes) return; } + cache.crate_version = crate_version; + rustc_interface::passes::emit_delayed_lints(tcx); if render_opts.dep_info().is_some() { diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 18e1afaf8a242..725c2be4e2121 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -30,14 +30,13 @@ pub(crate) mod collect_intra_doc_links; pub(crate) use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; mod check_doc_test_visibility; -pub(crate) use self::check_doc_test_visibility::CHECK_DOC_TEST_VISIBILITY; +pub(crate) use self::check_doc_test_visibility::{ + CHECK_DOC_TEST_VISIBILITY, Tests, should_have_doc_example, +}; mod collect_trait_impls; pub(crate) use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; -mod calculate_doc_coverage; -pub(crate) use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE; - mod lint; pub(crate) use self::lint::RUN_LINTS; @@ -81,7 +80,6 @@ pub(crate) const PASSES: &[Pass] = &[ PROPAGATE_STABILITY, COLLECT_INTRA_DOC_LINKS, COLLECT_TRAIT_IMPLS, - CALCULATE_DOC_COVERAGE, RUN_LINTS, ]; @@ -103,7 +101,6 @@ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[ pub(crate) const COVERAGE_PASSES: &[ConditionalPass] = &[ ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), - ConditionalPass::always(CALCULATE_DOC_COVERAGE), ]; impl ConditionalPass { diff --git a/tests/codegen-llvm/gpu_offload/scalar_host.rs b/tests/codegen-llvm/gpu_offload/scalar_host.rs index 3470761be06c8..66c910c439e46 100644 --- a/tests/codegen-llvm/gpu_offload/scalar_host.rs +++ b/tests/codegen-llvm/gpu_offload/scalar_host.rs @@ -13,21 +13,22 @@ // CHECK: define{{( dso_local)?}} void @main() // CHECK-NOT: define // CHECK: %addr = alloca i64, align 8 -// CHECK: store double 4.200000e+01, ptr [[TMP:%[^,]+]], align 8 -// CHECK: [[VAL:%[0-9]+]] = load double, ptr [[TMP]], align 8 -// CHECK: store double [[VAL]], ptr %addr, align 8 -// CHECK: %1 = getelementptr inbounds nuw i8, ptr %.offload_baseptrs, i64 8 -// CHECK-NEXT: store double [[VAL]], ptr %1, align 8 -// CHECK-NEXT: %2 = getelementptr inbounds nuw i8, ptr %.offload_ptrs, i64 8 -// CHECK-NEXT: store ptr %addr, ptr %2, align 8 +// CHECK: store float 4.200000e+01, ptr [[TMP:%[^,]+]], align 4 +// CHECK: [[VAL:%[0-9]+]] = load i32, ptr [[TMP]], align 4 +// CHECK: [[VAL_I64:%[0-9]+]] = zext i32 [[VAL]] to i64 +// CHECK: store i64 [[VAL_I64]], ptr %addr, align 8 +// CHECK: [[REG_GEP1:%[^,]+]] = getelementptr inbounds nuw i8, ptr %.offload_baseptrs, i64 8 +// CHECK-NEXT: store i64 [[VAL_I64]], ptr [[REG_GEP1]], align 8 +// CHECK-NEXT: [[REG_GEP2:%[^,]+]] = getelementptr inbounds nuw i8, ptr %.offload_ptrs, i64 8 +// CHECK-NEXT: store ptr %addr, ptr [[REG_GEP2]], align 8 // CHECK-NEXT: call void @__tgt_target_data_begin_mapper #[unsafe(no_mangle)] fn main() { - let mut x = 0.0; - let k = core::hint::black_box(42.0); + let mut x = 0.0f32; + let k = core::hint::black_box(42.0f32); - core::intrinsics::offload::<_, _, ()>(foo, [1, 1, 1], [1, 1, 1], 0, (&mut x, k)); + core::intrinsics::offload::<_, _, ()>(foo, [1, 1, 1], [1, 1, 1], 0, (&mut x as *mut f32, k)); } unsafe extern "C" { diff --git a/tests/codegen-llvm/gpu_offload/slice_host.rs b/tests/codegen-llvm/gpu_offload/slice_host.rs index d4157d24e03dd..0f27821ef765c 100644 --- a/tests/codegen-llvm/gpu_offload/slice_host.rs +++ b/tests/codegen-llvm/gpu_offload/slice_host.rs @@ -26,8 +26,8 @@ #[unsafe(no_mangle)] fn main() { - let mut x = [0.0, 0.0, 0.0, 0.0]; - core::intrinsics::offload::<_, _, ()>(foo, [1, 1, 1], [1, 1, 1], 0, ((&mut x) as &mut [f64],)); + let mut x = [0.0f32, 0.0, 0.0, 0.0]; + core::intrinsics::offload::<_, _, ()>(foo, [1, 1, 1], [1, 1, 1], 0, ((&mut x) as &mut [f32],)); } unsafe extern "C" { diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-diag-mode.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-diag-mode.rs new file mode 100644 index 0000000000000..07688a8e5cb0b --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-diag-mode.rs @@ -0,0 +1,20 @@ +// Verifies that pointer type membership tests for indirect calls are emitted. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-diag=true -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer + +#![crate_type = "lib"] + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: start: + // CHECK: [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}") + // CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail + // CHECK: type_test.pass: + // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg) + // CHECK: type_test.fail: + // CHECK-NEXT: {{%.+}} = ptrtoint ptr {{%f|%0}} to i64 + // CHECK-NEXT: call void @__ubsan_handle_cfi_check_fail_abort( + // CHECK-NEXT: unreachable + f(arg) +} diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-recover-mode.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-recover-mode.rs new file mode 100644 index 0000000000000..0dbcb7a833fb7 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-recover-mode.rs @@ -0,0 +1,20 @@ +// Verifies that pointer type membership tests for indirect calls are emitted. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-recover=true -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer + +#![crate_type = "lib"] + +pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { + // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: start: + // CHECK: [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}") + // CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail + // CHECK: type_test.pass: + // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg) + // CHECK: type_test.fail: + // CHECK-NEXT: {{%.+}} = ptrtoint ptr {{%f|%0}} to i64 + // CHECK-NEXT: call void @__ubsan_handle_cfi_check_fail( + // CHECK-NEXT: br label %type_test.pass + f(arg) +} diff --git a/tests/run-make/rustdoc-show-coverage/foo.rs b/tests/run-make/rustdoc-show-coverage/foo.rs new file mode 100644 index 0000000000000..4892b4ce1ae69 --- /dev/null +++ b/tests/run-make/rustdoc-show-coverage/foo.rs @@ -0,0 +1,5 @@ +pub struct Bar; + +impl Bar { + pub fn foo() {} +} diff --git a/tests/run-make/rustdoc-show-coverage/rmake.rs b/tests/run-make/rustdoc-show-coverage/rmake.rs new file mode 100644 index 0000000000000..90ad50267b8ad --- /dev/null +++ b/tests/run-make/rustdoc-show-coverage/rmake.rs @@ -0,0 +1,58 @@ +// This test ensures that `-o` option works as expected with `--show-coverage`. +// Regression test for . + +//@ needs-target-std +// To not have to deal with windows paths: +//@ only-linux + +use run_make_support::rfs::{read_to_string, remove_file}; +use run_make_support::{path, rustdoc}; + +fn run_rustdoc(extra_args: &[&str]) -> String { + rustdoc() + .input("foo.rs") + .arg("-Zunstable-options") + .arg("--show-coverage") + .args(extra_args) + .run() + .stdout_utf8() +} + +fn check_print_stdout(extra_args: &[&str], stdout_check: &str) { + let out = run_rustdoc(extra_args); + + // By default, it shouldn't have created a `doc` folder. + assert!(!path("doc").exists(), "`doc` folder created with {extra_args:?}"); + // It should have display its output on stdout. + assert!(out.starts_with(stdout_check), "{out:?} doesn't start with {stdout_check:?}"); +} + +fn check_generate_file(ext: &str, extra_args: &[&str], file_check: &str) { + let mut args = extra_args.to_vec(); + args.push("-o"); + args.push("doc"); + let out = run_rustdoc(&args); + + // By default, it shouldn't have created a `doc` folder. + assert!(path("doc").exists(), "`doc` folder not created with {args:?}"); + let file = format!("doc/foo.{ext}"); + assert!(path(&file).exists()); + + let expected = format!("Generated output into {file:?}\n"); + assert_eq!(out, expected, "Expected {expected:?}, got {out:?}"); + + let content = read_to_string(&file); + assert!(content.starts_with(file_check), "{content:?} doesn't start with {file_check:?}"); + remove_file(file); +} + +fn main() { + check_print_stdout(&[], "+-"); + check_print_stdout(&["-o", "-"], "+-"); + check_print_stdout(&["--output-format=json"], "{"); + check_print_stdout(&["--output-format=json", "-o", "-"], "{"); + + // Now we check that it works with "-o something". + check_generate_file("txt", &[], "+-"); + check_generate_file("json", &["--output-format=json"], "{"); +} diff --git a/tests/rustdoc-ui/coverage/allow_missing_docs.rs b/tests/rustdoc-ui/coverage/allow_missing_docs.rs index 43f0d731fdea0..feca5a1bfe3e9 100644 --- a/tests/rustdoc-ui/coverage/allow_missing_docs.rs +++ b/tests/rustdoc-ui/coverage/allow_missing_docs.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass //! Make sure to have some docs on your crate root diff --git a/tests/rustdoc-ui/coverage/basic.rs b/tests/rustdoc-ui/coverage/basic.rs index febcc80fbbb50..fc44f6826cb9c 100644 --- a/tests/rustdoc-ui/coverage/basic.rs +++ b/tests/rustdoc-ui/coverage/basic.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass #![feature(extern_types)] diff --git a/tests/rustdoc-ui/coverage/doc-examples-json.rs b/tests/rustdoc-ui/coverage/doc-examples-json.rs index 4aa4bf23771d9..bfec2600cb875 100644 --- a/tests/rustdoc-ui/coverage/doc-examples-json.rs +++ b/tests/rustdoc-ui/coverage/doc-examples-json.rs @@ -1,5 +1,5 @@ //@ check-pass -//@ compile-flags:-Z unstable-options --output-format json --show-coverage +//@ compile-flags:-Z unstable-options --output-format json --show-coverage -o - // This check ensures that only one doc example is counted since they're "optional" on // certain items. diff --git a/tests/rustdoc-ui/coverage/doc-examples.rs b/tests/rustdoc-ui/coverage/doc-examples.rs index 283d9c424aa19..dd8969f934ee2 100644 --- a/tests/rustdoc-ui/coverage/doc-examples.rs +++ b/tests/rustdoc-ui/coverage/doc-examples.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass //! This test ensure that only rust code examples are counted. diff --git a/tests/rustdoc-ui/doctest-output.rs b/tests/rustdoc-ui/coverage/doctest-output.rs similarity index 100% rename from tests/rustdoc-ui/doctest-output.rs rename to tests/rustdoc-ui/coverage/doctest-output.rs diff --git a/tests/rustdoc-ui/doctest-output.stderr b/tests/rustdoc-ui/coverage/doctest-output.stderr similarity index 100% rename from tests/rustdoc-ui/doctest-output.stderr rename to tests/rustdoc-ui/coverage/doctest-output.stderr diff --git a/tests/rustdoc-ui/coverage/empty.rs b/tests/rustdoc-ui/coverage/empty.rs index bcd3e48988b15..fd9f1e617fbec 100644 --- a/tests/rustdoc-ui/coverage/empty.rs +++ b/tests/rustdoc-ui/coverage/empty.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass // an empty crate still has one item to document: the crate root diff --git a/tests/rustdoc-ui/coverage/enum-tuple-documented.rs b/tests/rustdoc-ui/coverage/enum-tuple-documented.rs index 4cbeb7a164da1..9e88e896f8da7 100644 --- a/tests/rustdoc-ui/coverage/enum-tuple-documented.rs +++ b/tests/rustdoc-ui/coverage/enum-tuple-documented.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass // The point of this test is to ensure that the number of "documented" items diff --git a/tests/rustdoc-ui/coverage/enum-tuple.rs b/tests/rustdoc-ui/coverage/enum-tuple.rs index 5cbc52a7d033f..25d3c9f57bafe 100644 --- a/tests/rustdoc-ui/coverage/enum-tuple.rs +++ b/tests/rustdoc-ui/coverage/enum-tuple.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass //! (remember the crate root is still a module) diff --git a/tests/rustdoc-ui/coverage/enums.rs b/tests/rustdoc-ui/coverage/enums.rs index 29e4198457610..bdb213c2a53b7 100644 --- a/tests/rustdoc-ui/coverage/enums.rs +++ b/tests/rustdoc-ui/coverage/enums.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass //! (remember the crate root is still a module) diff --git a/tests/rustdoc-ui/coverage/exotic.rs b/tests/rustdoc-ui/coverage/exotic.rs index 9fc1498cb2a3a..2beb890b21926 100644 --- a/tests/rustdoc-ui/coverage/exotic.rs +++ b/tests/rustdoc-ui/coverage/exotic.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass #![feature(rustdoc_internals)] diff --git a/tests/rustdoc-ui/coverage/json.rs b/tests/rustdoc-ui/coverage/json.rs index bfa8dc7008305..dcab7df252249 100644 --- a/tests/rustdoc-ui/coverage/json.rs +++ b/tests/rustdoc-ui/coverage/json.rs @@ -1,5 +1,5 @@ //@ check-pass -//@ compile-flags:-Z unstable-options --output-format json --show-coverage +//@ compile-flags:-Z unstable-options --output-format json --show-coverage -o - pub mod foo { /// Hello! diff --git a/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs b/tests/rustdoc-ui/coverage/output-format-coveragejson-emit-depinfo.rs similarity index 71% rename from tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs rename to tests/rustdoc-ui/coverage/output-format-coveragejson-emit-depinfo.rs index 0609b515e5ca8..97cdedecb0aaf 100644 --- a/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs +++ b/tests/rustdoc-ui/coverage/output-format-coveragejson-emit-depinfo.rs @@ -1,2 +1,2 @@ -//@ compile-flags: --show-coverage --output-format=json --emit=dep-info -Zunstable-options +//@ compile-flags: --show-coverage --output-format=json --emit=dep-info -Zunstable-options -o - //@ build-pass diff --git a/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.stdout b/tests/rustdoc-ui/coverage/output-format-coveragejson-emit-depinfo.stdout similarity index 100% rename from tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.stdout rename to tests/rustdoc-ui/coverage/output-format-coveragejson-emit-depinfo.stdout diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_non_static.stderr b/tests/rustdoc-ui/coverage/output-format-json-emit-html.html_non_static.stderr similarity index 100% rename from tests/rustdoc-ui/output-format-json-emit-html.html_non_static.stderr rename to tests/rustdoc-ui/coverage/output-format-json-emit-html.html_non_static.stderr diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_non_static_coverage.stderr b/tests/rustdoc-ui/coverage/output-format-json-emit-html.html_non_static_coverage.stderr similarity index 100% rename from tests/rustdoc-ui/output-format-json-emit-html.html_non_static_coverage.stderr rename to tests/rustdoc-ui/coverage/output-format-json-emit-html.html_non_static_coverage.stderr diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_static.stderr b/tests/rustdoc-ui/coverage/output-format-json-emit-html.html_static.stderr similarity index 100% rename from tests/rustdoc-ui/output-format-json-emit-html.html_static.stderr rename to tests/rustdoc-ui/coverage/output-format-json-emit-html.html_static.stderr diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_static_coverage.stderr b/tests/rustdoc-ui/coverage/output-format-json-emit-html.html_static_coverage.stderr similarity index 100% rename from tests/rustdoc-ui/output-format-json-emit-html.html_static_coverage.stderr rename to tests/rustdoc-ui/coverage/output-format-json-emit-html.html_static_coverage.stderr diff --git a/tests/rustdoc-ui/output-format-json-emit-html.rs b/tests/rustdoc-ui/coverage/output-format-json-emit-html.rs similarity index 100% rename from tests/rustdoc-ui/output-format-json-emit-html.rs rename to tests/rustdoc-ui/coverage/output-format-json-emit-html.rs diff --git a/tests/rustdoc-ui/coverage/private.rs b/tests/rustdoc-ui/coverage/private.rs index 91490eff7a8d5..3b78c5d761dbc 100644 --- a/tests/rustdoc-ui/coverage/private.rs +++ b/tests/rustdoc-ui/coverage/private.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage --document-private-items +//@ compile-flags:-Z unstable-options --show-coverage --document-private-items -o - //@ check-pass #![allow(unused)] diff --git a/tests/rustdoc-ui/show-coverage-json-emit-html-non-static.rs b/tests/rustdoc-ui/coverage/show-coverage-json-emit-html-non-static.rs similarity index 100% rename from tests/rustdoc-ui/show-coverage-json-emit-html-non-static.rs rename to tests/rustdoc-ui/coverage/show-coverage-json-emit-html-non-static.rs diff --git a/tests/rustdoc-ui/show-coverage-json-emit-html-non-static.stderr b/tests/rustdoc-ui/coverage/show-coverage-json-emit-html-non-static.stderr similarity index 100% rename from tests/rustdoc-ui/show-coverage-json-emit-html-non-static.stderr rename to tests/rustdoc-ui/coverage/show-coverage-json-emit-html-non-static.stderr diff --git a/tests/rustdoc-ui/show-coverage-json.rs b/tests/rustdoc-ui/coverage/show-coverage-json.rs similarity index 91% rename from tests/rustdoc-ui/show-coverage-json.rs rename to tests/rustdoc-ui/coverage/show-coverage-json.rs index 3851e34fe3599..e7ddc69d79f8a 100644 --- a/tests/rustdoc-ui/show-coverage-json.rs +++ b/tests/rustdoc-ui/coverage/show-coverage-json.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Z unstable-options --show-coverage --output-format=json +//@ compile-flags: -Z unstable-options --show-coverage --output-format=json -o - //@ check-pass mod bar { diff --git a/tests/rustdoc-ui/show-coverage-json.stdout b/tests/rustdoc-ui/coverage/show-coverage-json.stdout similarity index 100% rename from tests/rustdoc-ui/show-coverage-json.stdout rename to tests/rustdoc-ui/coverage/show-coverage-json.stdout diff --git a/tests/rustdoc-ui/show-coverage.rs b/tests/rustdoc-ui/coverage/show-coverage.rs similarity index 68% rename from tests/rustdoc-ui/show-coverage.rs rename to tests/rustdoc-ui/coverage/show-coverage.rs index 00bb1606a82cb..1f9c3a8f805b7 100644 --- a/tests/rustdoc-ui/show-coverage.rs +++ b/tests/rustdoc-ui/coverage/show-coverage.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Z unstable-options --show-coverage +//@ compile-flags: -Z unstable-options --show-coverage -o - //@ check-pass mod bar { diff --git a/tests/rustdoc-ui/show-coverage.stdout b/tests/rustdoc-ui/coverage/show-coverage.stdout similarity index 90% rename from tests/rustdoc-ui/show-coverage.stdout rename to tests/rustdoc-ui/coverage/show-coverage.stdout index b9e0316545e77..42c17f8bbd696 100644 --- a/tests/rustdoc-ui/show-coverage.stdout +++ b/tests/rustdoc-ui/coverage/show-coverage.stdout @@ -1,7 +1,7 @@ +-------------------------------------+------------+------------+------------+------------+ | File | Documented | Percentage | Examples | Percentage | +-------------------------------------+------------+------------+------------+------------+ -| ...ests/rustdoc-ui/show-coverage.rs | 1 | 50.0% | 1 | 100.0% | +| ...doc-ui/coverage/show-coverage.rs | 1 | 50.0% | 1 | 100.0% | +-------------------------------------+------------+------------+------------+------------+ | Total | 1 | 50.0% | 1 | 100.0% | +-------------------------------------+------------+------------+------------+------------+ diff --git a/tests/rustdoc-ui/coverage/statics-consts.rs b/tests/rustdoc-ui/coverage/statics-consts.rs index 85cc23847396e..5177673f7958a 100644 --- a/tests/rustdoc-ui/coverage/statics-consts.rs +++ b/tests/rustdoc-ui/coverage/statics-consts.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass //! gotta make sure we can count statics and consts correctly, too diff --git a/tests/rustdoc-ui/coverage/traits.rs b/tests/rustdoc-ui/coverage/traits.rs index 89044369e6a77..37e147004d714 100644 --- a/tests/rustdoc-ui/coverage/traits.rs +++ b/tests/rustdoc-ui/coverage/traits.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --show-coverage +//@ compile-flags:-Z unstable-options --show-coverage -o - //@ check-pass #![feature(trait_alias)] diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout index e7b8a1dccf802..0243f6cd533a0 100644 --- a/tests/rustdoc-ui/issues/issue-91713.stdout +++ b/tests/rustdoc-ui/issues/issue-91713.stdout @@ -8,7 +8,6 @@ strip-aliased-non-local - strips all non-local private aliased items from the ou propagate-stability - propagates stability to child items collect-intra-doc-links - resolves intra-doc links collect-trait-impls - retrieves trait impls for items in the crate -calculate-doc-coverage - counts the number of items with and without documentation run-lints - runs some of rustdoc's lints Default passes for rustdoc: @@ -26,4 +25,3 @@ collect-intra-doc-links Passes run with `--show-coverage`: strip-hidden (when not --document-hidden-items) strip-private (when not --document-private-items) -calculate-doc-coverage diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs index 72b54ed472756..b30d33091c47f 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs @@ -2,6 +2,7 @@ // Tests that a doc comment will not preclude a field from being considered a diagnostic argument //@ normalize-stderr: "the following other types implement trait `IntoDiagArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr" //@ normalize-stderr: "(COMPILER_DIR/.*\.rs):[0-9]+:[0-9]+" -> "$1:LL:CC" +//@ normalize-stderr: "rustc_errors::Diag::<'a, G>::arg" -> "Diag::<'a, G>::arg" // The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly, // changing the output of this test. Since Subdiagnostic is strictly internal to the compiler diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index 48a338db297e5..feee6eed4593f 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `NotIntoDiagArg: IntoDiagArg` is not satisfied - --> $DIR/diagnostic-derive-doc-comment-field.rs:34:10 + --> $DIR/diagnostic-derive-doc-comment-field.rs:35:10 | LL | #[derive(Diagnostic)] | ---------- required by a bound introduced by this call @@ -8,7 +8,7 @@ LL | arg: NotIntoDiagArg, | ^^^^^^^^^^^^^^ unsatisfied trait bound | help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `NotIntoDiagArg` - --> $DIR/diagnostic-derive-doc-comment-field.rs:26:1 + --> $DIR/diagnostic-derive-doc-comment-field.rs:27:1 | LL | struct NotIntoDiagArg; | ^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ note: required by a bound in `Diag::<'a, G>::arg` = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotIntoDiagArg: IntoDiagArg` is not satisfied - --> $DIR/diagnostic-derive-doc-comment-field.rs:44:10 + --> $DIR/diagnostic-derive-doc-comment-field.rs:45:10 | LL | #[derive(Subdiagnostic)] | ------------- required by a bound introduced by this call @@ -31,7 +31,7 @@ LL | arg: NotIntoDiagArg, | ^^^^^^^^^^^^^^ unsatisfied trait bound | help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `NotIntoDiagArg` - --> $DIR/diagnostic-derive-doc-comment-field.rs:26:1 + --> $DIR/diagnostic-derive-doc-comment-field.rs:27:1 | LL | struct NotIntoDiagArg; | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.rs b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.rs new file mode 100644 index 0000000000000..ae55712c50a93 --- /dev/null +++ b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.rs @@ -0,0 +1,39 @@ +//! Regression test for . +//! +//! Deeply nested associated-type projections used to ICE with "type variables +//! should not be hashed" — but only under incremental compilation. They should now +//! produce ordinary trait-bound errors instead of crashing. + +//@ incremental + +struct S; +struct S2

(); //~ ERROR type parameter `P` is never used + +trait Foo { + type Out; +} + +trait Bar { + type Out; +} + +trait Qux { + type Out; +} + +trait Fuzz { + type Out; +} + +impl, B> Fuzz> for S2 { + type Out = <>::Out as Bar< + //~^ ERROR the trait bound `>::Out: Qux` is not satisfied + //~| ERROR the trait bound `>::Out: Bar, _>` is not satisfied + //~| ERROR the trait bound `>::Out: Bar, _>` is not satisfied + S2, + <<>::Out as Qux>::Out as Fuzz>>::Out, + //~^ ERROR the trait bound `>::Out: Qux` is not satisfied + >>::Out; +} + +fn main() {} diff --git a/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.stderr b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.stderr new file mode 100644 index 0000000000000..fdf55aa4c2bdb --- /dev/null +++ b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.stderr @@ -0,0 +1,65 @@ +error[E0392]: type parameter `P` is never used + --> $DIR/nested-assoc-type-projection-ice-109864.rs:10:11 + | +LL | struct S2

(); + | ^ unused type parameter + | + = help: consider removing `P`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `P` to be a const parameter, use `const P: /* Type */` instead + +error[E0277]: the trait bound `>::Out: Qux` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:29:16 + | +LL | type Out = <>::Out as Bar< + | ________________^ +... | +LL | | >>::Out; + | |___________^ the trait `Qux` is not implemented for `>::Out` + | +help: consider further restricting the associated type + | +LL | impl, B> Fuzz> for S2 where >::Out: Qux { + | ++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `>::Out: Bar, _>` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:29:16 + | +LL | type Out = <>::Out as Bar< + | ________________^ +... | +LL | | >>::Out; + | |___________^ the trait `Bar, _>` is not implemented for `>::Out` + | +help: this trait has no implementations, consider adding one + --> $DIR/nested-assoc-type-projection-ice-109864.rs:16:1 + | +LL | trait Bar { + | ^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `>::Out: Qux` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:34:10 + | +LL | <<>::Out as Qux>::Out as Fuzz>>::Out, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qux` is not implemented for `>::Out` + | +help: consider further restricting the associated type + | +LL | impl, B> Fuzz> for S2 where >::Out: Qux { + | ++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `>::Out: Bar, _>` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:29:5 + | +LL | type Out = <>::Out as Bar< + | ^^^^^^^^ the trait `Bar, _>` is not implemented for `>::Out` + | +help: this trait has no implementations, consider adding one + --> $DIR/nested-assoc-type-projection-ice-109864.rs:16:1 + | +LL | trait Bar { + | ^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0392. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/feature-gates/feature-gate-f128.e2015.stderr b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr index 627010a935475..2cf3eacf07523 100644 --- a/tests/ui/feature-gates/feature-gate-f128.e2015.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr @@ -19,27 +19,127 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:13:12 + --> $DIR/feature-gate-f128.rs:13:18 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:16:12 + --> $DIR/feature-gate-f128.rs:16:18 | -LL | let e: f128 = 1u64.into(); - | ^^^^ +LL | let from_u8: f128 = 1_u8.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:17:19 + | +LL | let from_i16: f128 = 1_i16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:18:19 + | +LL | let from_u16: f128 = 1_u16.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:21:11 + --> $DIR/feature-gate-f128.rs:19:19 + | +LL | let from_i32: f128 = 1_i32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:20:19 + | +LL | let from_u32: f128 = 1_u32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:21:19 + | +LL | let from_i64: f128 = 1_i64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:22:19 + | +LL | let from_u64: f128 = 1_u64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:23:19 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:26:19 + | +LL | let from_f32: f128 = 1.0_f32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:27:19 + | +LL | let from_f64: f128 = 1.0_f64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:28:20 + | +LL | let from_bool: f128 = true.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:32:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -49,7 +149,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:24:8 + --> $DIR/feature-gate-f128.rs:35:8 | LL | a: f128, | ^^^^ @@ -78,17 +178,27 @@ LL | let c = 0f128; = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f128.rs:23:26 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: use of unstable library feature `f128` - --> $DIR/feature-gate-f128.rs:13:24 + --> $DIR/feature-gate-f128.rs:13:30 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: required for `f128` to implement `From` - = note: required for `i64` to implement `Into` + = note: required for `f128` to implement `From` + = note: required for `i8` to implement `Into` -error: aborting due to 9 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr index 627010a935475..2cf3eacf07523 100644 --- a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr @@ -19,27 +19,127 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:13:12 + --> $DIR/feature-gate-f128.rs:13:18 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:16:12 + --> $DIR/feature-gate-f128.rs:16:18 | -LL | let e: f128 = 1u64.into(); - | ^^^^ +LL | let from_u8: f128 = 1_u8.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:17:19 + | +LL | let from_i16: f128 = 1_i16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:18:19 + | +LL | let from_u16: f128 = 1_u16.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:21:11 + --> $DIR/feature-gate-f128.rs:19:19 + | +LL | let from_i32: f128 = 1_i32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:20:19 + | +LL | let from_u32: f128 = 1_u32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:21:19 + | +LL | let from_i64: f128 = 1_i64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:22:19 + | +LL | let from_u64: f128 = 1_u64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:23:19 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:26:19 + | +LL | let from_f32: f128 = 1.0_f32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:27:19 + | +LL | let from_f64: f128 = 1.0_f64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:28:20 + | +LL | let from_bool: f128 = true.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:32:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -49,7 +149,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:24:8 + --> $DIR/feature-gate-f128.rs:35:8 | LL | a: f128, | ^^^^ @@ -78,17 +178,27 @@ LL | let c = 0f128; = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f128.rs:23:26 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: use of unstable library feature `f128` - --> $DIR/feature-gate-f128.rs:13:24 + --> $DIR/feature-gate-f128.rs:13:30 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: required for `f128` to implement `From` - = note: required for `i64` to implement `Into` + = note: required for `f128` to implement `From` + = note: required for `i8` to implement `Into` -error: aborting due to 9 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f128.rs b/tests/ui/feature-gates/feature-gate-f128.rs index 13851b72c70f2..3b64c71a23122 100644 --- a/tests/ui/feature-gates/feature-gate-f128.rs +++ b/tests/ui/feature-gates/feature-gate-f128.rs @@ -10,11 +10,22 @@ pub fn main() { let a: f128 = 100.0; //~ ERROR the type `f128` is unstable let b = 0.0f128; //~ ERROR the type `f128` is unstable let c = 0f128; //~ ERROR the type `f128` is unstable - let d: f128 = 1i64.into(); + let from_i8: f128 = 1_i8.into(); //~^ ERROR the type `f128` is unstable //~| ERROR use of unstable library feature `f128` - let e: f128 = 1u64.into(); + let from_u8: f128 = 1_u8.into(); //~ ERROR the type `f128` is unstable + let from_i16: f128 = 1_i16.into(); //~ ERROR the type `f128` is unstable + let from_u16: f128 = 1_u16.into(); //~ ERROR the type `f128` is unstable + let from_i32: f128 = 1_i32.into(); //~ ERROR the type `f128` is unstable + let from_u32: f128 = 1_u32.into(); //~ ERROR the type `f128` is unstable + let from_i64: f128 = 1_i64.into(); //~ ERROR the type `f128` is unstable + let from_u64: f128 = 1_u64.into(); //~ ERROR the type `f128` is unstable + let from_f16: f128 = 1.0_f16.into(); //~^ ERROR the type `f128` is unstable + //~| ERROR the type `f16` is unstable + let from_f32: f128 = 1.0_f32.into(); //~ ERROR the type `f128` is unstable + let from_f64: f128 = 1.0_f64.into(); //~ ERROR the type `f128` is unstable + let from_bool: f128 = true.into(); //~ ERROR the type `f128` is unstable foo(1.23); } diff --git a/tests/ui/feature-gates/feature-gate-f16.e2015.stderr b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr index b53f12af48fc8..3bc77d00e2384 100644 --- a/tests/ui/feature-gates/feature-gate-f16.e2015.stderr +++ b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr @@ -18,8 +18,48 @@ LL | let a: f16 = 100.0; = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f16.rs:17:20 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:20:18 + | +LL | let from_i8: f16 = 1_i8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:21:18 + | +LL | let from_u8: f16 = 1_u8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:22:20 + | +LL | let from_bool: f16 = true.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:19:11 + --> $DIR/feature-gate-f16.rs:26:11 | LL | fn foo(a: f16) {} | ^^^ @@ -29,7 +69,7 @@ LL | fn foo(a: f16) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:22:8 + --> $DIR/feature-gate-f16.rs:29:8 | LL | a: f16, | ^^^ @@ -59,26 +99,46 @@ LL | let c = 0f16; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:13:18 + --> $DIR/feature-gate-f16.rs:13:25 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:16:25 + | +LL | let into_f64: f64 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:17:27 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `f32_from_f16` - --> $DIR/feature-gate-f16.rs:13:25 + --> $DIR/feature-gate-f16.rs:13:32 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^ | = help: add `#![feature(f32_from_f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: required for `f32` to implement `From` = note: required for `f16` to implement `Into` -error: aborting due to 8 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f16.e2018.stderr b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr index b53f12af48fc8..3bc77d00e2384 100644 --- a/tests/ui/feature-gates/feature-gate-f16.e2018.stderr +++ b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr @@ -18,8 +18,48 @@ LL | let a: f16 = 100.0; = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f16.rs:17:20 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:20:18 + | +LL | let from_i8: f16 = 1_i8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:21:18 + | +LL | let from_u8: f16 = 1_u8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:22:20 + | +LL | let from_bool: f16 = true.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:19:11 + --> $DIR/feature-gate-f16.rs:26:11 | LL | fn foo(a: f16) {} | ^^^ @@ -29,7 +69,7 @@ LL | fn foo(a: f16) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:22:8 + --> $DIR/feature-gate-f16.rs:29:8 | LL | a: f16, | ^^^ @@ -59,26 +99,46 @@ LL | let c = 0f16; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:13:18 + --> $DIR/feature-gate-f16.rs:13:25 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:16:25 + | +LL | let into_f64: f64 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:17:27 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `f32_from_f16` - --> $DIR/feature-gate-f16.rs:13:25 + --> $DIR/feature-gate-f16.rs:13:32 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^ | = help: add `#![feature(f32_from_f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: required for `f32` to implement `From` = note: required for `f16` to implement `Into` -error: aborting due to 8 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f16.rs b/tests/ui/feature-gates/feature-gate-f16.rs index 6babc6c5c03ce..6211581db1c7a 100644 --- a/tests/ui/feature-gates/feature-gate-f16.rs +++ b/tests/ui/feature-gates/feature-gate-f16.rs @@ -10,9 +10,16 @@ pub fn main() { let a: f16 = 100.0; //~ ERROR the type `f16` is unstable let b = 0.0f16; //~ ERROR the type `f16` is unstable let c = 0f16; //~ ERROR the type `f16` is unstable - let d: f32 = 1.0f16.into(); + let into_f32: f32 = 1.0f16.into(); //~^ ERROR the type `f16` is unstable //~| ERROR use of unstable library feature `f32_from_f16` + let into_f64: f64 = 1.0_f16.into(); //~ ERROR the type `f16` is unstable + let into_f128: f128 = 1.0_f16.into(); + //~^ ERROR the type `f16` is unstable + //~| ERROR the type `f128` is unstable + let from_i8: f16 = 1_i8.into(); //~ ERROR the type `f16` is unstable + let from_u8: f16 = 1_u8.into(); //~ ERROR the type `f16` is unstable + let from_bool: f16 = true.into(); //~ ERROR the type `f16` is unstable foo(1.23); } diff --git a/tests/ui/offload/check_config.fail.stderr b/tests/ui/offload/check_config.fail.stderr index a9162ed926cb0..f1c73687889fd 100644 --- a/tests/ui/offload/check_config.fail.stderr +++ b/tests/ui/offload/check_config.fail.stderr @@ -1,4 +1,4 @@ -error: using the offload feature requires -Z offload=Enable +error: using the offload feature requires -Z offload= error: using the offload feature requires -C lto=fat diff --git a/tests/ui/offload/check_config.rs b/tests/ui/offload/check_config.rs index 667c6d9788bae..69afe65a308b4 100644 --- a/tests/ui/offload/check_config.rs +++ b/tests/ui/offload/check_config.rs @@ -3,10 +3,10 @@ //@ needs-enzyme //@[pass] build-pass //@[fail] build-fail -//@[pass] compile-flags: -Zunstable-options -Zoffload=Enable -Clto=fat --emit=metadata +//@[pass] compile-flags: -Zunstable-options -Zoffload=Device -Clto=fat --emit=metadata //@[fail] compile-flags: -Clto=thin -//[fail]~? ERROR: using the offload feature requires -Z offload=Enable +//[fail]~? ERROR: using the offload feature requires -Z offload= //[fail]~? ERROR: using the offload feature requires -C lto=fat #![feature(core_intrinsics)] @@ -17,7 +17,7 @@ fn main() { } fn kernel_1(x: &mut [f32; 256]) { - core::intrinsics::offload(_kernel_1, (x,)) + core::intrinsics::offload(_kernel_1, [1, 1, 1], [1, 1, 1], 0, (x,)) } fn _kernel_1(x: &mut [f32; 256]) {} diff --git a/tests/ui/offload/non_tuple_args.rs b/tests/ui/offload/non_tuple_args.rs new file mode 100644 index 0000000000000..0a07c99a26d34 --- /dev/null +++ b/tests/ui/offload/non_tuple_args.rs @@ -0,0 +1,11 @@ +//@ compile-flags: -Zunstable-options -Zoffload=Device -Clto=fat + +#![feature(core_intrinsics)] + +fn main() { + // args_ty is not a tuple + core::intrinsics::offload::<_, _, ()>(kernel_0, [1, 1, 1], [1, 1, 1], 0, 42); + //~^ ERROR `{integer}` is not a tuple +} + +fn kernel_0() {} diff --git a/tests/ui/offload/non_tuple_args.stderr b/tests/ui/offload/non_tuple_args.stderr new file mode 100644 index 0000000000000..8b59d6828c6f2 --- /dev/null +++ b/tests/ui/offload/non_tuple_args.stderr @@ -0,0 +1,12 @@ +error[E0277]: `{integer}` is not a tuple + --> $DIR/non_tuple_args.rs:7:36 + | +LL | core::intrinsics::offload::<_, _, ()>(kernel_0, [1, 1, 1], [1, 1, 1], 0, 42); + | ^ the nightly-only, unstable trait `std::marker::Tuple` is not implemented for `{integer}` + | +note: required by a bound in `offload` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/offload/type_mismatch.rs b/tests/ui/offload/type_mismatch.rs new file mode 100644 index 0000000000000..4079444a0aff1 --- /dev/null +++ b/tests/ui/offload/type_mismatch.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -Zunstable-options -Zoffload=Device -Clto=fat + +#![feature(core_intrinsics)] + +fn main() { + // kernel_ty is not a function item + let not_fn = 42; + core::intrinsics::offload::<_, _, ()>(not_fn, [1, 1, 1], [1, 1, 1], 0, ()); + //~^ ERROR expected a function item for the offload kernel, found `i32` + + // argument count mismatch + core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, ()); + //~^ ERROR offload kernel expects 1 arguments, but 0 arguments were provided + + // argument type mismatch + core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, (42.0f64,)); + //~^ ERROR type mismatch in offload kernel argument 0: expected `f32`, found `f64` + + // return type mismatch + let _: f64 = core::intrinsics::offload::<_, _, f64>(kernel_0, [1, 1, 1], [1, 1, 1], 0, ()); + //~^ ERROR offload kernel return type mismatch: kernel returns `()`, but offload call expects `f64` + + // multiple argument type mismatch + core::intrinsics::offload::<_, _, ()>(kernel_2, [1, 1, 1], [1, 1, 1], 0, (42.0f64, 42.0f64)); + //~^ ERROR type mismatch in offload kernel argument 0: expected `f32`, found `f64` + //~| ERROR type mismatch in offload kernel argument 1: expected `f32`, found `f64` +} + +fn kernel_0() {} +fn kernel_1(_x: f32) {} +fn kernel_2(_x: f32, _y: f32) {} diff --git a/tests/ui/offload/type_mismatch.stderr b/tests/ui/offload/type_mismatch.stderr new file mode 100644 index 0000000000000..8cf160ca09486 --- /dev/null +++ b/tests/ui/offload/type_mismatch.stderr @@ -0,0 +1,38 @@ +error: expected a function item for the offload kernel, found `i32` + --> $DIR/type_mismatch.rs:8:5 + | +LL | core::intrinsics::offload::<_, _, ()>(not_fn, [1, 1, 1], [1, 1, 1], 0, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: offload kernel expects 1 arguments, but 0 arguments were provided + --> $DIR/type_mismatch.rs:12:5 + | +LL | core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: type mismatch in offload kernel argument 0: expected `f32`, found `f64` + --> $DIR/type_mismatch.rs:16:5 + | +LL | core::intrinsics::offload::<_, _, ()>(kernel_1, [1, 1, 1], [1, 1, 1], 0, (42.0f64,)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: offload kernel return type mismatch: kernel returns `()`, but offload call expects `f64` + --> $DIR/type_mismatch.rs:20:18 + | +LL | let _: f64 = core::intrinsics::offload::<_, _, f64>(kernel_0, [1, 1, 1], [1, 1, 1], 0, ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: type mismatch in offload kernel argument 0: expected `f32`, found `f64` + --> $DIR/type_mismatch.rs:24:5 + | +LL | core::intrinsics::offload::<_, _, ()>(kernel_2, [1, 1, 1], [1, 1, 1], 0, (42.0f64, 42.0f64)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: type mismatch in offload kernel argument 1: expected `f32`, found `f64` + --> $DIR/type_mismatch.rs:24:5 + | +LL | core::intrinsics::offload::<_, _, ()>(kernel_2, [1, 1, 1], [1, 1, 1], 0, (42.0f64, 42.0f64)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/pin-ergonomics/pinned-drop-check.stderr b/tests/ui/pin-ergonomics/pinned-drop-check.stderr index 3a848c66578b4..3dc6e18a9178e 100644 --- a/tests/ui/pin-ergonomics/pinned-drop-check.stderr +++ b/tests/ui/pin-ergonomics/pinned-drop-check.stderr @@ -71,12 +71,18 @@ error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop | LL | impl Drop for Foo {} | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + | + = help: implement the missing item: `fn drop(&mut self) { todo!() }` + = help: implement the missing item: `fn pin_drop(self: Pin<&mut Self>) { todo!() }` error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop` --> $DIR/pinned-drop-check.rs:60:5 | LL | impl Drop for Bar {} | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + | + = help: implement the missing item: `fn drop(&mut self) { todo!() }` + = help: implement the missing item: `fn pin_drop(self: Pin<&mut Self>) { todo!() }` error: `Bar` must implement `pin_drop` --> $DIR/pinned-drop-check.rs:87:9 diff --git a/tests/ui/sanitizer/cfi/fn-ptr-type-mismatch.rs b/tests/ui/sanitizer/cfi/fn-ptr-type-mismatch.rs new file mode 100644 index 0000000000000..6fe7eec7c6920 --- /dev/null +++ b/tests/ui/sanitizer/cfi/fn-ptr-type-mismatch.rs @@ -0,0 +1,41 @@ +// Verifies that calling a function pointer with a mismatched type triggers a +// CFI violation and causes the process to trap. + +//@ revisions: cfi kcfi +// FIXME(#122848) Remove only-linux once OSX CFI binaries work +//@ only-linux +//@ ignore-backends: gcc +//@ [cfi] needs-sanitizer-cfi +//@ [cfi] needs-sanitizer-support +//@ [kcfi] needs-sanitizer-kcfi +//@ compile-flags: -C target-feature=-crt-static +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer +//@ [cfi] compile-flags: -C opt-level=0 -C codegen-units=1 -C lto +//@ [cfi] compile-flags: -C prefer-dynamic=off +//@ [cfi] compile-flags: -Z sanitizer=cfi +//@ [cfi] compile-flags: -Z sanitizer-cfi-diag=true +//@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off +//@ run-fail-or-crash + +use std::hint::black_box; +use std::mem; + +fn add_one(x: i32) -> i32 { + x + 1 +} + +// Accept a function pointer as a parameter so that the indirect call cannot +// be devirtualized by the compiler. +#[inline(never)] +fn call_with_mismatch(f: fn(i32) -> i32) { + // Transmute fn(i32) -> i32 into fn(i32, i32) -> i32, creating a + // function pointer type mismatch that CFI should catch. + let g: fn(i32, i32) -> i32 = unsafe { mem::transmute(f) }; + // This indirect call should fail the CFI type check and trap. + let _result = g(1, 2); +} + +fn main() { + call_with_mismatch(black_box(add_one)); +} diff --git a/tests/ui/std/add-spawn-hook-reentrancy-159923.rs b/tests/ui/std/add-spawn-hook-reentrancy-159923.rs index a3714bfda9501..a488193d120f3 100644 --- a/tests/ui/std/add-spawn-hook-reentrancy-159923.rs +++ b/tests/ui/std/add-spawn-hook-reentrancy-159923.rs @@ -2,6 +2,7 @@ //@ edition:2024 //@ run-pass //@ needs-threads +//@ needs-unwind #![feature(alloc_error_hook, thread_spawn_hook)] diff --git a/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.rs b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.rs new file mode 100644 index 0000000000000..cce714757cc62 --- /dev/null +++ b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.rs @@ -0,0 +1,13 @@ +fn foo(_x: u32, a: impl Into, _y: u32, b: impl Into) { + println!("fox: a={}, b={}", a.into(), b.into()); +} + +fn main() { + let bar: String = "bar".to_string(); + let baz: &str = "baz"; + + for (a, b) in &[(&bar, baz)] { + let a: &String = a; + foo(42, a, 43, b); //~ ERROR: the trait bound `String: From<&&str>` is not satisfied [E0277] + } +} diff --git a/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.stderr b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.stderr new file mode 100644 index 0000000000000..422660d580efc --- /dev/null +++ b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `String: From<&&str>` is not satisfied + --> $DIR/bad-error-message-impl-trait-double-ref-issue-85681.rs:11:24 + | +LL | foo(42, a, 43, b); + | --- ^ the trait `From<&&str>` is not implemented for `String` + | | + | required by a bound introduced by this call + | + = help: consider casting the `&&str` value to `&str` + = note: required for `&&str` to implement `Into` +note: required by a bound in `foo` + --> $DIR/bad-error-message-impl-trait-double-ref-issue-85681.rs:1:56 + | +LL | fn foo(_x: u32, a: impl Into, _y: u32, b: impl Into) { + | ^^^^^^^^^^^^ required by this bound in `foo` +help: consider dereferencing here + | +LL | foo(42, a, 43, *b); + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr b/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr index 7ad10cfce984f..9868cf8faa084 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr @@ -1,6 +1,12 @@ error[E0046]: not all trait items implemented, missing one of: `eq`, `neq` --> $DIR/rustc_must_implement_one_of.rs:41:1 | +LL | fn eq(&self, other: &Self) -> bool { + | ---------------------------------- `eq` from trait +... +LL | fn neq(&self, other: &Self) -> bool { + | ----------------------------------- `neq` from trait +... LL | impl Equal for T3 {} | ^^^^^^^^^^^^^^^^^ missing one of `eq`, `neq` in implementation | diff --git a/tests/ui/traits/explicit-reference-cast-hrtb.rs b/tests/ui/traits/explicit-reference-cast-hrtb.rs new file mode 100644 index 0000000000000..8714bff369b82 --- /dev/null +++ b/tests/ui/traits/explicit-reference-cast-hrtb.rs @@ -0,0 +1,14 @@ +//! Regression test for #158967 + +struct Foo; + +fn f() +where + for<'a> Foo: From<&'a String>, +{ +} + +fn main() { + f(); + //~^ ERROR the trait bound `for<'a> Foo: From<&'a String>` is not satisfied [E0277] +} diff --git a/tests/ui/traits/explicit-reference-cast-hrtb.stderr b/tests/ui/traits/explicit-reference-cast-hrtb.stderr new file mode 100644 index 0000000000000..4921a87900051 --- /dev/null +++ b/tests/ui/traits/explicit-reference-cast-hrtb.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `for<'a> Foo: From<&'a String>` is not satisfied + --> $DIR/explicit-reference-cast-hrtb.rs:12:5 + | +LL | f(); + | ^^^ unsatisfied trait bound + | +help: the trait `for<'a> From<&'a String>` is not implemented for `Foo` + --> $DIR/explicit-reference-cast-hrtb.rs:3:1 + | +LL | struct Foo; + | ^^^^^^^^^^ +note: required by a bound in `f` + --> $DIR/explicit-reference-cast-hrtb.rs:7:18 + | +LL | fn f() + | - required by a bound in this function +LL | where +LL | for<'a> Foo: From<&'a String>, + | ^^^^^^^^^^^^^^^^ required by this bound in `f` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.