diff options
340 files changed, 6236 insertions, 2023 deletions
diff --git a/.editorconfig b/.editorconfig index 1b137cf4ebe..6c8560aa1f5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,10 +8,13 @@ root = true end_of_line = lf charset = utf-8 insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 4 # some tests need trailing whitespace in output snapshots -[!tests/] -trim_trailing_whitespace = true +[tests/**] +trim_trailing_whitespace = false # for actual source code files of test, we still don't want trailing whitespace [tests/**.{rs,js}] trim_trailing_whitespace = true @@ -19,9 +22,9 @@ trim_trailing_whitespace = true [tests/ui/{frontmatter/frontmatter-whitespace-3.rs,parser/shebang/shebang-space.rs}] trim_trailing_whitespace = false -[!src/llvm-project] -indent_style = space -indent_size = 4 +[src/llvm-project] +indent_style = unset +indent_size = unset [*.rs] max_line_length = 100 diff --git a/Cargo.lock b/Cargo.lock index a8df53f3a41..52f50481157 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3204,9 +3204,9 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb13874a0e55baf4ac3d49d38206aecb31a55b75d6c4d04fd850b53942c8cc8" +checksum = "3b881c015c729b43105bbd3702a9bdecee28fafaa21126d1d62e454ec011a4b7" dependencies = [ "anyhow", "rustc_version", diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 16fd9241a17..eac93957797 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -856,6 +856,9 @@ # as libstd features, this option can also be used to configure features such as optimize_for_size. #rust.std-features = ["panic_unwind"] +# Trigger a `DebugBreak` after an internal compiler error during bootstrap on Windows +#rust.break-on-ice = true + # ============================================================================= # Distribution options # diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index ea98bebd305..6dc6d1026f6 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -22,8 +22,7 @@ pub enum CommentKind { Block, } -// This type must not implement `Hash` due to the unusual `PartialEq` impl below. -#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)] pub enum InvisibleOrigin { // From the expansion of a metavariable in a declarative macro. MetaVar(MetaVarKind), @@ -45,20 +44,6 @@ impl InvisibleOrigin { } } -impl PartialEq for InvisibleOrigin { - #[inline] - fn eq(&self, _other: &InvisibleOrigin) -> bool { - // When we had AST-based nonterminals we couldn't compare them, and the - // old `Nonterminal` type had an `eq` that always returned false, - // resulting in this restriction: - // https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment - // This `eq` emulates that behaviour. We could consider lifting this - // restriction now but there are still cases involving invisible - // delimiters that make it harder than it first appears. - false - } -} - /// Annoyingly similar to `NonterminalKind`, but the slight differences are important. #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] pub enum MetaVarKind { @@ -142,7 +127,8 @@ impl Delimiter { } } - // This exists because `InvisibleOrigin`s should be compared. It is only used for assertions. + // This exists because `InvisibleOrigin`s should not be compared. It is only used for + // assertions. pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool { match (self, other) { (Delimiter::Parenthesis, Delimiter::Parenthesis) => true, diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index b8a748563d5..7fa1293463c 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -151,7 +151,7 @@ attr_parsing_unrecognized_repr_hint = attr_parsing_unstable_cfg_target_compact = compact `cfg(target(..))` is experimental and subject to change -attr_parsing_unstable_feature_bound_incompatible_stability = Item annotated with `#[unstable_feature_bound]` should not be stable +attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` attr_parsing_unsupported_literal_cfg_boolean = diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 7e77781dc2f..c3adb5e767e 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -12,9 +12,7 @@ use cranelift_object::{ObjectBuilder, ObjectModule}; use rustc_codegen_ssa::assert_module_sources::CguReuse; use rustc_codegen_ssa::back::link::ensure_removed; use rustc_codegen_ssa::base::determine_cgu_reuse; -use rustc_codegen_ssa::{ - CodegenResults, CompiledModule, CrateInfo, ModuleKind, errors as ssa_errors, -}; +use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, errors as ssa_errors}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; @@ -363,7 +361,6 @@ fn emit_cgu( invocation_temp, prof, product.object, - ModuleKind::Regular, name.clone(), producer, )?; @@ -372,7 +369,6 @@ fn emit_cgu( module_regular, module_global_asm: global_asm_object_file.map(|global_asm_object_file| CompiledModule { name: format!("{name}.asm"), - kind: ModuleKind::Regular, object: Some(global_asm_object_file), dwarf_object: None, bytecode: None, @@ -389,7 +385,6 @@ fn emit_module( invocation_temp: Option<&str>, prof: &SelfProfilerRef, mut object: cranelift_object::object::write::Object<'_>, - kind: ModuleKind, name: String, producer_str: &str, ) -> Result<CompiledModule, String> { @@ -430,7 +425,6 @@ fn emit_module( Ok(CompiledModule { name, - kind, object: Some(tmp_file), dwarf_object: None, bytecode: None, @@ -485,7 +479,6 @@ fn reuse_workproduct_for_cgu( Ok(ModuleCodegenResult { module_regular: CompiledModule { name: cgu.name().to_string(), - kind: ModuleKind::Regular, object: Some(obj_out_regular), dwarf_object: None, bytecode: None, @@ -495,7 +488,6 @@ fn reuse_workproduct_for_cgu( }, module_global_asm: source_file_global_asm.map(|source_file| CompiledModule { name: cgu.name().to_string(), - kind: ModuleKind::Regular, object: Some(obj_out_global_asm), dwarf_object: None, bytecode: None, @@ -651,7 +643,6 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option<CompiledModule> { tcx.sess.invocation_temp.as_deref(), &tcx.sess.prof, product.object, - ModuleKind::Allocator, "allocator_shim".to_owned(), &crate::debuginfo::producer(tcx.sess), ) { diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index fcee6b6df62..9d8ce2383f2 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -204,7 +204,7 @@ fn fat_lto( let path = tmp_path.path().to_path_buf().join(&module.name); let path = path.to_str().expect("path"); let context = &module.module_llvm.context; - let config = cgcx.config(module.kind); + let config = &cgcx.module_config; // NOTE: we need to set the optimization level here in order for LTO to do its job. context.set_optimization_level(to_gcc_opt_level(config.opt_level)); context.add_command_line_option("-flto=auto"); diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 5affb26483a..9f2d37d39d8 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -29,8 +29,18 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[ } /// Get LLVM attribute for the provided inline heuristic. -#[inline] -fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> { +pub(crate) fn inline_attr<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + instance: ty::Instance<'tcx>, +) -> Option<&'ll Attribute> { + // `optnone` requires `noinline` + let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) { + (_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never, + (InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint, + (inline, _) => inline, + }; + if !cx.tcx.sess.opts.unstable_opts.inline_llvm { // disable LLVM inlining return Some(AttributeKind::NoInline.create_attr(cx.llcx)); @@ -346,14 +356,6 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( OptimizeAttr::Speed => {} } - // `optnone` requires `noinline` - let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) { - (_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never, - (InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint, - (inline, _) => inline, - }; - to_add.extend(inline_attr(cx, inline)); - if cx.sess().must_emit_unwind_tables() { to_add.push(uwtable_attr(cx.llcx, cx.sess().opts.unstable_opts.use_sync_unwind)); } @@ -488,6 +490,14 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let function_features = codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>(); + // Apply function attributes as per usual if there are no user defined + // target features otherwise this will get applied at the callsite. + if function_features.is_empty() { + if let Some(inline_attr) = inline_attr(cx, instance) { + to_add.push(inline_attr); + } + } + let function_features = function_features .iter() // Convert to LLVMFeatures and filter out unavailable ones @@ -517,6 +527,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let function_features = function_features.iter().map(|s| s.as_str()); let target_features: String = global_features.chain(function_features).intersperse(",").collect(); + if !target_features.is_empty() { to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features)); } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index fc38c4f3e51..326b876e7e6 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -11,7 +11,7 @@ use object::{Object, ObjectSection}; use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; +use rustc_codegen_ssa::{ModuleCodegen, looks_like_rust_object_file}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; use rustc_errors::DiagCtxtHandle; @@ -43,9 +43,7 @@ fn prepare_lto( .map(|symbol| CString::new(symbol.to_owned()).unwrap()) .collect::<Vec<CString>>(); - if cgcx.regular_module_config.instrument_coverage - || cgcx.regular_module_config.pgo_gen.enabled() - { + if cgcx.module_config.instrument_coverage || cgcx.module_config.pgo_gen.enabled() { // These are weak symbols that point to the profile version and the // profile name, which need to be treated as exported so LTO doesn't nix // them. @@ -55,15 +53,15 @@ fn prepare_lto( symbols_below_threshold.extend(PROFILER_WEAK_SYMBOLS.iter().map(|&sym| sym.to_owned())); } - if cgcx.regular_module_config.sanitizer.contains(SanitizerSet::MEMORY) { + if cgcx.module_config.sanitizer.contains(SanitizerSet::MEMORY) { let mut msan_weak_symbols = Vec::new(); // Similar to profiling, preserve weak msan symbol during LTO. - if cgcx.regular_module_config.sanitizer_recover.contains(SanitizerSet::MEMORY) { + if cgcx.module_config.sanitizer_recover.contains(SanitizerSet::MEMORY) { msan_weak_symbols.push(c"__msan_keep_going"); } - if cgcx.regular_module_config.sanitizer_memory_track_origins != 0 { + if cgcx.module_config.sanitizer_memory_track_origins != 0 { msan_weak_symbols.push(c"__msan_track_origins"); } @@ -227,15 +225,9 @@ fn fat_lto( // All the other modules will be serialized and reparsed into the new // context, so this hopefully avoids serializing and parsing the largest // codegen unit. - // - // Additionally use a regular module as the base here to ensure that various - // file copy operations in the backend work correctly. The only other kind - // of module here should be an allocator one, and if your crate is smaller - // than the allocator module then the size doesn't really matter anyway. let costliest_module = in_memory .iter() .enumerate() - .filter(|&(_, module)| module.kind == ModuleKind::Regular) .map(|(i, module)| { let cost = unsafe { llvm::LLVMRustModuleCost(module.module_llvm.llmod()) }; (cost, i) @@ -583,7 +575,7 @@ pub(crate) fn run_pass_manager( thin: bool, ) { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_lto_optimize", &*module.name); - let config = cgcx.config(module.kind); + let config = &cgcx.module_config; // Now we have one massive module inside of llmod. Time to run the // LTO-specific optimization passes that LLVM provides. @@ -745,7 +737,7 @@ pub(crate) fn optimize_thin_module( let module_llvm = ModuleLlvm::parse(cgcx, module_name, thin_module.data(), dcx); let mut module = ModuleCodegen::new_regular(thin_module.name(), module_llvm); // Given that the newly created module lacks a thinlto buffer for embedding, we need to re-add it here. - if cgcx.config(ModuleKind::Regular).embed_bitcode() { + if cgcx.module_config.embed_bitcode() { module.thin_lto_buffer = Some(thin_module.data().to_vec()); } { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 37379586d58..7d0691366e6 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1392,7 +1392,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn call( &mut self, llty: &'ll Type, - fn_attrs: Option<&CodegenFnAttrs>, + fn_call_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: &'ll Value, args: &[&'ll Value], @@ -1409,10 +1409,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } // Emit CFI pointer type membership test - self.cfi_type_test(fn_attrs, fn_abi, instance, llfn); + self.cfi_type_test(fn_call_attrs, fn_abi, instance, llfn); // Emit KCFI operand bundle - let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); + let kcfi_bundle = self.kcfi_operand_bundle(fn_call_attrs, fn_abi, instance, llfn); if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.as_ref()) { bundles.push(kcfi_bundle); } @@ -1429,6 +1429,29 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { c"".as_ptr(), ) }; + + if let Some(instance) = instance { + // Attributes on the function definition being called + let fn_defn_attrs = self.cx.tcx.codegen_fn_attrs(instance.def_id()); + if let Some(fn_call_attrs) = fn_call_attrs + && !fn_call_attrs.target_features.is_empty() + // If there is an inline attribute and a target feature that matches + // we will add the attribute to the callsite otherwise we'll omit + // this and not add the attribute to prevent soundness issues. + && let Some(inlining_rule) = attributes::inline_attr(&self.cx, instance) + && self.cx.tcx.is_target_feature_call_safe( + &fn_call_attrs.target_features, + &fn_defn_attrs.target_features, + ) + { + attributes::apply_to_callsite( + call, + llvm::AttributePlace::Function, + &[inlining_rule], + ); + } + } + if let Some(fn_abi) = fn_abi { fn_abi.apply_attrs_callsite(self, call); } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4fd6110ac4a..257c7b95666 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -217,6 +217,10 @@ pub(crate) unsafe fn create_module<'ll>( // LLVM 22.0 updated the default layout on avr: https://github.com/llvm/llvm-project/pull/153010 target_data_layout = target_data_layout.replace("n8:16", "n8") } + if sess.target.arch == "nvptx64" { + // LLVM 22 updated the NVPTX layout to indicate 256-bit vector load/store: https://github.com/llvm/llvm-project/pull/155198 + target_data_layout = target_data_layout.replace("-i256:256", ""); + } } // Ensure the data-layout values hardcoded remain the defaults. diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 49d3dedbeab..85f71f331a4 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -383,7 +383,9 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { | sym::rotate_left | sym::rotate_right | sym::saturating_add - | sym::saturating_sub => { + | sym::saturating_sub + | sym::unchecked_funnel_shl + | sym::unchecked_funnel_shr => { let ty = args[0].layout.ty; if !ty.is_integral() { tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType { @@ -424,18 +426,26 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::bitreverse => { self.call_intrinsic("llvm.bitreverse", &[llty], &[args[0].immediate()]) } - sym::rotate_left | sym::rotate_right => { - let is_left = name == sym::rotate_left; - let val = args[0].immediate(); - let raw_shift = args[1].immediate(); - // rotate = funnel shift with first two args the same + sym::rotate_left + | sym::rotate_right + | sym::unchecked_funnel_shl + | sym::unchecked_funnel_shr => { + let is_left = name == sym::rotate_left || name == sym::unchecked_funnel_shl; + let lhs = args[0].immediate(); + let (rhs, raw_shift) = + if name == sym::rotate_left || name == sym::rotate_right { + // rotate = funnel shift with first two args the same + (lhs, args[1].immediate()) + } else { + (args[1].immediate(), args[2].immediate()) + }; let llvm_name = format!("llvm.fsh{}", if is_left { 'l' } else { 'r' }); // llvm expects shift to be the same type as the values, but rust // always uses `u32`. - let raw_shift = self.intcast(raw_shift, self.val_ty(val), false); + let raw_shift = self.intcast(raw_shift, self.val_ty(lhs), false); - self.call_intrinsic(llvm_name, &[llty], &[val, val, raw_shift]) + self.call_intrinsic(llvm_name, &[llty], &[lhs, rhs, raw_shift]) } sym::saturating_add | sym::saturating_sub => { let is_add = name == sym::saturating_add; diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 44b9941691a..dd688b8b345 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -40,15 +40,15 @@ codegen_ssa_dynamic_linking_with_lto = .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO codegen_ssa_error_calling_dlltool = - Error calling dlltool '{$dlltool_path}': {$error} + error calling dlltool '{$dlltool_path}': {$error} codegen_ssa_error_creating_import_library = - Error creating import library for {$lib_name}: {$error} + error creating import library for {$lib_name}: {$error} codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error} codegen_ssa_error_writing_def_file = - Error writing .DEF file: {$error} + error writing .DEF file: {$error} codegen_ssa_expected_name_value_pair = expected name value pair @@ -264,9 +264,9 @@ codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at c codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link -codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms. +codegen_ssa_static_library_native_artifacts = link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms. -codegen_ssa_static_library_native_artifacts_to_file = Native artifacts to link against have been written to {$path}. The order and any duplication can be significant on some platforms. +codegen_ssa_static_library_native_artifacts_to_file = native artifacts to link against have been written to {$path}. The order and any duplication can be significant on some platforms. codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` failed: {$status} .note = {$output} @@ -364,13 +364,13 @@ codegen_ssa_unable_to_run = unable to run `{$util}`: {$error} codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error} -codegen_ssa_unable_to_write_debugger_visualizer = Unable to write debugger visualizer file `{$path}`: {$error} +codegen_ssa_unable_to_write_debugger_visualizer = unable to write debugger visualizer file `{$path}`: {$error} codegen_ssa_unexpected_parameter_name = unexpected parameter name .label = expected `{$prefix_nops}` or `{$entry_nops}` codegen_ssa_unknown_archive_kind = - Don't know how to build archive of type: {$kind} + don't know how to build archive of type: {$kind} codegen_ssa_unknown_ctarget_feature = unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}` diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 19c919c0e4e..48b01ea2df1 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -58,6 +58,7 @@ use super::linker::{self, Linker}; use super::metadata::{MetadataPosition, create_wrapper_file}; use super::rpath::{self, RPathConfig}; use super::{apple, versioned_llvm_target}; +use crate::base::needs_allocator_shim_for_linking; use crate::{ CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, looks_like_rust_object_file, }; @@ -2080,9 +2081,17 @@ fn add_local_crate_regular_objects(cmd: &mut dyn Linker, codegen_results: &Codeg } /// Add object files for allocator code linked once for the whole crate tree. -fn add_local_crate_allocator_objects(cmd: &mut dyn Linker, codegen_results: &CodegenResults) { - if let Some(obj) = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref()) { - cmd.add_object(obj); +fn add_local_crate_allocator_objects( + cmd: &mut dyn Linker, + codegen_results: &CodegenResults, + crate_type: CrateType, +) { + if needs_allocator_shim_for_linking(&codegen_results.crate_info.dependency_formats, crate_type) + { + if let Some(obj) = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref()) + { + cmd.add_object(obj); + } } } @@ -2281,7 +2290,7 @@ fn linker_with_args( codegen_results, metadata, ); - add_local_crate_allocator_objects(cmd, codegen_results); + add_local_crate_allocator_objects(cmd, codegen_results, crate_type); // Avoid linking to dynamic libraries unless they satisfy some undefined symbols // at the point at which they are specified on the command line. diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index df1e91b12f9..a2efd420a32 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -11,8 +11,9 @@ use rustc_metadata::{ }; use rustc_middle::bug; use rustc_middle::middle::dependency_format::Linkage; -use rustc_middle::middle::exported_symbols; -use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind}; +use rustc_middle::middle::exported_symbols::{ + self, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, +}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; @@ -22,6 +23,8 @@ use tracing::{debug, warn}; use super::command::Command; use super::symbol_export; +use crate::back::symbol_export::allocator_shim_symbols; +use crate::base::needs_allocator_shim_for_linking; use crate::errors; #[cfg(test)] @@ -1827,7 +1830,7 @@ fn exported_symbols_for_non_proc_macro( let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { // Do not export mangled symbols from cdylibs and don't attempt to export compiler-builtins - // from any cdylib. The latter doesn't work anyway as we use hidden visibility for + // from any dylib. The latter doesn't work anyway as we use hidden visibility for // compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning. if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) { symbols.push(( @@ -1838,6 +1841,14 @@ fn exported_symbols_for_non_proc_macro( } }); + // Mark allocator shim symbols as exported only if they were generated. + if export_threshold == SymbolExportLevel::Rust + && needs_allocator_shim_for_linking(tcx.dependency_formats(()), crate_type) + && tcx.allocator_kind(()).is_some() + { + symbols.extend(allocator_shim_symbols(tcx)); + } + symbols } diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index c95038375a1..f4a9037940a 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -1,6 +1,7 @@ use std::ffi::CString; use std::sync::Arc; +use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::memmap::Mmap; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportLevel}; @@ -8,8 +9,9 @@ use rustc_middle::ty::TyCtxt; use rustc_session::config::{CrateType, Lto}; use tracing::info; -use crate::back::symbol_export::{self, symbol_name_for_instance_in_crate}; +use crate::back::symbol_export::{self, allocator_shim_symbols, symbol_name_for_instance_in_crate}; use crate::back::write::CodegenContext; +use crate::base::allocator_kind_for_codegen; use crate::errors::{DynamicLinkingWithLTO, LtoDisallowed, LtoDylib, LtoProcMacro}; use crate::traits::*; @@ -94,6 +96,19 @@ pub(super) fn exported_symbols_for_lto( .filter_map(|&(s, info): &(ExportedSymbol<'_>, SymbolExportInfo)| { if info.level.is_below_threshold(export_threshold) || info.used { Some(symbol_name_for_instance_in_crate(tcx, s, cnum)) + } else if export_threshold == SymbolExportLevel::C + && info.rustc_std_internal_symbol + && let Some(AllocatorKind::Default) = allocator_kind_for_codegen(tcx) + { + // Export the __rdl_* exports for usage by the allocator shim when not using + // #[global_allocator]. Most of the conditions above are only used to avoid + // unnecessary expensive symbol_name_for_instance_in_crate calls. + let sym = symbol_name_for_instance_in_crate(tcx, s, cnum); + if sym.contains("__rdl_") || sym.contains("__rg_oom") { + Some(sym) + } else { + None + } } else { None } @@ -115,6 +130,11 @@ pub(super) fn exported_symbols_for_lto( } } + // Mark allocator shim symbols as exported only if they were generated. + if export_threshold == SymbolExportLevel::Rust && allocator_kind_for_codegen(tcx).is_some() { + symbols_below_threshold.extend(allocator_shim_symbols(tcx).map(|(name, _kind)| name)); + } + symbols_below_threshold } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index d8a1480e911..b49e67217fb 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -18,7 +18,7 @@ use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::TlsModel; use tracing::debug; -use crate::base::allocator_kind_for_codegen; +use crate::back::symbol_export; fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { crates_export_threshold(tcx.crate_types()) @@ -217,31 +217,6 @@ fn exported_non_generic_symbols_provider_local<'tcx>( )); } - // Mark allocator shim symbols as exported only if they were generated. - if allocator_kind_for_codegen(tcx).is_some() { - for symbol_name in ALLOCATOR_METHODS - .iter() - .map(|method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str())) - .chain([ - mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - mangle_internal_symbol(tcx, OomStrategy::SYMBOL), - mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), - ]) - { - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); - - symbols.push(( - exported_symbol, - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, - used: false, - rustc_std_internal_symbol: true, - }, - )); - } - } - // Sort so we get a stable incr. comp. hash. symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx)); @@ -516,6 +491,31 @@ pub(crate) fn provide(providers: &mut Providers) { upstream_monomorphizations_for_provider; } +pub(crate) fn allocator_shim_symbols( + tcx: TyCtxt<'_>, +) -> impl Iterator<Item = (String, SymbolExportKind)> { + ALLOCATOR_METHODS + .iter() + .map(move |method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str())) + .chain([ + mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), + mangle_internal_symbol(tcx, OomStrategy::SYMBOL), + mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + ]) + .map(move |symbol_name| { + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); + + ( + symbol_export::exporting_symbol_name_for_instance_in_crate( + tcx, + exported_symbol, + LOCAL_CRATE, + ), + SymbolExportKind::Text, + ) + }) +} + fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel { // We export anything that's not mangled at the "C" layer as it probably has // to do with ABI concerns. We do not, however, apply such treatment to diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 92582dcc399..f637e7f58db 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -138,12 +138,23 @@ impl ModuleConfig { let emit_obj = if !should_emit_obj { EmitObj::None - } else if sess.target.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled() { + } else if sess.target.obj_is_bitcode + || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins) + { // This case is selected if the target uses objects as bitcode, or // if linker plugin LTO is enabled. In the linker plugin LTO case // the assumption is that the final link-step will read the bitcode // and convert it to object code. This may be done by either the // native linker or rustc itself. + // + // Note, however, that the linker-plugin-lto requested here is + // explicitly ignored for `#![no_builtins]` crates. These crates are + // specifically ignored by rustc's LTO passes and wouldn't work if + // loaded into the linker. These crates define symbols that LLVM + // lowers intrinsics to, and these symbol dependencies aren't known + // until after codegen. As a result any crate marked + // `#![no_builtins]` is assumed to not participate in LTO and + // instead goes on to generate object code. EmitObj::Bitcode } else if need_bitcode_in_object(tcx) { EmitObj::ObjectCode(BitcodeSection::Full) @@ -322,8 +333,7 @@ pub struct CodegenContext<B: WriteBackendMethods> { pub crate_types: Vec<CrateType>, pub output_filenames: Arc<OutputFilenames>, pub invocation_temp: Option<String>, - pub regular_module_config: Arc<ModuleConfig>, - pub allocator_module_config: Arc<ModuleConfig>, + pub module_config: Arc<ModuleConfig>, pub tm_factory: TargetMachineFactoryFn<B>, pub msvc_imps_needed: bool, pub is_pe_coff: bool, @@ -361,13 +371,6 @@ impl<B: WriteBackendMethods> CodegenContext<B> { pub fn create_dcx(&self) -> DiagCtxt { DiagCtxt::new(Box::new(self.diag_emitter.clone())) } - - pub fn config(&self, kind: ModuleKind) -> &ModuleConfig { - match kind { - ModuleKind::Regular => &self.regular_module_config, - ModuleKind::Allocator => &self.allocator_module_config, - } - } } fn generate_thin_lto_work<B: ExtraBackendMethods>( @@ -431,6 +434,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( backend: B, tcx: TyCtxt<'_>, target_cpu: String, + allocator_module: Option<ModuleCodegen<B::Module>>, ) -> OngoingCodegen<B> { let (coordinator_send, coordinator_receive) = channel(); @@ -454,6 +458,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( coordinator_receive, Arc::new(regular_config), Arc::new(allocator_config), + allocator_module, coordinator_send.clone(), ); @@ -484,7 +489,7 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir"); - for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) { + for module in &compiled_modules.modules { let mut files = Vec::new(); if let Some(object_file_path) = &module.object { files.push((OutputType::Object.extension(), object_file_path.as_path())); @@ -709,15 +714,6 @@ pub(crate) enum WorkItem<B: WriteBackendMethods> { } impl<B: WriteBackendMethods> WorkItem<B> { - fn module_kind(&self) -> ModuleKind { - match *self { - WorkItem::Optimize(ref m) => m.kind, - WorkItem::CopyPostLtoArtifacts(_) | WorkItem::FatLto { .. } | WorkItem::ThinLto(_) => { - ModuleKind::Regular - } - } - } - /// Generate a short description of this work item suitable for use as a thread name. fn short_description(&self) -> String { // `pthread_setname()` on *nix ignores anything beyond the first 15 @@ -798,19 +794,12 @@ pub(crate) fn compute_per_cgu_lto_type( sess_lto: &Lto, opts: &config::Options, sess_crate_types: &[CrateType], - module_kind: ModuleKind, ) -> ComputedLtoType { // If the linker does LTO, we don't have to do it. Note that we // keep doing full LTO, if it is requested, as not to break the // assumption that the output will be a single module. let linker_does_lto = opts.cg.linker_plugin_lto.enabled(); - // When we're automatically doing ThinLTO for multi-codegen-unit - // builds we don't actually want to LTO the allocator modules if - // it shows up. This is due to various linker shenanigans that - // we'll encounter later. - let is_allocator = module_kind == ModuleKind::Allocator; - // We ignore a request for full crate graph LTO if the crate type // is only an rlib, as there is no full crate graph to process, // that'll happen later. @@ -822,7 +811,7 @@ pub(crate) fn compute_per_cgu_lto_type( let is_rlib = matches!(sess_crate_types, [CrateType::Rlib]); match sess_lto { - Lto::ThinLocal if !linker_does_lto && !is_allocator => ComputedLtoType::Thin, + Lto::ThinLocal if !linker_does_lto => ComputedLtoType::Thin, Lto::Thin if !linker_does_lto && !is_rlib => ComputedLtoType::Thin, Lto::Fat if !is_rlib => ComputedLtoType::Fat, _ => ComputedLtoType::No, @@ -832,23 +821,22 @@ pub(crate) fn compute_per_cgu_lto_type( fn execute_optimize_work_item<B: ExtraBackendMethods>( cgcx: &CodegenContext<B>, mut module: ModuleCodegen<B::Module>, - module_config: &ModuleConfig, ) -> WorkItemResult<B> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); - B::optimize(cgcx, dcx, &mut module, module_config); + B::optimize(cgcx, dcx, &mut module, &cgcx.module_config); // After we've done the initial round of optimizations we need to // decide whether to synchronously codegen this module or ship it // back to the coordinator thread for further LTO processing (which // has to wait for all the initial modules to be optimized). - let lto_type = compute_per_cgu_lto_type(&cgcx.lto, &cgcx.opts, &cgcx.crate_types, module.kind); + let lto_type = compute_per_cgu_lto_type(&cgcx.lto, &cgcx.opts, &cgcx.crate_types); // If we're doing some form of incremental LTO then we need to be sure to // save our module to disk first. - let bitcode = if cgcx.config(module.kind).emit_pre_lto_bc { + let bitcode = if cgcx.module_config.emit_pre_lto_bc { let filename = pre_lto_bitcode_filename(&module.name); cgcx.incr_comp_session_dir.as_ref().map(|path| path.join(&filename)) } else { @@ -857,7 +845,7 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>( match lto_type { ComputedLtoType::No => { - let module = B::codegen(cgcx, module, module_config); + let module = B::codegen(cgcx, module, &cgcx.module_config); WorkItemResult::Finished(module) } ComputedLtoType::Thin => { @@ -888,7 +876,6 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>( fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( cgcx: &CodegenContext<B>, module: CachedModuleCodegen, - module_config: &ModuleConfig, ) -> WorkItemResult<B> { let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap(); @@ -948,6 +935,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( } }; + let module_config = &cgcx.module_config; let should_emit_obj = module_config.emit_obj != EmitObj::None; let assembly = load_from_incr_cache(module_config.emit_asm, OutputType::Assembly); let llvm_ir = load_from_incr_cache(module_config.emit_ir, OutputType::LlvmAssembly); @@ -960,7 +948,6 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( WorkItemResult::Finished(CompiledModule { links_from_incr_cache, name: module.name, - kind: ModuleKind::Regular, object, dwarf_object, bytecode, @@ -975,7 +962,6 @@ fn execute_fat_lto_work_item<B: ExtraBackendMethods>( each_linked_rlib_for_lto: &[PathBuf], mut needs_fat_lto: Vec<FatLtoInput<B>>, import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>, - module_config: &ModuleConfig, ) -> WorkItemResult<B> { for (module, wp) in import_only_modules { needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module }) @@ -987,17 +973,16 @@ fn execute_fat_lto_work_item<B: ExtraBackendMethods>( each_linked_rlib_for_lto, needs_fat_lto, ); - let module = B::codegen(cgcx, module, module_config); + let module = B::codegen(cgcx, module, &cgcx.module_config); WorkItemResult::Finished(module) } fn execute_thin_lto_work_item<B: ExtraBackendMethods>( cgcx: &CodegenContext<B>, module: lto::ThinModule<B>, - module_config: &ModuleConfig, ) -> WorkItemResult<B> { let module = B::optimize_thin(cgcx, module); - let module = B::codegen(cgcx, module, module_config); + let module = B::codegen(cgcx, module, &cgcx.module_config); WorkItemResult::Finished(module) } @@ -1082,6 +1067,7 @@ fn start_executing_work<B: ExtraBackendMethods>( coordinator_receive: Receiver<Message<B>>, regular_config: Arc<ModuleConfig>, allocator_config: Arc<ModuleConfig>, + allocator_module: Option<ModuleCodegen<B::Module>>, tx_to_llvm_workers: Sender<Message<B>>, ) -> thread::JoinHandle<Result<CompiledModules, ()>> { let coordinator_send = tx_to_llvm_workers; @@ -1146,8 +1132,7 @@ fn start_executing_work<B: ExtraBackendMethods>( expanded_args: tcx.sess.expanded_args.clone(), diag_emitter: shared_emitter.clone(), output_filenames: Arc::clone(tcx.output_filenames(())), - regular_module_config: regular_config, - allocator_module_config: allocator_config, + module_config: regular_config, tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features), msvc_imps_needed: msvc_imps_needed(tcx), is_pe_coff: tcx.sess.target.is_like_windows, @@ -1162,6 +1147,11 @@ fn start_executing_work<B: ExtraBackendMethods>( invocation_temp: sess.invocation_temp.clone(), }; + let compiled_allocator_module = allocator_module.map(|mut allocator_module| { + B::optimize(&cgcx, tcx.sess.dcx(), &mut allocator_module, &allocator_config); + B::codegen(&cgcx, allocator_module, &allocator_config) + }); + // This is the "main loop" of parallel work happening for parallel codegen. // It's here that we manage parallelism, schedule work, and work with // messages coming from clients. @@ -1301,7 +1291,6 @@ fn start_executing_work<B: ExtraBackendMethods>( // This is where we collect codegen units that have gone all the way // through codegen and LLVM. let mut compiled_modules = vec![]; - let mut compiled_allocator_module = None; let mut needs_fat_lto = Vec::new(); let mut needs_thin_lto = Vec::new(); let mut lto_import_only_modules = Vec::new(); @@ -1575,15 +1564,7 @@ fn start_executing_work<B: ExtraBackendMethods>( match result { Ok(WorkItemResult::Finished(compiled_module)) => { - match compiled_module.kind { - ModuleKind::Regular => { - compiled_modules.push(compiled_module); - } - ModuleKind::Allocator => { - assert!(compiled_allocator_module.is_none()); - compiled_allocator_module = Some(compiled_module); - } - } + compiled_modules.push(compiled_module); } Ok(WorkItemResult::NeedsFatLto(fat_lto_input)) => { assert!(!started_lto); @@ -1711,45 +1692,38 @@ fn spawn_work<'a, B: ExtraBackendMethods>( let cgcx = cgcx.clone(); B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || { - let result = std::panic::catch_unwind(AssertUnwindSafe(|| { - let module_config = cgcx.config(work.module_kind()); - - match work { - WorkItem::Optimize(m) => { - let _timer = - cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name); - execute_optimize_work_item(&cgcx, m, module_config) - } - WorkItem::CopyPostLtoArtifacts(m) => { - let _timer = cgcx.prof.generic_activity_with_arg( - "codegen_copy_artifacts_from_incr_cache", - &*m.name, - ); - execute_copy_from_cache_work_item(&cgcx, m, module_config) - } - WorkItem::FatLto { - exported_symbols_for_lto, - each_linked_rlib_for_lto, + let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work { + WorkItem::Optimize(m) => { + let _timer = + cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name); + execute_optimize_work_item(&cgcx, m) + } + WorkItem::CopyPostLtoArtifacts(m) => { + let _timer = cgcx + .prof + .generic_activity_with_arg("codegen_copy_artifacts_from_incr_cache", &*m.name); + execute_copy_from_cache_work_item(&cgcx, m) + } + WorkItem::FatLto { + exported_symbols_for_lto, + each_linked_rlib_for_lto, + needs_fat_lto, + import_only_modules, + } => { + let _timer = + cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", "everything"); + execute_fat_lto_work_item( + &cgcx, + &exported_symbols_for_lto, + &each_linked_rlib_for_lto, needs_fat_lto, import_only_modules, - } => { - let _timer = cgcx - .prof - .generic_activity_with_arg("codegen_module_perform_lto", "everything"); - execute_fat_lto_work_item( - &cgcx, - &exported_symbols_for_lto, - &each_linked_rlib_for_lto, - needs_fat_lto, - import_only_modules, - module_config, - ) - } - WorkItem::ThinLto(m) => { - let _timer = - cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()); - execute_thin_lto_work_item(&cgcx, m, module_config) - } + ) + } + WorkItem::ThinLto(m) => { + let _timer = + cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()); + execute_thin_lto_work_item(&cgcx, m) } })); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 8abaf201aba..a9a2ae1b3db 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -17,6 +17,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{ItemId, Target}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; +use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::exported_symbols::{self, SymbolExportKind}; use rustc_middle::middle::lang_items; use rustc_middle::mir::BinOp; @@ -45,9 +46,7 @@ use crate::meth::load_vtable; use crate::mir::operand::OperandValue; use crate::mir::place::PlaceRef; use crate::traits::*; -use crate::{ - CachedModuleCodegen, CodegenLintLevels, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir, -}; +use crate::{CachedModuleCodegen, CodegenLintLevels, CrateInfo, ModuleCodegen, errors, meth, mir}; pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate { match (op, signed) { @@ -630,14 +629,30 @@ pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option<AllocatorKind> { // If the crate doesn't have an `allocator_kind` set then there's definitely // no shim to generate. Otherwise we also check our dependency graph for all // our output crate types. If anything there looks like its a `Dynamic` - // linkage, then it's already got an allocator shim and we'll be using that - // one instead. If nothing exists then it's our job to generate the - // allocator! - let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| { + // linkage for all crate types we may link as, then it's already got an + // allocator shim and we'll be using that one instead. If nothing exists + // then it's our job to generate the allocator! If crate types disagree + // about whether an allocator shim is necessary or not, we generate one + // and let needs_allocator_shim_for_linking decide at link time whether or + // not to use it for any particular linker invocation. + let all_crate_types_any_dynamic_crate = tcx.dependency_formats(()).iter().all(|(_, list)| { use rustc_middle::middle::dependency_format::Linkage; list.iter().any(|&linkage| linkage == Linkage::Dynamic) }); - if any_dynamic_crate { None } else { tcx.allocator_kind(()) } + if all_crate_types_any_dynamic_crate { None } else { tcx.allocator_kind(()) } +} + +/// Decide if this particular crate type needs an allocator shim linked in. +/// This may return true even when allocator_kind_for_codegen returns false. In +/// this case no allocator shim shall be linked. +pub(crate) fn needs_allocator_shim_for_linking( + dependency_formats: &Dependencies, + crate_type: CrateType, +) -> bool { + use rustc_middle::middle::dependency_format::Linkage; + let any_dynamic_crate = + dependency_formats[&crate_type].iter().any(|&linkage| linkage == Linkage::Dynamic); + !any_dynamic_crate } pub fn codegen_crate<B: ExtraBackendMethods>( @@ -647,7 +662,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( ) -> OngoingCodegen<B> { // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu); + let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, None); ongoing_codegen.codegen_finished(tcx); @@ -678,7 +693,27 @@ pub fn codegen_crate<B: ExtraBackendMethods>( } } - let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu); + // Codegen an allocator shim, if necessary. + let allocator_module = if let Some(kind) = allocator_kind_for_codegen(tcx) { + let llmod_id = + cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); + + tcx.sess.time("write_allocator_module", || { + let module = backend.codegen_allocator( + tcx, + &llmod_id, + kind, + // If allocator_kind is Some then alloc_error_handler_kind must + // also be Some. + tcx.alloc_error_handler_kind(()).unwrap(), + ); + Some(ModuleCodegen::new_allocator(llmod_id, module)) + }) + } else { + None + }; + + let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu, allocator_module); // For better throughput during parallel processing by LLVM, we used to sort // CGUs largest to smallest. This would lead to better thread utilization @@ -795,35 +830,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>( } } - // Codegen an allocator shim, if necessary. - // Do this last to ensure the LLVM_passes timer doesn't start while no CGUs have been codegened - // yet for the backend to optimize. - if let Some(kind) = allocator_kind_for_codegen(tcx) { - let llmod_id = - cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); - let module_llvm = tcx.sess.time("write_allocator_module", || { - backend.codegen_allocator( - tcx, - &llmod_id, - kind, - // If allocator_kind is Some then alloc_error_handler_kind must - // also be Some. - tcx.alloc_error_handler_kind(()).unwrap(), - ) - }); - - ongoing_codegen.wait_for_signal_to_codegen_item(); - ongoing_codegen.check_for_errors(tcx.sess); - - // These modules are generally cheap and won't throw off scheduling. - let cost = 0; - submit_codegened_module_to_llvm( - &ongoing_codegen.coordinator, - ModuleCodegen::new_allocator(llmod_id, module_llvm), - cost, - ); - } - ongoing_codegen.codegen_finished(tcx); // Since the main thread is sometimes blocked during codegen, we keep track @@ -1118,12 +1124,7 @@ pub fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> // We can re-use either the pre- or the post-thinlto state. If no LTO is // being performed then we can use post-LTO artifacts, otherwise we must // reuse pre-LTO artifacts - match compute_per_cgu_lto_type( - &tcx.sess.lto(), - &tcx.sess.opts, - tcx.crate_types(), - ModuleKind::Regular, - ) { + match compute_per_cgu_lto_type(&tcx.sess.lto(), &tcx.sess.opts, tcx.crate_types()) { ComputedLtoType::No => CguReuse::PostLto, _ => CguReuse::PreLto, } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 961bb788149..008340e614d 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -428,9 +428,16 @@ fn check_result( // llvm/llvm-project#70563). if !codegen_fn_attrs.target_features.is_empty() && matches!(codegen_fn_attrs.inline, InlineAttr::Always) + && !tcx.features().target_feature_inline_always() && let Some(span) = interesting_spans.inline { - tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`"); + feature_err( + tcx.sess, + sym::target_feature_inline_always, + span, + "cannot use `#[inline(always)]` with `#[target_feature]`", + ) + .emit(); } // warn that inline has no effect when no_sanitize is present diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index fe0500a5d4c..5b90ffaa056 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -120,7 +120,6 @@ impl<M> ModuleCodegen<M> { CompiledModule { name: self.name.clone(), - kind: self.kind, object, dwarf_object, bytecode, @@ -134,7 +133,6 @@ impl<M> ModuleCodegen<M> { #[derive(Debug, Encodable, Decodable)] pub struct CompiledModule { pub name: String, - pub kind: ModuleKind, pub object: Option<PathBuf>, pub dwarf_object: Option<PathBuf>, pub bytecode: Option<PathBuf>, diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 60518dafbf2..700d7c26752 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -457,7 +457,7 @@ const_eval_validation_failure = it is undefined behavior to use this value const_eval_validation_failure_note = - The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. const_eval_validation_front_matter_invalid_value = constructing invalid value const_eval_validation_front_matter_invalid_value_with_path = constructing invalid value at {$path} diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index 2c6a0291ac2..b62cdc35f51 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -14,7 +14,7 @@ driver_impl_ice_version = rustc {$version} running on {$triple} driver_impl_rlink_corrupt_file = corrupt metadata encountered in `{$file}` -driver_impl_rlink_empty_version_number = The input does not contain version number +driver_impl_rlink_empty_version_number = the input does not contain version number driver_impl_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}` @@ -24,6 +24,6 @@ driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc ver driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}` -driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file +driver_impl_rlink_wrong_file_type = the input does not look like a .rlink file driver_impl_unstable_feature_usage = cannot dump feature usage metrics: {$error} diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 71fc54f0d33..a56e0f3fae1 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1160,7 +1160,7 @@ impl<'a> DiagCtxtHandle<'a> { // - It's only produce with JSON output. // - It's not emitted the usual way, via `emit_diagnostic`. // - The `$message_type` field is "unused_externs" rather than the usual - // "diagnosic". + // "diagnostic". // // We count it as a lint error because it has a lint level. The value // of `loud` (which comes from "unused-externs" or diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 0324057e331..ab8e059b7b7 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -77,7 +77,7 @@ use std::rc::Rc; pub(crate) use NamedMatch::*; pub(crate) use ParseResult::*; -use rustc_ast::token::{self, DocComment, NonterminalKind, Token}; +use rustc_ast::token::{self, DocComment, NonterminalKind, Token, TokenKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_lint_defs::pluralize; @@ -397,7 +397,23 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { { ident1.name == ident2.name && is_raw1 == is_raw2 } else { - t1.kind == t2.kind + // Note: we SHOULD NOT use `t1.kind == t2.kind` here, and we should instead compare the + // tokens using the special comparison logic below. + // It makes sure that variants containing `InvisibleOrigin` will + // never compare equal to one another. + // + // When we had AST-based nonterminals we couldn't compare them, and the + // old `Nonterminal` type had an `eq` that always returned false, + // resulting in this restriction: + // <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> + // This comparison logic emulates that behaviour. We could consider lifting this + // restriction now but there are still cases involving invisible + // delimiters that make it harder than it first appears. + match (t1.kind, t2.kind) { + (TokenKind::OpenInvisible(_) | TokenKind::CloseInvisible(_), _) + | (_, TokenKind::OpenInvisible(_) | TokenKind::CloseInvisible(_)) => false, + (a, b) => a == b, + } } } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 573e9aab055..4f35bf63a1a 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -642,6 +642,8 @@ declare_features! ( (unstable, super_let, "1.88.0", Some(139076)), /// Allows subtrait items to shadow supertrait items. (unstable, supertrait_item_shadowing, "1.86.0", Some(89151)), + /// Allows the use of target_feature when a function is marked inline(always). + (unstable, target_feature_inline_always, "CURRENT_RUSTC_VERSION", Some(145574)), /// Allows using `#[thread_local]` on `static` items. (unstable, thread_local, "1.0.0", Some(29594)), /// Allows defining `trait X = A + B;` alias items. diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index cfc6bc2f3a0..aa2d27ab809 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -449,6 +449,9 @@ pub(crate) fn check_intrinsic_type( } sym::unchecked_shl | sym::unchecked_shr => (2, 0, vec![param(0), param(1)], param(0)), sym::rotate_left | sym::rotate_right => (1, 0, vec![param(0), tcx.types.u32], param(0)), + sym::unchecked_funnel_shl | sym::unchecked_funnel_shr => { + (1, 0, vec![param(0), param(0), tcx.types.u32], param(0)) + } sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => { (1, 0, vec![param(0), param(0)], param(0)) } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index f5770b7312d..2ba7ed46f92 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -490,12 +490,8 @@ fn resolve_local<'tcx>( // // Iterate up to the enclosing destruction scope to find the same scope that will also // be used for the result of the block itself. - while let Some(s) = visitor.cx.var_parent { - let parent = visitor.scope_tree.parent_map.get(&s).cloned(); - if let Some(Scope { data: ScopeData::Destruction, .. }) = parent { - break; - } - visitor.cx.var_parent = parent; + if let Some(inner_scope) = visitor.cx.var_parent { + (visitor.cx.var_parent, _) = visitor.scope_tree.default_temporary_scope(inner_scope) } } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 8f131f45bbd..4c820b8877b 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -13,7 +13,7 @@ use rustc_lint::LintStore; use rustc_middle::ty; use rustc_middle::ty::CurrentGcx; use rustc_middle::util::Providers; -use rustc_parse::new_parser_from_source_str; +use rustc_parse::new_parser_from_simple_source_str; use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; @@ -68,7 +68,7 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg { }; } - match new_parser_from_source_str(&psess, filename, s.to_string()) { + match new_parser_from_simple_source_str(&psess, filename, s.to_string()) { Ok(mut parser) => match parser.parse_meta_item(AllowLeadingUnsafe::No) { Ok(meta_item) if parser.token == token::Eof => { if meta_item.path.segments.len() != 1 { @@ -166,7 +166,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`") }; - let mut parser = match new_parser_from_source_str(&psess, filename, s.to_string()) { + let mut parser = match new_parser_from_simple_source_str(&psess, filename, s.to_string()) { Ok(parser) => parser, Err(errs) => { errs.into_iter().for_each(|err| err.cancel()); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index d10b1920343..c29ab569f47 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -331,24 +331,37 @@ pub fn is_whitespace(c: char) -> bool { matches!( c, - // Usual ASCII suspects - '\u{0009}' // \t - | '\u{000A}' // \n + // End-of-line characters + | '\u{000A}' // line feed (\n) | '\u{000B}' // vertical tab | '\u{000C}' // form feed - | '\u{000D}' // \r - | '\u{0020}' // space - - // NEXT LINE from latin1 - | '\u{0085}' + | '\u{000D}' // carriage return (\r) + | '\u{0085}' // next line (from latin1) + | '\u{2028}' // LINE SEPARATOR + | '\u{2029}' // PARAGRAPH SEPARATOR - // Bidi markers + // `Default_Ignorable_Code_Point` characters | '\u{200E}' // LEFT-TO-RIGHT MARK | '\u{200F}' // RIGHT-TO-LEFT MARK - // Dedicated whitespace characters from Unicode - | '\u{2028}' // LINE SEPARATOR - | '\u{2029}' // PARAGRAPH SEPARATOR + // Horizontal space characters + | '\u{0009}' // tab (\t) + | '\u{0020}' // space + ) +} + +/// True if `c` is considered horizontal whitespace according to Rust language definition. +pub fn is_horizontal_whitespace(c: char) -> bool { + // This is Pattern_White_Space. + // + // Note that this set is stable (ie, it doesn't change with different + // Unicode versions), so it's ok to just hard-code the values. + + matches!( + c, + // Horizontal space characters + '\u{0009}' // tab (\t) + | '\u{0020}' // space ) } @@ -538,7 +551,7 @@ impl Cursor<'_> { debug_assert!(length_opening >= 3); // whitespace between the opening and the infostring. - self.eat_while(|ch| ch != '\n' && is_whitespace(ch)); + self.eat_while(|ch| ch != '\n' && is_horizontal_whitespace(ch)); // copied from `eat_identifier`, but allows `-` and `.` in infostring to allow something like // `---Cargo.toml` as a valid opener @@ -547,7 +560,7 @@ impl Cursor<'_> { self.eat_while(|c| is_id_continue(c) || c == '-' || c == '.'); } - self.eat_while(|ch| ch != '\n' && is_whitespace(ch)); + self.eat_while(|ch| ch != '\n' && is_horizontal_whitespace(ch)); let invalid_infostring = self.first() != '\n'; let mut found = false; @@ -588,7 +601,7 @@ impl Cursor<'_> { // on a standalone line. Might be wrong. while let Some(closing) = rest.find("---") { let preceding_chars_start = rest[..closing].rfind("\n").map_or(0, |i| i + 1); - if rest[preceding_chars_start..closing].chars().all(is_whitespace) { + if rest[preceding_chars_start..closing].chars().all(is_horizontal_whitespace) { // candidate found potential_closing = Some(closing); break; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index ce92263babd..b79075ac09b 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -5141,3 +5141,57 @@ declare_lint! { "detects tail calls of functions marked with `#[track_caller]`", @feature_gate = explicit_tail_calls; } +declare_lint! { + /// The `inline_always_mismatching_target_features` lint will trigger when a + /// function with the `#[inline(always)]` and `#[target_feature(enable = "...")]` + /// attributes is called and cannot be inlined due to missing target features in the caller. + /// + /// ### Example + /// + /// ```rust,ignore (fails on x86_64) + /// #[inline(always)] + /// #[target_feature(enable = "fp16")] + /// unsafe fn callee() { + /// // operations using fp16 types + /// } + /// + /// // Caller does not enable the required target feature + /// fn caller() { + /// unsafe { callee(); } + /// } + /// + /// fn main() { + /// caller(); + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: call to `#[inline(always)]`-annotated `callee` requires the same target features. Function will not have `alwaysinline` attribute applied + /// --> $DIR/builtin.rs:5192:14 + /// | + /// 10 | unsafe { callee(); } + /// | ^^^^^^^^ + /// | + /// note: `fp16` target feature enabled in `callee` here but missing from `caller` + /// --> $DIR/builtin.rs:5185:1 + /// | + /// 3 | #[target_feature(enable = "fp16")] + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// 4 | unsafe fn callee() { + /// | ------------------ + /// = note: `#[warn(inline_always_mismatching_target_features)]` on by default + /// warning: 1 warning emitted + /// ``` + /// + /// ### Explanation + /// + /// Inlining a function with a target feature attribute into a caller that + /// lacks the corresponding target feature can lead to unsound behavior. + /// LLVM may select the wrong instructions or registers, or reorder + /// operations, potentially resulting in runtime errors. + pub INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES, + Warn, + r#"detects when a function annotated with `#[inline(always)]` and `#[target_feature(enable = "..")]` is inlined into a caller without the required target feature"#, +} diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 866736f74a0..8b4503073b0 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -82,7 +82,7 @@ pub enum TargetFeatureKind { Forced, } -#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, HashStable)] pub struct TargetFeature { /// The name of the target feature (e.g. "avx") pub name: Symbol, diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 857d041224f..5367e5edd49 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -299,4 +299,43 @@ impl ScopeTree { true } + + /// Returns the scope of non-lifetime-extended temporaries within a given scope, as well as + /// whether we've recorded a potential backwards-incompatible change to lint on. + /// Returns `None` when no enclosing temporary scope is found, such as for static items. + pub fn default_temporary_scope(&self, inner: Scope) -> (Option<Scope>, Option<Scope>) { + let mut id = inner; + let mut backwards_incompatible = None; + + while let Some(&p) = self.parent_map.get(&id) { + match p.data { + ScopeData::Destruction => { + debug!("temporary_scope({inner:?}) = {id:?} [enclosing]"); + return (Some(id), backwards_incompatible); + } + ScopeData::IfThenRescope | ScopeData::MatchGuard => { + debug!("temporary_scope({inner:?}) = {p:?} [enclosing]"); + return (Some(p), backwards_incompatible); + } + ScopeData::Node + | ScopeData::CallSite + | ScopeData::Arguments + | ScopeData::IfThen + | ScopeData::Remainder(_) => { + // If we haven't already passed through a backwards-incompatible node, + // then check if we are passing through one now and record it if so. + // This is for now only working for cases where a temporary lifetime is + // *shortened*. + if backwards_incompatible.is_none() { + backwards_incompatible = + self.backwards_incompatible_scope.get(&p.local_id).copied(); + } + id = p + } + } + } + + debug!("temporary_scope({inner:?}) = None"); + (None, backwards_incompatible) + } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 72ab6ac612c..97c8a0336c2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -738,8 +738,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) } - type ProbeRef = &'tcx inspect::Probe<TyCtxt<'tcx>>; - fn mk_probe_ref(self, probe: inspect::Probe<Self>) -> &'tcx inspect::Probe<TyCtxt<'tcx>> { + type Probe = &'tcx inspect::Probe<TyCtxt<'tcx>>; + fn mk_probe(self, probe: inspect::Probe<Self>) -> &'tcx inspect::Probe<TyCtxt<'tcx>> { self.arena.alloc(probe) } fn evaluate_root_goal_for_proof_tree_raw( diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs index 7dfe2d28051..8b92e48ed1a 100644 --- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs +++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs @@ -35,41 +35,8 @@ impl RvalueScopes { // if there's one. Static items, for instance, won't // have an enclosing scope, hence no scope will be // returned. - let mut id = Scope { local_id: expr_id, data: ScopeData::Node }; - let mut backwards_incompatible = None; - - while let Some(&p) = region_scope_tree.parent_map.get(&id) { - match p.data { - ScopeData::Destruction => { - debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]"); - return (Some(id), backwards_incompatible); - } - ScopeData::IfThenRescope | ScopeData::MatchGuard => { - debug!("temporary_scope({expr_id:?}) = {p:?} [enclosing]"); - return (Some(p), backwards_incompatible); - } - ScopeData::Node - | ScopeData::CallSite - | ScopeData::Arguments - | ScopeData::IfThen - | ScopeData::Remainder(_) => { - // If we haven't already passed through a backwards-incompatible node, - // then check if we are passing through one now and record it if so. - // This is for now only working for cases where a temporary lifetime is - // *shortened*. - if backwards_incompatible.is_none() { - backwards_incompatible = region_scope_tree - .backwards_incompatible_scope - .get(&p.local_id) - .copied(); - } - id = p - } - } - } - - debug!("temporary_scope({expr_id:?}) = None"); - (None, backwards_incompatible) + region_scope_tree + .default_temporary_scope(Scope { local_id: expr_id, data: ScopeData::Node }) } /// Make an association between a sub-expression and an extended lifetime diff --git a/compiler/rustc_mir_transform/src/check_inline_always_target_features.rs b/compiler/rustc_mir_transform/src/check_inline_always_target_features.rs new file mode 100644 index 00000000000..abad28f0a8f --- /dev/null +++ b/compiler/rustc_mir_transform/src/check_inline_always_target_features.rs @@ -0,0 +1,88 @@ +use rustc_hir::attrs::InlineAttr; +use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind}; +use rustc_middle::mir::{Body, TerminatorKind}; +use rustc_middle::ty::{self, TyCtxt}; + +use crate::pass_manager::MirLint; + +pub(super) struct CheckInlineAlwaysTargetFeature; + +impl<'tcx> MirLint<'tcx> for CheckInlineAlwaysTargetFeature { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + check_inline_always_target_features(tcx, body) + } +} + +/// `#[target_feature]`-annotated functions can be marked `#[inline]` and will only be inlined if +/// the target features match (as well as all of the other inlining heuristics). `#[inline(always)]` +/// will always inline regardless of matching target features, which can result in errors from LLVM. +/// However, it is desirable to be able to always annotate certain functions (e.g. SIMD intrinsics) +/// as `#[inline(always)]` but check the target features match in Rust to avoid the LLVM errors. +/// +/// We check the caller and callee target features to ensure that this can +/// be done or emit a lint. +#[inline] +fn check_inline_always_target_features<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let caller_def_id = body.source.def_id().expect_local(); + if !tcx.def_kind(caller_def_id).has_codegen_attrs() { + return; + } + + let caller_codegen_fn_attrs = tcx.codegen_fn_attrs(caller_def_id); + + for bb in body.basic_blocks.iter() { + let terminator = bb.terminator(); + match &terminator.kind { + TerminatorKind::Call { func, .. } | TerminatorKind::TailCall { func, .. } => { + let fn_ty = func.ty(body, tcx); + let ty::FnDef(callee_def_id, _) = *fn_ty.kind() else { + continue; + }; + + if !tcx.def_kind(callee_def_id).has_codegen_attrs() { + continue; + } + let callee_codegen_fn_attrs = tcx.codegen_fn_attrs(callee_def_id); + if callee_codegen_fn_attrs.inline != InlineAttr::Always + || callee_codegen_fn_attrs.target_features.is_empty() + { + continue; + } + + // Scan the users defined target features and ensure they + // match the caller. + if tcx.is_target_feature_call_safe( + &callee_codegen_fn_attrs.target_features, + &caller_codegen_fn_attrs + .target_features + .iter() + .cloned() + .chain(tcx.sess.target_features.iter().map(|feat| TargetFeature { + name: *feat, + kind: TargetFeatureKind::Implied, + })) + .collect::<Vec<_>>(), + ) { + continue; + } + + let callee_only: Vec<_> = callee_codegen_fn_attrs + .target_features + .iter() + .filter(|it| !caller_codegen_fn_attrs.target_features.contains(it)) + .filter(|it| !matches!(it.kind, TargetFeatureKind::Implied)) + .map(|it| it.name.as_str()) + .collect(); + + crate::errors::emit_inline_always_target_feature_diagnostic( + tcx, + terminator.source_info.span, + callee_def_id, + caller_def_id.into(), + &callee_only, + ); + } + _ => (), + } + } +} diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index ad9635aae33..775f5f9a7cf 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -2,6 +2,7 @@ use rustc_errors::codes::*; use rustc_errors::{Diag, LintDiagnostic}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::AssertKind; +use rustc_middle::query::Key; use rustc_middle::ty::TyCtxt; use rustc_session::lint::{self, Lint}; use rustc_span::def_id::DefId; @@ -9,6 +10,46 @@ use rustc_span::{Ident, Span, Symbol}; use crate::fluent_generated as fluent; +/// Emit diagnostic for calls to `#[inline(always)]`-annotated functions with a +/// `#[target_feature]` attribute where the caller enables a different set of target features. +pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + call_span: Span, + callee_def_id: DefId, + caller_def_id: DefId, + callee_only: &[&'a str], +) { + let callee = tcx.def_path_str(callee_def_id); + let caller = tcx.def_path_str(caller_def_id); + + tcx.node_span_lint( + lint::builtin::INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES, + tcx.local_def_id_to_hir_id(caller_def_id.as_local().unwrap()), + call_span, + |lint| { + lint.primary_message(format!( + "call to `#[inline(always)]`-annotated `{callee}` \ + requires the same target features to be inlined" + )); + lint.note("function will not be inlined"); + + lint.note(format!( + "the following target features are on `{callee}` but missing from `{caller}`: {}", + callee_only.join(", ") + )); + lint.span_note(callee_def_id.default_span(tcx), format!("`{callee}` is defined here")); + + let feats = callee_only.join(","); + lint.span_suggestion( + tcx.def_span(caller_def_id).shrink_to_lo(), + format!("add `#[target_feature]` attribute to `{caller}`"), + format!("#[target_feature(enable = \"{feats}\")]\n"), + lint::Applicability::MaybeIncorrect, + ); + }, + ); +} + #[derive(LintDiagnostic)] #[diag(mir_transform_unconditional_recursion)] #[help] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 8f319e64916..1663dfa744f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -117,6 +117,7 @@ declare_passes! { mod add_subtyping_projections : Subtyper; mod check_inline : CheckForceInline; mod check_call_recursion : CheckCallRecursion, CheckDropRecursion; + mod check_inline_always_target_features: CheckInlineAlwaysTargetFeature; mod check_alignment : CheckAlignment; mod check_enums : CheckEnums; mod check_const_item_mutation : CheckConstItemMutation; @@ -384,6 +385,9 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { // MIR-level lints. &Lint(check_inline::CheckForceInline), &Lint(check_call_recursion::CheckCallRecursion), + // Check callee's target features match callers target features when + // using `#[inline(always)]` + &Lint(check_inline_always_target_features::CheckInlineAlwaysTargetFeature), &Lint(check_packed_ref::CheckPackedRef), &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 31106a74527..443aebbdb4d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1275,7 +1275,7 @@ pub fn evaluate_root_goal_for_proof_tree_raw_provider< >( cx: I, canonical_goal: CanonicalInput<I>, -) -> (QueryResult<I>, I::ProbeRef) { +) -> (QueryResult<I>, I::Probe) { let mut inspect = inspect::ProofTreeBuilder::new(); let canonical_result = SearchGraph::<D>::evaluate_root_goal_for_proof_tree( cx, @@ -1284,7 +1284,7 @@ pub fn evaluate_root_goal_for_proof_tree_raw_provider< &mut inspect, ); let final_revision = inspect.unwrap(); - (canonical_result, cx.mk_probe_ref(final_revision)) + (canonical_result, cx.mk_probe(final_revision)) } /// Evaluate a goal to build a proof tree. diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 4ca2f57bd87..77dd313d9b8 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -58,7 +58,7 @@ parse_async_use_order_incorrect = the order of `use` and `async` is incorrect parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns .suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @` -parse_at_in_struct_pattern = Unexpected `@` in struct pattern +parse_at_in_struct_pattern = unexpected `@` in struct pattern .note = struct patterns use `field: pattern` syntax to bind to fields .help = consider replacing `new_name @ field_name` with `field_name: new_name` if that is what you intended diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 9792240a548..e3bd6a9a327 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -6,7 +6,7 @@ use rustc_ast::util::unicode::{TEXT_FLOW_CONTROL_CHARS, contains_text_flow_contr use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey}; use rustc_lexer::{ - Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_whitespace, + Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_horizontal_whitespace, }; use rustc_literal_escaper::{EscapeError, Mode, check_for_errors}; use rustc_session::lint::BuiltinLintDiag; @@ -597,7 +597,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let last_line_start = within.rfind('\n').map_or(0, |i| i + 1); let last_line = &within[last_line_start..]; - let last_line_trimmed = last_line.trim_start_matches(is_whitespace); + let last_line_trimmed = last_line.trim_start_matches(is_horizontal_whitespace); let last_line_start_pos = frontmatter_opening_end_pos + BytePos(last_line_start as u32); let frontmatter_span = self.mk_sp(frontmatter_opening_pos, self.pos); @@ -640,7 +640,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { }); } - if !rest.trim_matches(is_whitespace).is_empty() { + if !rest.trim_matches(is_horizontal_whitespace).is_empty() { let span = self.mk_sp(last_line_start_pos, self.pos); self.dcx().emit_err(errors::FrontmatterExtraCharactersAfterClose { span }); } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 197333d942d..b790966acfd 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -62,7 +62,20 @@ pub fn new_parser_from_source_str( source: String, ) -> Result<Parser<'_>, Vec<Diag<'_>>> { let source_file = psess.source_map().new_source_file(name, source); - new_parser_from_source_file(psess, source_file) + new_parser_from_source_file(psess, source_file, FrontmatterAllowed::Yes) +} + +/// Creates a new parser from a simple (no frontmatter) source string. +/// +/// On failure, the errors must be consumed via `unwrap_or_emit_fatal`, `emit`, `cancel`, +/// etc., otherwise a panic will occur when they are dropped. +pub fn new_parser_from_simple_source_str( + psess: &ParseSess, + name: FileName, + source: String, +) -> Result<Parser<'_>, Vec<Diag<'_>>> { + let source_file = psess.source_map().new_source_file(name, source); + new_parser_from_source_file(psess, source_file, FrontmatterAllowed::No) } /// Creates a new parser from a filename. On failure, the errors must be consumed via @@ -96,7 +109,7 @@ pub fn new_parser_from_file<'a>( } err.emit(); }); - new_parser_from_source_file(psess, source_file) + new_parser_from_source_file(psess, source_file, FrontmatterAllowed::Yes) } pub fn utf8_error<E: EmissionGuarantee>( @@ -147,9 +160,10 @@ pub fn utf8_error<E: EmissionGuarantee>( fn new_parser_from_source_file( psess: &ParseSess, source_file: Arc<SourceFile>, + frontmatter_allowed: FrontmatterAllowed, ) -> Result<Parser<'_>, Vec<Diag<'_>>> { let end_pos = source_file.end_position(); - let stream = source_file_to_stream(psess, source_file, None, FrontmatterAllowed::Yes)?; + let stream = source_file_to_stream(psess, source_file, None, frontmatter_allowed)?; let mut parser = Parser::new(psess, stream, None); if parser.token == token::Eof { parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None); diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 498d9a405fa..afd08319738 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -687,6 +687,7 @@ passes_unused_var_maybe_capture_ref = unused variable: `{$name}` passes_unused_var_remove_field = unused variable: `{$name}` passes_unused_var_remove_field_suggestion = try removing the field +passes_unused_var_typo = you might have meant to pattern match on the similarly named {$kind} `{$item_name}` passes_unused_variable_args_in_macro = `{$name}` is captured in macro and introduced a unused variable diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 680e2a26d84..23dcabef1a1 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1367,6 +1367,22 @@ pub(crate) struct UnusedVarRemoveFieldSugg { #[note] pub(crate) struct UnusedVarAssignedOnly { pub name: String, + #[subdiagnostic] + pub typo: Option<PatternTypo>, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + passes_unused_var_typo, + style = "verbose", + applicability = "machine-applicable" +)] +pub(crate) struct PatternTypo { + #[suggestion_part(code = "{code}")] + pub span: Span, + pub code: String, + pub item_name: String, + pub kind: String, } #[derive(LintDiagnostic)] @@ -1434,6 +1450,8 @@ pub(crate) struct UnusedVariableTryPrefix { #[subdiagnostic] pub sugg: UnusedVariableSugg, pub name: String, + #[subdiagnostic] + pub typo: Option<PatternTypo>, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index ae16a51bc69..1b2ffb5b3db 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -95,8 +95,10 @@ use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, find_attr}; use rustc_index::IndexVec; use rustc_middle::query::Providers; use rustc_middle::span_bug; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt}; use rustc_session::lint; +use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{BytePos, Span, Symbol}; use tracing::{debug, instrument}; @@ -1688,6 +1690,51 @@ impl<'tcx> Liveness<'_, 'tcx> { let is_assigned = if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) }; + let mut typo = None; + for (hir_id, _, span) in &hir_ids_and_spans { + let ty = self.typeck_results.node_type(*hir_id); + if let ty::Adt(adt, _) = ty.peel_refs().kind() { + let name = Symbol::intern(&name); + let adt_def = self.ir.tcx.adt_def(adt.did()); + let variant_names: Vec<_> = adt_def + .variants() + .iter() + .filter(|v| matches!(v.ctor, Some((CtorKind::Const, _)))) + .map(|v| v.name) + .collect(); + if let Some(name) = find_best_match_for_name(&variant_names, name, None) + && let Some(variant) = adt_def.variants().iter().find(|v| { + v.name == name && matches!(v.ctor, Some((CtorKind::Const, _))) + }) + { + typo = Some(errors::PatternTypo { + span: *span, + code: with_no_trimmed_paths!(self.ir.tcx.def_path_str(variant.def_id)), + kind: self.ir.tcx.def_descr(variant.def_id).to_string(), + item_name: variant.name.to_string(), + }); + } + } + } + if typo.is_none() { + for (hir_id, _, span) in &hir_ids_and_spans { + let ty = self.typeck_results.node_type(*hir_id); + // Look for consts of the same type with similar names as well, not just unit + // structs and variants. + for def_id in self.ir.tcx.hir_body_owners() { + if let DefKind::Const = self.ir.tcx.def_kind(def_id) + && self.ir.tcx.type_of(def_id).instantiate_identity() == ty + { + typo = Some(errors::PatternTypo { + span: *span, + code: with_no_trimmed_paths!(self.ir.tcx.def_path_str(def_id)), + kind: "constant".to_string(), + item_name: self.ir.tcx.item_name(def_id).to_string(), + }); + } + } + } + } if is_assigned { self.ir.tcx.emit_node_span_lint( lint::builtin::UNUSED_VARIABLES, @@ -1696,7 +1743,7 @@ impl<'tcx> Liveness<'_, 'tcx> { .into_iter() .map(|(_, _, ident_span)| ident_span) .collect::<Vec<_>>(), - errors::UnusedVarAssignedOnly { name }, + errors::UnusedVarAssignedOnly { name, typo }, ) } else if can_remove { let spans = hir_ids_and_spans @@ -1788,6 +1835,7 @@ impl<'tcx> Liveness<'_, 'tcx> { name, sugg, string_interp: suggestions, + typo, }, ); } diff --git a/compiler/rustc_query_system/messages.ftl b/compiler/rustc_query_system/messages.ftl index f48dc60afa0..f686608034c 100644 --- a/compiler/rustc_query_system/messages.ftl +++ b/compiler/rustc_query_system/messages.ftl @@ -18,8 +18,8 @@ query_system_cycle_usage = cycle used when {$usage} query_system_increment_compilation = internal compiler error: encountered incremental compilation error with {$dep_node} .help = This is a known issue with the compiler. Run {$run_cmd} to allow your project to compile -query_system_increment_compilation_note1 = Please follow the instructions below to create a bug report with the provided information -query_system_increment_compilation_note2 = See <https://github.com/rust-lang/rust/issues/84970> for more information +query_system_increment_compilation_note1 = please follow the instructions below to create a bug report with the provided information +query_system_increment_compilation_note2 = see <https://github.com/rust-lang/rust/issues/84970> for more information query_system_overflow_note = query depth increased by {$depth} when {$desc} diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 47280a93677..0e566e20a12 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -470,6 +470,8 @@ resolve_variable_bound_with_different_mode = .label = bound in different ways .first_binding_span = first binding +resolve_variable_is_a_typo = you might have meant to use the similarly named previously used binding `{$typo}` + resolve_variable_is_not_bound_in_all_patterns = variable `{$name}` is not bound in all patterns diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5dfc4292a38..abbacc70b3e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -661,8 +661,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ResolutionError::VariableNotBoundInPattern(binding_error, parent_scope) => { let BindingError { name, target, origin, could_be_path } = binding_error; - let target_sp = target.iter().copied().collect::<Vec<_>>(); - let origin_sp = origin.iter().copied().collect::<Vec<_>>(); + let mut target_sp = target.iter().map(|pat| pat.span).collect::<Vec<_>>(); + target_sp.sort(); + target_sp.dedup(); + let mut origin_sp = origin.iter().map(|(span, _)| *span).collect::<Vec<_>>(); + origin_sp.sort(); + origin_sp.dedup(); let msp = MultiSpan::from_spans(target_sp.clone()); let mut err = self @@ -671,8 +675,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for sp in target_sp { err.subdiagnostic(errors::PatternDoesntBindName { span: sp, name }); } - for sp in origin_sp { - err.subdiagnostic(errors::VariableNotInAllPatterns { span: sp }); + for sp in &origin_sp { + err.subdiagnostic(errors::VariableNotInAllPatterns { span: *sp }); + } + let mut suggested_typo = false; + if !target.iter().all(|pat| matches!(pat.kind, ast::PatKind::Ident(..))) + && !origin.iter().all(|(_, pat)| matches!(pat.kind, ast::PatKind::Ident(..))) + { + // The check above is so that when we encounter `match foo { (a | b) => {} }`, + // we don't suggest `(a | a) => {}`, which would never be what the user wants. + let mut target_visitor = BindingVisitor::default(); + for pat in &target { + target_visitor.visit_pat(pat); + } + target_visitor.identifiers.sort(); + target_visitor.identifiers.dedup(); + let mut origin_visitor = BindingVisitor::default(); + for (_, pat) in &origin { + origin_visitor.visit_pat(pat); + } + origin_visitor.identifiers.sort(); + origin_visitor.identifiers.dedup(); + // Find if the binding could have been a typo + if let Some(typo) = + find_best_match_for_name(&target_visitor.identifiers, name.name, None) + && !origin_visitor.identifiers.contains(&typo) + { + err.subdiagnostic(errors::PatternBindingTypo { spans: origin_sp, typo }); + suggested_typo = true; + } } if could_be_path { let import_suggestions = self.lookup_import_candidates( @@ -693,10 +724,86 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ); - if import_suggestions.is_empty() { + if import_suggestions.is_empty() && !suggested_typo { + let kinds = [ + DefKind::Ctor(CtorOf::Variant, CtorKind::Const), + DefKind::Ctor(CtorOf::Struct, CtorKind::Const), + DefKind::Const, + DefKind::AssocConst, + ]; + let mut local_names = vec![]; + self.add_module_candidates( + parent_scope.module, + &mut local_names, + &|res| matches!(res, Res::Def(_, _)), + None, + ); + let local_names: FxHashSet<_> = local_names + .into_iter() + .filter_map(|s| match s.res { + Res::Def(_, def_id) => Some(def_id), + _ => None, + }) + .collect(); + + let mut local_suggestions = vec![]; + let mut suggestions = vec![]; + for kind in kinds { + if let Some(suggestion) = self.early_lookup_typo_candidate( + ScopeSet::All(Namespace::ValueNS), + &parent_scope, + name, + &|res: Res| match res { + Res::Def(k, _) => k == kind, + _ => false, + }, + ) && let Res::Def(kind, mut def_id) = suggestion.res + { + if let DefKind::Ctor(_, _) = kind { + def_id = self.tcx.parent(def_id); + } + let kind = kind.descr(def_id); + if local_names.contains(&def_id) { + // The item is available in the current scope. Very likely to + // be a typo. Don't use the full path. + local_suggestions.push(( + suggestion.candidate, + suggestion.candidate.to_string(), + kind, + )); + } else { + suggestions.push(( + suggestion.candidate, + self.def_path_str(def_id), + kind, + )); + } + } + } + let suggestions = if !local_suggestions.is_empty() { + // There is at least one item available in the current scope that is a + // likely typo. We only show those. + local_suggestions + } else { + suggestions + }; + for (name, sugg, kind) in suggestions { + err.span_suggestion_verbose( + span, + format!( + "you might have meant to use the similarly named {kind} `{name}`", + ), + sugg, + Applicability::MaybeIncorrect, + ); + suggested_typo = true; + } + } + if import_suggestions.is_empty() && !suggested_typo { let help_msg = format!( - "if you meant to match on a variant or a `const` item, consider \ - making the path in the pattern qualified: `path::to::ModOrType::{name}`", + "if you meant to match on a unit struct, unit variant or a `const` \ + item, consider making the path in the pattern qualified: \ + `path::to::ModOrType::{name}`", ); err.span_help(span, help_msg); } @@ -1016,6 +1123,39 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .emit() } + fn def_path_str(&self, mut def_id: DefId) -> String { + // We can't use `def_path_str` in resolve. + let mut path = vec![def_id]; + while let Some(parent) = self.tcx.opt_parent(def_id) { + def_id = parent; + path.push(def_id); + if def_id.is_top_level_module() { + break; + } + } + // We will only suggest importing directly if it is accessible through that path. + path.into_iter() + .rev() + .map(|def_id| { + self.tcx + .opt_item_name(def_id) + .map(|name| { + match ( + def_id.is_top_level_module(), + def_id.is_local(), + self.tcx.sess.edition(), + ) { + (true, true, Edition::Edition2015) => String::new(), + (true, true, _) => kw::Crate.to_string(), + (true, false, _) | (false, _, _) => name.to_string(), + } + }) + .unwrap_or_else(|| "_".to_string()) + }) + .collect::<Vec<String>>() + .join("::") + } + pub(crate) fn add_scope_set_candidates( &mut self, suggestions: &mut Vec<TypoSuggestion>, @@ -3396,7 +3536,7 @@ impl UsePlacementFinder { } } -impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { +impl<'tcx> Visitor<'tcx> for UsePlacementFinder { fn visit_crate(&mut self, c: &Crate) { if self.target_module == CRATE_NODE_ID { let inject = c.spans.inject_use_span; @@ -3424,6 +3564,22 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { } } +#[derive(Default)] +struct BindingVisitor { + identifiers: Vec<Symbol>, + spans: FxHashMap<Symbol, Vec<Span>>, +} + +impl<'tcx> Visitor<'tcx> for BindingVisitor { + fn visit_pat(&mut self, pat: &ast::Pat) { + if let ast::PatKind::Ident(_, ident, _) = pat.kind { + self.identifiers.push(ident.name); + self.spans.entry(ident.name).or_default().push(ident.span); + } + visit::walk_pat(self, pat); + } +} + fn search_for_any_use_in_items(items: &[Box<ast::Item>]) -> Option<Span> { for item in items { if let ItemKind::Use(..) = item.kind diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 63d6fa23a14..72be94e58db 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -986,6 +986,18 @@ pub(crate) struct VariableNotInAllPatterns { pub(crate) span: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + resolve_variable_is_a_typo, + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct PatternBindingTypo { + #[suggestion_part(code = "{typo}")] + pub(crate) spans: Vec<Span>, + pub(crate) typo: Symbol, +} + #[derive(Diagnostic)] #[diag(resolve_name_defined_multiple_time)] #[note] diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index dae42645bec..bc06a227571 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -422,6 +422,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // to detect potential ambiguities. let mut innermost_result: Option<(NameBinding<'_>, Flags)> = None; let mut determinacy = Determinacy::Determined; + let mut extern_prelude_item_binding = None; + let mut extern_prelude_flag_binding = None; // Shadowed bindings don't need to be marked as used or non-speculatively loaded. macro finalize_scope() { if innermost_result.is_none() { finalize } else { None } @@ -558,7 +560,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::ExternPreludeItems => { // FIXME: use `finalize_scope` here. match this.reborrow().extern_prelude_get_item(ident, finalize.is_some()) { - Some(binding) => Ok((binding, Flags::empty())), + Some(binding) => { + extern_prelude_item_binding = Some(binding); + Ok((binding, Flags::empty())) + } None => Err(Determinacy::determined( this.graph_root.unexpanded_invocations.borrow().is_empty(), )), @@ -566,7 +571,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::ExternPreludeFlags => { match this.extern_prelude_get_flag(ident, finalize_scope!().is_some()) { - Some(binding) => Ok((binding, Flags::empty())), + Some(binding) => { + extern_prelude_flag_binding = Some(binding); + Ok((binding, Flags::empty())) + } None => Err(Determinacy::Determined), } } @@ -686,7 +694,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { None }; - if let Some(kind) = ambiguity_error_kind { + // Skip ambiguity errors for extern flag bindings "overridden" + // by extern item bindings. + // FIXME: Remove with lang team approval. + let issue_145575_hack = Some(binding) + == extern_prelude_flag_binding + && extern_prelude_item_binding.is_some() + && extern_prelude_item_binding != Some(innermost_binding); + if let Some(kind) = ambiguity_error_kind + && !issue_145575_hack + { let misc = |f: Flags| { if f.contains(Flags::MISC_SUGGEST_CRATE) { AmbiguityErrorMisc::SuggestCrate diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6a12fafcb1e..521fef2b9d4 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -8,7 +8,6 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; -use std::collections::BTreeSet; use std::collections::hash_map::Entry; use std::mem::{replace, swap, take}; @@ -3682,31 +3681,30 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // 2) Record any missing bindings or binding mode inconsistencies. for (map_outer, pat_outer) in not_never_pats.iter() { // Check against all arms except for the same pattern which is always self-consistent. - let inners = not_never_pats - .iter() - .filter(|(_, pat)| pat.id != pat_outer.id) - .flat_map(|(map, _)| map); - - for (&name, binding_inner) in inners { - match map_outer.get(&name) { - None => { - // The inner binding is missing in the outer. - let binding_error = - missing_vars.entry(name).or_insert_with(|| BindingError { - name, - origin: BTreeSet::new(), - target: BTreeSet::new(), - could_be_path: name.as_str().starts_with(char::is_uppercase), - }); - binding_error.origin.insert(binding_inner.span); - binding_error.target.insert(pat_outer.span); - } - Some(binding_outer) => { - if binding_outer.annotation != binding_inner.annotation { - // The binding modes in the outer and inner bindings differ. - inconsistent_vars - .entry(name) - .or_insert((binding_inner.span, binding_outer.span)); + let inners = not_never_pats.iter().filter(|(_, pat)| pat.id != pat_outer.id); + + for (map, pat) in inners { + for (&name, binding_inner) in map { + match map_outer.get(&name) { + None => { + // The inner binding is missing in the outer. + let binding_error = + missing_vars.entry(name).or_insert_with(|| BindingError { + name, + origin: Default::default(), + target: Default::default(), + could_be_path: name.as_str().starts_with(char::is_uppercase), + }); + binding_error.origin.push((binding_inner.span, (***pat).clone())); + binding_error.target.push((***pat_outer).clone()); + } + Some(binding_outer) => { + if binding_outer.annotation != binding_inner.annotation { + // The binding modes in the outer and inner bindings differ. + inconsistent_vars + .entry(name) + .or_insert((binding_inner.span, binding_outer.span)); + } } } } @@ -3719,7 +3717,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { v.could_be_path = false; } self.report_error( - *v.origin.iter().next().unwrap(), + v.origin.iter().next().unwrap().0, ResolutionError::VariableNotBoundInPattern(v, self.parent_scope), ); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9674c0356c2..0dea6ae3327 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -230,8 +230,8 @@ enum Used { #[derive(Debug)] struct BindingError { name: Ident, - origin: BTreeSet<Span>, - target: BTreeSet<Span>, + origin: Vec<(Span, ast::Pat)>, + target: Vec<ast::Pat>, could_be_path: bool, } diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index c32593a6d95..bb2cda77dff 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -81,8 +81,8 @@ cfg_select! { // use `loadu`, which supports unaligned loading. let chunk = unsafe { _mm_loadu_si128(chunk.as_ptr() as *const __m128i) }; - // For character in the chunk, see if its byte value is < 0, which - // indicates that it's part of a UTF-8 char. + // For each character in the chunk, see if its byte value is < 0, + // which indicates that it's part of a UTF-8 char. let multibyte_test = _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)); // Create a bit mask from the comparison results. let multibyte_mask = _mm_movemask_epi8(multibyte_test); @@ -132,8 +132,111 @@ cfg_select! { } } } + target_arch = "loongarch64" => { + fn analyze_source_file_dispatch( + src: &str, + lines: &mut Vec<RelativeBytePos>, + multi_byte_chars: &mut Vec<MultiByteChar>, + ) { + use std::arch::is_loongarch_feature_detected; + + if is_loongarch_feature_detected!("lsx") { + unsafe { + analyze_source_file_lsx(src, lines, multi_byte_chars); + } + } else { + analyze_source_file_generic( + src, + src.len(), + RelativeBytePos::from_u32(0), + lines, + multi_byte_chars, + ); + } + } + + /// Checks 16 byte chunks of text at a time. If the chunk contains + /// something other than printable ASCII characters and newlines, the + /// function falls back to the generic implementation. Otherwise it uses + /// LSX intrinsics to quickly find all newlines. + #[target_feature(enable = "lsx")] + unsafe fn analyze_source_file_lsx( + src: &str, + lines: &mut Vec<RelativeBytePos>, + multi_byte_chars: &mut Vec<MultiByteChar>, + ) { + use std::arch::loongarch64::*; + + const CHUNK_SIZE: usize = 16; + + let (chunks, tail) = src.as_bytes().as_chunks::<CHUNK_SIZE>(); + + // This variable keeps track of where we should start decoding a + // chunk. If a multi-byte character spans across chunk boundaries, + // we need to skip that part in the next chunk because we already + // handled it. + let mut intra_chunk_offset = 0; + + for (chunk_index, chunk) in chunks.iter().enumerate() { + // All LSX memory instructions support unaligned access, so using + // vld is fine. + let chunk = unsafe { lsx_vld::<0>(chunk.as_ptr() as *const i8) }; + + // For each character in the chunk, see if its byte value is < 0, + // which indicates that it's part of a UTF-8 char. + let multibyte_mask = lsx_vmskltz_b(chunk); + // Create a bit mask from the comparison results. + let multibyte_mask = lsx_vpickve2gr_w::<0>(multibyte_mask); + + // If the bit mask is all zero, we only have ASCII chars here: + if multibyte_mask == 0 { + assert!(intra_chunk_offset == 0); + + // Check for newlines in the chunk + let newlines_test = lsx_vseqi_b::<{b'\n' as i32}>(chunk); + let newlines_mask = lsx_vmskltz_b(newlines_test); + let mut newlines_mask = lsx_vpickve2gr_w::<0>(newlines_mask); + + let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1); + + while newlines_mask != 0 { + let index = newlines_mask.trailing_zeros(); + + lines.push(RelativeBytePos(index) + output_offset); + + // Clear the bit, so we can find the next one. + newlines_mask &= newlines_mask - 1; + } + } else { + // The slow path. + // There are multibyte chars in here, fallback to generic decoding. + let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset; + intra_chunk_offset = analyze_source_file_generic( + &src[scan_start..], + CHUNK_SIZE - intra_chunk_offset, + RelativeBytePos::from_usize(scan_start), + lines, + multi_byte_chars, + ); + } + } + + // There might still be a tail left to analyze + let tail_start = src.len() - tail.len() + intra_chunk_offset; + if tail_start < src.len() { + analyze_source_file_generic( + &src[tail_start..], + src.len() - tail_start, + RelativeBytePos::from_usize(tail_start), + lines, + multi_byte_chars, + ); + } + } + } _ => { - // The target (or compiler version) does not support SSE2 ... + // The target (or compiler version) does not support vector instructions + // our specialized implementations need (x86 SSE2, loongarch64 LSX)... fn analyze_source_file_dispatch( src: &str, lines: &mut Vec<RelativeBytePos>, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index ae6755f0764..8907c5e4c4a 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -18,6 +18,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![cfg_attr(bootstrap, feature(round_char_boundary))] +#![cfg_attr(target_arch = "loongarch64", feature(stdarch_loongarch))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 77260d07c99..e5108d8b7e9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2162,6 +2162,7 @@ symbols! { target_family, target_feature, target_feature_11, + target_feature_inline_always, target_has_atomic, target_has_atomic_equal_alignment, target_has_atomic_load_store, @@ -2280,6 +2281,8 @@ symbols! { unboxed_closures, unchecked_add, unchecked_div, + unchecked_funnel_shl, + unchecked_funnel_shr, unchecked_mul, unchecked_rem, unchecked_shl, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs index f1b6fa123de..cd55576ef81 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { llvm_target: "aarch64-pc-windows-msvc".into(), metadata: TargetMetadata { description: Some("ARM64 Windows MSVC".into()), - tier: Some(2), + tier: Some(1), host_tools: Some(true), std: Some(true), }, diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs index 91e3064aaed..b6a08958284 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { arch: "loongarch64".into(), options: TargetOptions { cpu: "generic".into(), - features: "+f,+d".into(), + features: "+f,+d,-lsx".into(), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), llvm_abiname: "lp64d".into(), diff --git a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs index 598f0f19f0d..cada0dd640a 100644 --- a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs @@ -6,7 +6,7 @@ use crate::spec::{ pub(crate) fn target() -> Target { Target { arch: "nvptx64".into(), - data_layout: "e-p6:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64".into(), + data_layout: "e-p6:32:32-i64:64-i128:128-i256:256-v16:16-v32:32-n16:32:64".into(), llvm_target: "nvptx64-nvidia-cuda".into(), metadata: TargetMetadata { description: Some("--emit=asm generates PTX code that runs on NVIDIA GPUs".into()), diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index f5448baf8c0..3355c0c2104 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -1,3 +1,4 @@ +use std::borrow::Borrow; use std::fmt::Debug; use std::hash::Hash; use std::ops::Deref; @@ -383,12 +384,12 @@ pub trait Interner: defining_anchor: Self::LocalDefId, ) -> Self::LocalDefIds; - type ProbeRef: Copy + Debug + Hash + Eq + Deref<Target = inspect::Probe<Self>>; - fn mk_probe_ref(self, probe: inspect::Probe<Self>) -> Self::ProbeRef; + type Probe: Debug + Hash + Eq + Borrow<inspect::Probe<Self>>; + fn mk_probe(self, probe: inspect::Probe<Self>) -> Self::Probe; fn evaluate_root_goal_for_proof_tree_raw( self, canonical_goal: CanonicalInput<Self>, - ) -> (QueryResult<Self>, Self::ProbeRef); + ) -> (QueryResult<Self>, Self::Probe); } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs index 5452ac44158..3af2f8dbaf2 100644 --- a/compiler/rustc_type_ir/src/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -49,7 +49,7 @@ pub type CanonicalState<I, T> = Canonical<I, State<I, T>>; pub struct GoalEvaluation<I: Interner> { pub uncanonicalized_goal: Goal<I, I::Predicate>, pub orig_values: Vec<I::GenericArg>, - pub final_revision: I::ProbeRef, + pub final_revision: I::Probe, pub result: QueryResult<I>, } diff --git a/library/Cargo.lock b/library/Cargo.lock index 8b860f69492..c16bb3eafbd 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -327,7 +327,8 @@ dependencies = [ "rustc-demangle", "std_detect", "unwind", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasi 0.14.3+wasi-0.2.4", "windows-targets 0.0.0", ] @@ -400,6 +401,17 @@ dependencies = [ ] [[package]] +name = "wasi" +version = "0.14.3+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +dependencies = [ + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", + "wit-bindgen", +] + +[[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -475,3 +487,13 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" +dependencies = [ + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 07f51b7614f..cb32896161e 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -17,9 +17,11 @@ use crate::fmt; use crate::string::String; #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, B: ?Sized> Borrow<B> for Cow<'a, B> +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<'a, B: ?Sized> const Borrow<B> for Cow<'a, B> where B: ToOwned, + B::Owned: [const] Borrow<B>, { fn borrow(&self) -> &B { &**self @@ -326,9 +328,10 @@ impl<B: ?Sized + ToOwned> Cow<'_, B> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<B: ?Sized + ToOwned> Deref for Cow<'_, B> +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<B: ?Sized + ToOwned> const Deref for Cow<'_, B> where - B::Owned: Borrow<B>, + B::Owned: [const] Borrow<B>, { type Target = B; @@ -439,7 +442,11 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized + ToOwned> AsRef<T> for Cow<'_, T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: ?Sized + ToOwned> const AsRef<T> for Cow<'_, T> +where + T::Owned: [const] Borrow<T>, +{ fn as_ref(&self) -> &T { self } diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index fac4d1a65ab..212d7c8465b 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -128,8 +128,9 @@ pub use realalloc::collections::TryReserveErrorKind; reason = "Uncertain how much info should be exposed", issue = "48043" )] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] #[cfg(not(test))] -impl From<TryReserveErrorKind> for TryReserveError { +impl const From<TryReserveErrorKind> for TryReserveError { #[inline] fn from(kind: TryReserveErrorKind) -> Self { Self { kind } @@ -137,8 +138,9 @@ impl From<TryReserveErrorKind> for TryReserveError { } #[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] #[cfg(not(test))] -impl From<LayoutError> for TryReserveErrorKind { +impl const From<LayoutError> for TryReserveErrorKind { /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`]. #[inline] fn from(_: LayoutError) -> Self { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 711092ae8eb..cba1ce40f75 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -107,10 +107,10 @@ #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] +#![feature(const_convert)] #![feature(const_default)] #![feature(const_eval_select)] #![feature(const_heap)] -#![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] @@ -168,6 +168,7 @@ #![feature(allow_internal_unstable)] #![feature(cfg_sanitize)] #![feature(const_precise_live_drops)] +#![feature(const_trait_impl)] #![feature(coroutine_trait)] #![feature(decl_macro)] #![feature(dropck_eyepatch)] diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index fd05f9ca464..b0027e964e4 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -468,10 +468,6 @@ impl<A: Allocator> RawVecInner<A> { return Ok(Self::new_in(alloc, elem_layout.alignment())); } - if let Err(err) = alloc_guard(layout.size()) { - return Err(err); - } - let result = match init { AllocInit::Uninitialized => alloc.allocate(layout), #[cfg(not(no_global_oom_handling))] @@ -662,7 +658,7 @@ impl<A: Allocator> RawVecInner<A> { let new_layout = layout_array(cap, elem_layout)?; let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?; - // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items + // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items unsafe { self.set_ptr_and_cap(ptr, cap) }; Ok(()) @@ -684,7 +680,7 @@ impl<A: Allocator> RawVecInner<A> { let new_layout = layout_array(cap, elem_layout)?; let ptr = finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)?; - // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items + // SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items unsafe { self.set_ptr_and_cap(ptr, cap); } @@ -771,8 +767,6 @@ fn finish_grow<A>( where A: Allocator, { - alloc_guard(new_layout.size())?; - let memory = if let Some((ptr, old_layout)) = current_memory { debug_assert_eq!(old_layout.align(), new_layout.align()); unsafe { @@ -799,23 +793,6 @@ fn handle_error(e: TryReserveError) -> ! { } } -// We need to guarantee the following: -// * We don't ever allocate `> isize::MAX` byte-size objects. -// * We don't overflow `usize::MAX` and actually allocate too little. -// -// On 64-bit we just need to check for overflow since trying to allocate -// `> isize::MAX` bytes will surely fail. On 32-bit and 16-bit we need to add -// an extra guard for this in case we're running on a platform which can use -// all 4GB in user-space, e.g., PAE or x32. -#[inline] -fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { - if usize::BITS < 64 && alloc_size > isize::MAX as usize { - Err(CapacityOverflow.into()) - } else { - Ok(()) - } -} - #[inline] fn layout_array(cap: usize, elem_layout: Layout) -> Result<Layout, TryReserveError> { elem_layout.repeat(cap).map(|(layout, _pad)| layout).map_err(|_| CapacityOverflow.into()) diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index 97de7d6a701..0201c875221 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -49,6 +49,7 @@ // Language features: // tidy-alphabetical-start #![feature(cfg_sanitize)] +#![feature(const_trait_impl)] #![feature(dropck_eyepatch)] #![feature(lang_items)] #![feature(min_specialization)] diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index c4bb5ab7b21..d14419a23a1 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -48,6 +48,7 @@ pub use iter::IntoIter; /// assert_eq!(strings, ["Hello there!", "Hello there!"]); /// ``` #[inline] +#[must_use = "cloning is often expensive and is not expected to have side effects"] #[stable(feature = "array_repeat", since = "CURRENT_RUSTC_VERSION")] pub fn repeat<T: Clone, const N: usize>(val: T) -> [T; N] { from_trusted_iterator(repeat_n(val, N)) @@ -190,7 +191,7 @@ impl fmt::Display for TryFromSliceError { impl Error for TryFromSliceError {} #[stable(feature = "try_from_slice_error", since = "1.36.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<Infallible> for TryFromSliceError { fn from(x: Infallible) -> TryFromSliceError { match x {} @@ -198,7 +199,8 @@ impl const From<Infallible> for TryFromSliceError { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, const N: usize> AsRef<[T]> for [T; N] { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T, const N: usize> const AsRef<[T]> for [T; N] { #[inline] fn as_ref(&self) -> &[T] { &self[..] @@ -206,7 +208,8 @@ impl<T, const N: usize> AsRef<[T]> for [T; N] { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, const N: usize> AsMut<[T]> for [T; N] { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T, const N: usize> const AsMut<[T]> for [T; N] { #[inline] fn as_mut(&mut self) -> &mut [T] { &mut self[..] @@ -214,14 +217,16 @@ impl<T, const N: usize> AsMut<[T]> for [T; N] { } #[stable(feature = "array_borrow", since = "1.4.0")] -impl<T, const N: usize> Borrow<[T]> for [T; N] { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T, const N: usize> const Borrow<[T]> for [T; N] { fn borrow(&self) -> &[T] { self } } #[stable(feature = "array_borrow", since = "1.4.0")] -impl<T, const N: usize> BorrowMut<[T]> for [T; N] { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T, const N: usize> const BorrowMut<[T]> for [T; N] { fn borrow_mut(&mut self) -> &mut [T] { self } @@ -240,7 +245,8 @@ impl<T, const N: usize> BorrowMut<[T]> for [T; N] { /// assert_eq!(512, u16::from_le_bytes(bytes_tail)); /// ``` #[stable(feature = "try_from", since = "1.34.0")] -impl<T, const N: usize> TryFrom<&[T]> for [T; N] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T, const N: usize> const TryFrom<&[T]> for [T; N] where T: Copy, { @@ -265,7 +271,8 @@ where /// assert_eq!(512, u16::from_le_bytes(bytes_tail)); /// ``` #[stable(feature = "try_from_mut_slice_to_array", since = "1.59.0")] -impl<T, const N: usize> TryFrom<&mut [T]> for [T; N] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T, const N: usize> const TryFrom<&mut [T]> for [T; N] where T: Copy, { @@ -290,7 +297,8 @@ where /// assert_eq!(512, u16::from_le_bytes(*bytes_tail)); /// ``` #[stable(feature = "try_from", since = "1.34.0")] -impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<'a, T, const N: usize> const TryFrom<&'a [T]> for &'a [T; N] { type Error = TryFromSliceError; #[inline] @@ -312,7 +320,8 @@ impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] { /// assert_eq!(512, u16::from_le_bytes(*bytes_tail)); /// ``` #[stable(feature = "try_from", since = "1.34.0")] -impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<'a, T, const N: usize> const TryFrom<&'a mut [T]> for &'a mut [T; N] { type Error = TryFromSliceError; #[inline] diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index 419e4694594..49d540314a2 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -1156,7 +1156,7 @@ macro_rules! into_int_impl { ($($ty:ty)*) => { $( #[unstable(feature = "ascii_char", issue = "110998")] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<AsciiChar> for $ty { #[inline] fn from(chr: AsciiChar) -> $ty { diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index da05f236d2f..6ce7e4656b9 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -154,6 +154,8 @@ /// [`String`]: ../../std/string/struct.String.html #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Borrow"] +#[const_trait] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] pub trait Borrow<Borrowed: ?Sized> { /// Immutably borrows from an owned value. /// @@ -185,6 +187,8 @@ pub trait Borrow<Borrowed: ?Sized> { /// for more information on borrowing as another type. #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "BorrowMut"] +#[const_trait] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> { /// Mutably borrows from an owned value. /// @@ -206,7 +210,8 @@ pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Borrow<T> for T { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: ?Sized> const Borrow<T> for T { #[rustc_diagnostic_item = "noop_method_borrow"] fn borrow(&self) -> &T { self @@ -214,28 +219,32 @@ impl<T: ?Sized> Borrow<T> for T { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> BorrowMut<T> for T { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: ?Sized> const BorrowMut<T> for T { fn borrow_mut(&mut self) -> &mut T { self } } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Borrow<T> for &T { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: ?Sized> const Borrow<T> for &T { fn borrow(&self) -> &T { self } } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Borrow<T> for &mut T { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: ?Sized> const Borrow<T> for &mut T { fn borrow(&self) -> &T { self } } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> BorrowMut<T> for &mut T { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: ?Sized> const BorrowMut<T> for &mut T { fn borrow_mut(&mut self) -> &mut T { self } diff --git a/library/core/src/bstr/mod.rs b/library/core/src/bstr/mod.rs index 13127d645a2..e13dc5cd44d 100644 --- a/library/core/src/bstr/mod.rs +++ b/library/core/src/bstr/mod.rs @@ -63,14 +63,16 @@ impl ByteStr { /// ``` #[inline] #[unstable(feature = "bstr", issue = "134915")] - pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &B) -> &Self { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn new<B: ?Sized + [const] AsRef<[u8]>>(bytes: &B) -> &Self { ByteStr::from_bytes(bytes.as_ref()) } #[doc(hidden)] #[unstable(feature = "bstr_internals", issue = "none")] #[inline] - pub fn from_bytes(slice: &[u8]) -> &Self { + #[rustc_const_unstable(feature = "bstr_internals", issue = "none")] + pub const fn from_bytes(slice: &[u8]) -> &Self { // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to // the wrapped type into a reference to the wrapper type. unsafe { &*(slice as *const [u8] as *const Self) } @@ -79,7 +81,8 @@ impl ByteStr { #[doc(hidden)] #[unstable(feature = "bstr_internals", issue = "none")] #[inline] - pub fn from_bytes_mut(slice: &mut [u8]) -> &mut Self { + #[rustc_const_unstable(feature = "bstr_internals", issue = "none")] + pub const fn from_bytes_mut(slice: &mut [u8]) -> &mut Self { // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to // the wrapped type into a reference to the wrapper type. unsafe { &mut *(slice as *mut [u8] as *mut Self) } @@ -88,20 +91,23 @@ impl ByteStr { #[doc(hidden)] #[unstable(feature = "bstr_internals", issue = "none")] #[inline] - pub fn as_bytes(&self) -> &[u8] { + #[rustc_const_unstable(feature = "bstr_internals", issue = "none")] + pub const fn as_bytes(&self) -> &[u8] { &self.0 } #[doc(hidden)] #[unstable(feature = "bstr_internals", issue = "none")] #[inline] - pub fn as_bytes_mut(&mut self) -> &mut [u8] { + #[rustc_const_unstable(feature = "bstr_internals", issue = "none")] + pub const fn as_bytes_mut(&mut self) -> &mut [u8] { &mut self.0 } } #[unstable(feature = "bstr", issue = "134915")] -impl Deref for ByteStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const Deref for ByteStr { type Target = [u8]; #[inline] @@ -111,7 +117,8 @@ impl Deref for ByteStr { } #[unstable(feature = "bstr", issue = "134915")] -impl DerefMut for ByteStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const DerefMut for ByteStr { #[inline] fn deref_mut(&mut self) -> &mut [u8] { &mut self.0 @@ -185,7 +192,8 @@ impl fmt::Display for ByteStr { } #[unstable(feature = "bstr", issue = "134915")] -impl AsRef<[u8]> for ByteStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<[u8]> for ByteStr { #[inline] fn as_ref(&self) -> &[u8] { &self.0 @@ -193,7 +201,8 @@ impl AsRef<[u8]> for ByteStr { } #[unstable(feature = "bstr", issue = "134915")] -impl AsRef<ByteStr> for ByteStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<ByteStr> for ByteStr { #[inline] fn as_ref(&self) -> &ByteStr { self @@ -203,7 +212,8 @@ impl AsRef<ByteStr> for ByteStr { // `impl AsRef<ByteStr> for [u8]` omitted to avoid widespread inference failures #[unstable(feature = "bstr", issue = "134915")] -impl AsRef<ByteStr> for str { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<ByteStr> for str { #[inline] fn as_ref(&self) -> &ByteStr { ByteStr::new(self) @@ -211,7 +221,8 @@ impl AsRef<ByteStr> for str { } #[unstable(feature = "bstr", issue = "134915")] -impl AsMut<[u8]> for ByteStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsMut<[u8]> for ByteStr { #[inline] fn as_mut(&mut self) -> &mut [u8] { &mut self.0 @@ -225,7 +236,8 @@ impl AsMut<[u8]> for ByteStr { // `impl Borrow<ByteStr> for str` omitted to avoid widespread inference failures #[unstable(feature = "bstr", issue = "134915")] -impl Borrow<[u8]> for ByteStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const Borrow<[u8]> for ByteStr { #[inline] fn borrow(&self) -> &[u8] { &self.0 @@ -235,7 +247,8 @@ impl Borrow<[u8]> for ByteStr { // `impl BorrowMut<ByteStr> for [u8]` omitted to avoid widespread inference failures #[unstable(feature = "bstr", issue = "134915")] -impl BorrowMut<[u8]> for ByteStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const BorrowMut<[u8]> for ByteStr { #[inline] fn borrow_mut(&mut self) -> &mut [u8] { &mut self.0 @@ -303,7 +316,8 @@ impl<'a> Default for &'a mut ByteStr { // } #[unstable(feature = "bstr", issue = "134915")] -impl<'a> TryFrom<&'a ByteStr> for &'a str { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<'a> const TryFrom<&'a ByteStr> for &'a str { type Error = crate::str::Utf8Error; #[inline] @@ -313,7 +327,8 @@ impl<'a> TryFrom<&'a ByteStr> for &'a str { } #[unstable(feature = "bstr", issue = "134915")] -impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<'a> const TryFrom<&'a mut ByteStr> for &'a mut str { type Error = crate::str::Utf8Error; #[inline] diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 59a6aa70620..9b53b75ebee 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -390,7 +390,8 @@ impl<T: Ord + Copy> Ord for Cell<T> { } #[stable(feature = "cell_from", since = "1.12.0")] -impl<T> From<T> for Cell<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const From<T> for Cell<T> { /// Creates a new `Cell<T>` containing the given value. fn from(t: T) -> Cell<T> { Cell::new(t) @@ -1402,7 +1403,8 @@ impl<T: ?Sized + Ord> Ord for RefCell<T> { } #[stable(feature = "cell_from", since = "1.12.0")] -impl<T> From<T> for RefCell<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const From<T> for RefCell<T> { /// Creates a new `RefCell<T>` containing the given value. fn from(t: T) -> RefCell<T> { RefCell::new(t) @@ -1483,7 +1485,7 @@ pub struct Ref<'b, T: ?Sized + 'b> { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T: ?Sized> const Deref for Ref<'_, T> { type Target = T; @@ -1967,7 +1969,7 @@ pub struct RefMut<'b, T: ?Sized + 'b> { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T: ?Sized> const Deref for RefMut<'_, T> { type Target = T; @@ -1979,7 +1981,7 @@ impl<T: ?Sized> const Deref for RefMut<'_, T> { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T: ?Sized> const DerefMut for RefMut<'_, T> { #[inline] fn deref_mut(&mut self) -> &mut T { @@ -2434,7 +2436,8 @@ impl<T: [const] Default> const Default for UnsafeCell<T> { } #[stable(feature = "cell_from", since = "1.12.0")] -impl<T> From<T> for UnsafeCell<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const From<T> for UnsafeCell<T> { /// Creates a new `UnsafeCell<T>` containing the given value. fn from(t: T) -> UnsafeCell<T> { UnsafeCell::new(t) @@ -2539,7 +2542,8 @@ impl<T: [const] Default> const Default for SyncUnsafeCell<T> { } #[unstable(feature = "sync_unsafe_cell", issue = "95439")] -impl<T> From<T> for SyncUnsafeCell<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const From<T> for SyncUnsafeCell<T> { /// Creates a new `SyncUnsafeCell<T>` containing the given value. fn from(t: T) -> SyncUnsafeCell<T> { SyncUnsafeCell::new(t) diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index c6c96571d33..833be059d75 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -395,7 +395,8 @@ impl<T: PartialEq> PartialEq for OnceCell<T> { impl<T: Eq> Eq for OnceCell<T> {} #[stable(feature = "once_cell", since = "1.70.0")] -impl<T> From<T> for OnceCell<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const From<T> for OnceCell<T> { /// Creates a new `OnceCell<T>` which already contains the given `value`. #[inline] fn from(value: T) -> Self { diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index cf5a91bf8dd..6380f42d320 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -36,7 +36,7 @@ pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char { } #[stable(feature = "char_convert", since = "1.13.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<char> for u32 { /// Converts a [`char`] into a [`u32`]. /// @@ -54,7 +54,7 @@ impl const From<char> for u32 { } #[stable(feature = "more_char_conversions", since = "1.51.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<char> for u64 { /// Converts a [`char`] into a [`u64`]. /// @@ -74,7 +74,7 @@ impl const From<char> for u64 { } #[stable(feature = "more_char_conversions", since = "1.51.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<char> for u128 { /// Converts a [`char`] into a [`u128`]. /// @@ -98,7 +98,8 @@ impl const From<char> for u128 { /// /// See [`impl From<u8> for char`](char#impl-From<u8>-for-char) for details on the encoding. #[stable(feature = "u8_from_char", since = "1.59.0")] -impl TryFrom<char> for u8 { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const TryFrom<char> for u8 { type Error = TryFromCharError; /// Tries to convert a [`char`] into a [`u8`]. @@ -113,7 +114,11 @@ impl TryFrom<char> for u8 { /// ``` #[inline] fn try_from(c: char) -> Result<u8, Self::Error> { - u8::try_from(u32::from(c)).map_err(|_| TryFromCharError(())) + // FIXME(const-hack): this should use map_err instead + match u8::try_from(u32::from(c)) { + Ok(b) => Ok(b), + Err(_) => Err(TryFromCharError(())), + } } } @@ -122,7 +127,8 @@ impl TryFrom<char> for u8 { /// /// This corresponds to the UCS-2 encoding, as specified in ISO/IEC 10646:2003. #[stable(feature = "u16_from_char", since = "1.74.0")] -impl TryFrom<char> for u16 { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const TryFrom<char> for u16 { type Error = TryFromCharError; /// Tries to convert a [`char`] into a [`u16`]. @@ -137,7 +143,11 @@ impl TryFrom<char> for u16 { /// ``` #[inline] fn try_from(c: char) -> Result<u16, Self::Error> { - u16::try_from(u32::from(c)).map_err(|_| TryFromCharError(())) + // FIXME(const-hack): this should use map_err instead + match u16::try_from(u32::from(c)) { + Ok(x) => Ok(x), + Err(_) => Err(TryFromCharError(())), + } } } @@ -160,7 +170,7 @@ impl TryFrom<char> for u16 { /// for a superset of Windows-1252 that fills the remaining blanks with corresponding /// C0 and C1 control codes. #[stable(feature = "char_convert", since = "1.13.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<u8> for char { /// Converts a [`u8`] into a [`char`]. /// @@ -246,7 +256,7 @@ const fn char_try_from_u32(i: u32) -> Result<char, CharTryFromError> { } #[stable(feature = "try_from", since = "1.34.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const TryFrom<u32> for char { type Error = CharTryFromError; diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index a0a7b7928d1..add21b491ad 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -217,7 +217,7 @@ pub const fn identity<T>(x: T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "AsRef"] #[const_trait] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] pub trait AsRef<T: PointeeSized>: PointeeSized { /// Converts this type into a shared reference of the (usually inferred) input type. #[stable(feature = "rust1", since = "1.0.0")] @@ -370,7 +370,7 @@ pub trait AsRef<T: PointeeSized>: PointeeSized { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "AsMut"] #[const_trait] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] pub trait AsMut<T: PointeeSized>: PointeeSized { /// Converts this type into a mutable reference of the (usually inferred) input type. #[stable(feature = "rust1", since = "1.0.0")] @@ -449,7 +449,7 @@ pub trait AsMut<T: PointeeSized>: PointeeSized { #[rustc_diagnostic_item = "Into"] #[stable(feature = "rust1", since = "1.0.0")] #[doc(search_unbox)] -#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] #[const_trait] pub trait Into<T>: Sized { /// Converts this type into the (usually inferred) input type. @@ -586,7 +586,7 @@ pub trait Into<T>: Sized { note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", ))] #[doc(search_unbox)] -#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] #[const_trait] pub trait From<T>: Sized { /// Converts to this type from the input type. @@ -615,7 +615,7 @@ pub trait From<T>: Sized { /// [`Into`], see there for details. #[rustc_diagnostic_item = "TryInto"] #[stable(feature = "try_from", since = "1.34.0")] -#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] #[const_trait] pub trait TryInto<T>: Sized { /// The type returned in the event of a conversion error. @@ -695,7 +695,7 @@ pub trait TryInto<T>: Sized { /// [`try_from`]: TryFrom::try_from #[rustc_diagnostic_item = "TryFrom"] #[stable(feature = "try_from", since = "1.34.0")] -#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] #[const_trait] pub trait TryFrom<T>: Sized { /// The type returned in the event of a conversion error. @@ -714,7 +714,7 @@ pub trait TryFrom<T>: Sized { // As lifts over & #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T: PointeeSized, U: PointeeSized> const AsRef<U> for &T where T: [const] AsRef<U>, @@ -727,7 +727,7 @@ where // As lifts over &mut #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T: PointeeSized, U: PointeeSized> const AsRef<U> for &mut T where T: [const] AsRef<U>, @@ -748,7 +748,7 @@ where // AsMut lifts over &mut #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T: PointeeSized, U: PointeeSized> const AsMut<U> for &mut T where T: [const] AsMut<U>, @@ -769,7 +769,7 @@ where // From implies Into #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T, U> const Into<U> for T where U: [const] From<T>, @@ -787,7 +787,7 @@ where // From (and thus Into) is reflexive #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T> const From<T> for T { /// Returns the argument unchanged. #[inline(always)] @@ -804,7 +804,7 @@ impl<T> const From<T> for T { #[stable(feature = "convert_infallible", since = "1.34.0")] #[rustc_reservation_impl = "permitting this impl would forbid us from adding \ `impl<T> From<!> for T` later; see rust-lang/rust#64715 for details"] -#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T> const From<!> for T { fn from(t: !) -> T { t @@ -813,7 +813,7 @@ impl<T> const From<!> for T { // TryFrom implies TryInto #[stable(feature = "try_from", since = "1.34.0")] -#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T, U> const TryInto<U> for T where U: [const] TryFrom<T>, @@ -829,7 +829,7 @@ where // Infallible conversions are semantically equivalent to fallible conversions // with an uninhabited error type. #[stable(feature = "try_from", since = "1.34.0")] -#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T, U> const TryFrom<U> for T where U: [const] Into<T>, @@ -847,7 +847,7 @@ where //////////////////////////////////////////////////////////////////////////////// #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T> const AsRef<[T]> for [T] { #[inline(always)] fn as_ref(&self) -> &[T] { @@ -856,7 +856,7 @@ impl<T> const AsRef<[T]> for [T] { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T> const AsMut<[T]> for [T] { #[inline(always)] fn as_mut(&mut self) -> &mut [T] { @@ -865,7 +865,7 @@ impl<T> const AsMut<[T]> for [T] { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const AsRef<str> for str { #[inline(always)] fn as_ref(&self) -> &str { @@ -874,7 +874,7 @@ impl const AsRef<str> for str { } #[stable(feature = "as_mut_str_for_str", since = "1.51.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const AsMut<str> for str { #[inline(always)] fn as_mut(&mut self) -> &mut str { @@ -936,7 +936,7 @@ impl const AsMut<str> for str { pub enum Infallible {} #[stable(feature = "convert_infallible", since = "1.34.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] impl const Clone for Infallible { fn clone(&self) -> Infallible { match *self {} @@ -986,7 +986,7 @@ impl Ord for Infallible { } #[stable(feature = "convert_infallible", since = "1.34.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<!> for Infallible { #[inline] fn from(x: !) -> Self { diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index affb4eb64d3..6ae588a4e04 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -69,7 +69,7 @@ macro_rules! impl_from { }; ($Small:ty => $Large:ty, #[$attr:meta], $doc:expr $(,)?) => { #[$attr] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<$Small> for $Large { // Rustdocs on the impl block show a "[+] show undocumented items" toggle. // Rustdocs on functions do not. @@ -201,7 +201,7 @@ macro_rules! impl_float_from_bool { )? ) => { #[stable(feature = "float_from_bool", since = "1.68.0")] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<bool> for $float { #[doc = concat!("Converts a [`bool`] to [`", stringify!($float),"`] losslessly.")] /// The resulting value is positive `0.0` for `false` and `1.0` for `true` values. @@ -252,7 +252,7 @@ impl_float_from_bool!( macro_rules! impl_try_from_unbounded { ($source:ty => $($target:ty),+) => {$( #[stable(feature = "try_from", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const TryFrom<$source> for $target { type Error = TryFromIntError; @@ -271,7 +271,7 @@ macro_rules! impl_try_from_unbounded { macro_rules! impl_try_from_lower_bounded { ($source:ty => $($target:ty),+) => {$( #[stable(feature = "try_from", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const TryFrom<$source> for $target { type Error = TryFromIntError; @@ -294,7 +294,7 @@ macro_rules! impl_try_from_lower_bounded { macro_rules! impl_try_from_upper_bounded { ($source:ty => $($target:ty),+) => {$( #[stable(feature = "try_from", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const TryFrom<$source> for $target { type Error = TryFromIntError; @@ -317,7 +317,7 @@ macro_rules! impl_try_from_upper_bounded { macro_rules! impl_try_from_both_bounded { ($source:ty => $($target:ty),+) => {$( #[stable(feature = "try_from", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const TryFrom<$source> for $target { type Error = TryFromIntError; @@ -456,7 +456,7 @@ use crate::num::NonZero; macro_rules! impl_nonzero_int_from_nonzero_int { ($Small:ty => $Large:ty) => { #[stable(feature = "nz_int_conv", since = "1.41.0")] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<NonZero<$Small>> for NonZero<$Large> { // Rustdocs on the impl block show a "[+] show undocumented items" toggle. // Rustdocs on functions do not. @@ -515,7 +515,8 @@ impl_nonzero_int_from_nonzero_int!(u64 => i128); macro_rules! impl_nonzero_int_try_from_int { ($Int:ty) => { #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] - impl TryFrom<$Int> for NonZero<$Int> { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + impl const TryFrom<$Int> for NonZero<$Int> { type Error = TryFromIntError; // Rustdocs on the impl block show a "[+] show undocumented items" toggle. @@ -547,7 +548,7 @@ impl_nonzero_int_try_from_int!(isize); macro_rules! impl_nonzero_int_try_from_nonzero_int { ($source:ty => $($target:ty),+) => {$( #[stable(feature = "nzint_try_from_nzint_conv", since = "1.49.0")] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const TryFrom<NonZero<$source>> for NonZero<$target> { type Error = TryFromIntError; diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index e6b599fafcf..d0b53e3a237 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -708,7 +708,8 @@ impl ops::Index<ops::RangeFrom<usize>> for CStr { } #[stable(feature = "cstring_asref", since = "1.7.0")] -impl AsRef<CStr> for CStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<CStr> for CStr { #[inline] fn as_ref(&self) -> &CStr { self diff --git a/library/core/src/intrinsics/fallback.rs b/library/core/src/intrinsics/fallback.rs index eec5c4d646d..96928325328 100644 --- a/library/core/src/intrinsics/fallback.rs +++ b/library/core/src/intrinsics/fallback.rs @@ -148,3 +148,76 @@ impl_disjoint_bitor! { u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, } + +#[const_trait] +#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] +pub trait FunnelShift: Copy + 'static { + /// See [`super::unchecked_funnel_shl`]; we just need the trait indirection to handle + /// different types since calling intrinsics with generics doesn't work. + unsafe fn unchecked_funnel_shl(self, rhs: Self, shift: u32) -> Self; + + /// See [`super::unchecked_funnel_shr`]; we just need the trait indirection to handle + /// different types since calling intrinsics with generics doesn't work. + unsafe fn unchecked_funnel_shr(self, rhs: Self, shift: u32) -> Self; +} + +macro_rules! impl_funnel_shifts { + ($($type:ident),*) => {$( + #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")] + impl const FunnelShift for $type { + #[cfg_attr(miri, track_caller)] + #[inline] + unsafe fn unchecked_funnel_shl(self, rhs: Self, shift: u32) -> Self { + // This implementation is also used by Miri so we have to check the precondition. + // SAFETY: this is guaranteed by the caller + unsafe { super::assume(shift < $type::BITS) }; + if shift == 0 { + self + } else { + // SAFETY: + // - `shift < T::BITS`, which satisfies `unchecked_shl` + // - this also ensures that `T::BITS - shift < T::BITS` (shift = 0 is checked + // above), which satisfies `unchecked_shr` + // - because the types are unsigned, the combination are disjoint bits (this is + // not true if they're signed, since SHR will fill in the empty space with a + // sign bit, not zero) + unsafe { + super::disjoint_bitor( + super::unchecked_shl(self, shift), + super::unchecked_shr(rhs, $type::BITS - shift), + ) + } + } + } + + #[cfg_attr(miri, track_caller)] + #[inline] + unsafe fn unchecked_funnel_shr(self, rhs: Self, shift: u32) -> Self { + // This implementation is also used by Miri so we have to check the precondition. + // SAFETY: this is guaranteed by the caller + unsafe { super::assume(shift < $type::BITS) }; + if shift == 0 { + rhs + } else { + // SAFETY: + // - `shift < T::BITS`, which satisfies `unchecked_shr` + // - this also ensures that `T::BITS - shift < T::BITS` (shift = 0 is checked + // above), which satisfies `unchecked_shl` + // - because the types are unsigned, the combination are disjoint bits (this is + // not true if they're signed, since SHR will fill in the empty space with a + // sign bit, not zero) + unsafe { + super::disjoint_bitor( + super::unchecked_shl(self, $type::BITS - shift), + super::unchecked_shr(rhs, shift), + ) + } + } + } + } + )*}; +} + +impl_funnel_shifts! { + u8, u16, u32, u64, u128, usize +} diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 904aa52c784..bffffbc29c1 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2102,6 +2102,61 @@ pub const fn saturating_add<T: Copy>(a: T, b: T) -> T; #[rustc_intrinsic] pub const fn saturating_sub<T: Copy>(a: T, b: T) -> T; +/// Funnel Shift left. +/// +/// Concatenates `a` and `b` (with `a` in the most significant half), +/// creating an integer twice as wide. Then shift this integer left +/// by `shift`), and extract the most significant half. If `a` and `b` +/// are the same, this is equivalent to a rotate left operation. +/// +/// It is undefined behavior if `shift` is greater than or equal to the +/// bit size of `T`. +/// +/// Safe versions of this intrinsic are available on the integer primitives +/// via the `funnel_shl` method. For example, [`u32::funnel_shl`]. +#[rustc_intrinsic] +#[rustc_nounwind] +#[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")] +#[unstable(feature = "funnel_shifts", issue = "145686")] +#[track_caller] +#[miri::intrinsic_fallback_is_spec] +pub const unsafe fn unchecked_funnel_shl<T: [const] fallback::FunnelShift>( + a: T, + b: T, + shift: u32, +) -> T { + // SAFETY: caller ensures that `shift` is in-range + unsafe { a.unchecked_funnel_shl(b, shift) } +} + +/// Funnel Shift right. +/// +/// Concatenates `a` and `b` (with `a` in the most significant half), +/// creating an integer twice as wide. Then shift this integer right +/// by `shift` (taken modulo the bit size of `T`), and extract the +/// least significant half. If `a` and `b` are the same, this is equivalent +/// to a rotate right operation. +/// +/// It is undefined behavior if `shift` is greater than or equal to the +/// bit size of `T`. +/// +/// Safer versions of this intrinsic are available on the integer primitives +/// via the `funnel_shr` method. For example, [`u32::funnel_shr`] +#[rustc_intrinsic] +#[rustc_nounwind] +#[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")] +#[unstable(feature = "funnel_shifts", issue = "145686")] +#[track_caller] +#[miri::intrinsic_fallback_is_spec] +pub const unsafe fn unchecked_funnel_shr<T: [const] fallback::FunnelShift>( + a: T, + b: T, + shift: u32, +) -> T { + // SAFETY: caller ensures that `shift` is in-range + unsafe { a.unchecked_funnel_shr(b, shift) } +} + /// This is an implementation detail of [`crate::ptr::read`] and should /// not be used anywhere else. See its comments for why this exists. /// diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 943b88e2330..3ebdf7b4727 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -321,6 +321,7 @@ impl<A: Default, B: Default> Default for Chain<A, B> { /// /// // take requires `Default` /// let _: Chain<_, _> = mem::take(&mut foo.0); + /// ``` fn default() -> Self { Chain::new(Default::default(), Default::default()) } diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index a6522659620..a55de75d56c 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -317,6 +317,108 @@ impl<I: Iterator> Peekable<I> { { self.next_if(|next| next == expected) } + + /// Consumes the next value of this iterator and applies a function `f` on it, + /// returning the result if the closure returns `Ok`. + /// + /// Otherwise if the closure returns `Err` the value is put back for the next iteration. + /// + /// The content of the `Err` variant is typically the original value of the closure, + /// but this is not required. If a different value is returned, + /// the next `peek()` or `next()` call will result in this new value. + /// This is similar to modifying the output of `peek_mut()`. + /// + /// If the closure panics, the next value will always be consumed and dropped + /// even if the panic is caught, because the closure never returned an `Err` value to put back. + /// + /// # Examples + /// + /// Parse the leading decimal number from an iterator of characters. + /// ``` + /// #![feature(peekable_next_if_map)] + /// let mut iter = "125 GOTO 10".chars().peekable(); + /// let mut line_num = 0_u32; + /// while let Some(digit) = iter.next_if_map(|c| c.to_digit(10).ok_or(c)) { + /// line_num = line_num * 10 + digit; + /// } + /// assert_eq!(line_num, 125); + /// assert_eq!(iter.collect::<String>(), " GOTO 10"); + /// ``` + /// + /// Matching custom types. + /// ``` + /// #![feature(peekable_next_if_map)] + /// + /// #[derive(Debug, PartialEq, Eq)] + /// enum Node { + /// Comment(String), + /// Red(String), + /// Green(String), + /// Blue(String), + /// } + /// + /// /// Combines all consecutive `Comment` nodes into a single one. + /// fn combine_comments(nodes: Vec<Node>) -> Vec<Node> { + /// let mut result = Vec::with_capacity(nodes.len()); + /// let mut iter = nodes.into_iter().peekable(); + /// let mut comment_text = None::<String>; + /// loop { + /// // Typically the closure in .next_if_map() matches on the input, + /// // extracts the desired pattern into an `Ok`, + /// // and puts the rest into an `Err`. + /// while let Some(text) = iter.next_if_map(|node| match node { + /// Node::Comment(text) => Ok(text), + /// other => Err(other), + /// }) { + /// comment_text.get_or_insert_default().push_str(&text); + /// } + /// + /// if let Some(text) = comment_text.take() { + /// result.push(Node::Comment(text)); + /// } + /// if let Some(node) = iter.next() { + /// result.push(node); + /// } else { + /// break; + /// } + /// } + /// result + /// } + ///# assert_eq!( // hiding the test to avoid cluttering the documentation. + ///# combine_comments(vec![ + ///# Node::Comment("The".to_owned()), + ///# Node::Comment("Quick".to_owned()), + ///# Node::Comment("Brown".to_owned()), + ///# Node::Red("Fox".to_owned()), + ///# Node::Green("Jumped".to_owned()), + ///# Node::Comment("Over".to_owned()), + ///# Node::Blue("The".to_owned()), + ///# Node::Comment("Lazy".to_owned()), + ///# Node::Comment("Dog".to_owned()), + ///# ]), + ///# vec![ + ///# Node::Comment("TheQuickBrown".to_owned()), + ///# Node::Red("Fox".to_owned()), + ///# Node::Green("Jumped".to_owned()), + ///# Node::Comment("Over".to_owned()), + ///# Node::Blue("The".to_owned()), + ///# Node::Comment("LazyDog".to_owned()), + ///# ], + ///# ) + /// ``` + #[unstable(feature = "peekable_next_if_map", issue = "143702")] + pub fn next_if_map<R>(&mut self, f: impl FnOnce(I::Item) -> Result<R, I::Item>) -> Option<R> { + let unpeek = if let Some(item) = self.next() { + match f(item) { + Ok(result) => return Some(result), + Err(item) => Some(item), + } + } else { + None + }; + self.peeked = Some(unpeek); + None + } } #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 82506379cac..c306011bdda 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -156,6 +156,7 @@ #![feature(f128)] #![feature(freeze_impls)] #![feature(fundamental)] +#![feature(funnel_shifts)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(intrinsics)] diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 02bb8179293..8868f05f1b9 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -258,7 +258,8 @@ impl<T: ?Sized> ManuallyDrop<T> { } #[stable(feature = "manually_drop", since = "1.20.0")] -impl<T: ?Sized> Deref for ManuallyDrop<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: ?Sized> const Deref for ManuallyDrop<T> { type Target = T; #[inline(always)] fn deref(&self) -> &T { @@ -267,7 +268,8 @@ impl<T: ?Sized> Deref for ManuallyDrop<T> { } #[stable(feature = "manually_drop", since = "1.20.0")] -impl<T: ?Sized> DerefMut for ManuallyDrop<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: ?Sized> const DerefMut for ManuallyDrop<T> { #[inline(always)] fn deref_mut(&mut self) -> &mut T { &mut self.value diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 3bf113d017c..9779fb8fe4d 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1087,7 +1087,7 @@ impl fmt::Debug for IpAddr { } #[stable(feature = "ip_from_ip", since = "1.16.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<Ipv4Addr> for IpAddr { /// Copies this address to a new `IpAddr::V4`. /// @@ -1110,7 +1110,7 @@ impl const From<Ipv4Addr> for IpAddr { } #[stable(feature = "ip_from_ip", since = "1.16.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<Ipv6Addr> for IpAddr { /// Copies this address to a new `IpAddr::V6`. /// @@ -1221,7 +1221,7 @@ impl Ord for Ipv4Addr { } #[stable(feature = "ip_u32", since = "1.1.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<Ipv4Addr> for u32 { /// Uses [`Ipv4Addr::to_bits`] to convert an IPv4 address to a host byte order `u32`. #[inline] @@ -1231,7 +1231,7 @@ impl const From<Ipv4Addr> for u32 { } #[stable(feature = "ip_u32", since = "1.1.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<u32> for Ipv4Addr { /// Uses [`Ipv4Addr::from_bits`] to convert a host byte order `u32` into an IPv4 address. #[inline] @@ -1241,7 +1241,7 @@ impl const From<u32> for Ipv4Addr { } #[stable(feature = "from_slice_v4", since = "1.9.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<[u8; 4]> for Ipv4Addr { /// Creates an `Ipv4Addr` from a four element byte array. /// @@ -1260,7 +1260,7 @@ impl const From<[u8; 4]> for Ipv4Addr { } #[stable(feature = "ip_from_slice", since = "1.17.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<[u8; 4]> for IpAddr { /// Creates an `IpAddr::V4` from a four element byte array. /// @@ -2215,7 +2215,7 @@ impl Ord for Ipv6Addr { } #[stable(feature = "i128", since = "1.26.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<Ipv6Addr> for u128 { /// Uses [`Ipv6Addr::to_bits`] to convert an IPv6 address to a host byte order `u128`. #[inline] @@ -2224,7 +2224,7 @@ impl const From<Ipv6Addr> for u128 { } } #[stable(feature = "i128", since = "1.26.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<u128> for Ipv6Addr { /// Uses [`Ipv6Addr::from_bits`] to convert a host byte order `u128` to an IPv6 address. #[inline] @@ -2234,7 +2234,7 @@ impl const From<u128> for Ipv6Addr { } #[stable(feature = "ipv6_from_octets", since = "1.9.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<[u8; 16]> for Ipv6Addr { /// Creates an `Ipv6Addr` from a sixteen element byte array. /// @@ -2262,7 +2262,7 @@ impl const From<[u8; 16]> for Ipv6Addr { } #[stable(feature = "ipv6_from_segments", since = "1.16.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<[u16; 8]> for Ipv6Addr { /// Creates an `Ipv6Addr` from an eight element 16-bit array. /// @@ -2291,7 +2291,7 @@ impl const From<[u16; 8]> for Ipv6Addr { } #[stable(feature = "ip_from_slice", since = "1.17.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<[u8; 16]> for IpAddr { /// Creates an `IpAddr::V6` from a sixteen element byte array. /// @@ -2319,7 +2319,7 @@ impl const From<[u8; 16]> for IpAddr { } #[stable(feature = "ip_from_slice", since = "1.17.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<[u16; 8]> for IpAddr { /// Creates an `IpAddr::V6` from an eight element 16-bit array. /// diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs index df99e9b20c2..ccc53c156d3 100644 --- a/library/core/src/net/socket_addr.rs +++ b/library/core/src/net/socket_addr.rs @@ -592,7 +592,7 @@ impl SocketAddrV6 { } #[stable(feature = "ip_from_ip", since = "1.16.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<SocketAddrV4> for SocketAddr { /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`]. #[inline] @@ -602,7 +602,7 @@ impl const From<SocketAddrV4> for SocketAddr { } #[stable(feature = "ip_from_ip", since = "1.16.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<SocketAddrV6> for SocketAddr { /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`]. #[inline] @@ -612,7 +612,7 @@ impl const From<SocketAddrV6> for SocketAddr { } #[stable(feature = "addr_from_into_ip", since = "1.17.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<I: [const] Into<IpAddr>> const From<(I, u16)> for SocketAddr { /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`]. /// diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index faa52329827..8a353dc0fbe 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -20,7 +20,7 @@ impl fmt::Display for TryFromIntError { impl Error for TryFromIntError {} #[stable(feature = "try_from", since = "1.34.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<Infallible> for TryFromIntError { fn from(x: Infallible) -> TryFromIntError { match x {} @@ -28,7 +28,7 @@ impl const From<Infallible> for TryFromIntError { } #[unstable(feature = "never_type", issue = "35121")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<!> for TryFromIntError { #[inline] fn from(never: !) -> TryFromIntError { diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 25864db5fea..db70fb65d44 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1285,7 +1285,7 @@ macro_rules! int_impl { /// /// ```should_panic #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")] - /// + /// ``` #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index acfe38b7a37..54d5a63633c 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -454,6 +454,9 @@ impl u8 { rot = 2, rot_op = "0x82", rot_result = "0xa", + fsh_op = "0x36", + fshl_result = "0x8", + fshr_result = "0x8d", swap_op = "0x12", swapped = "0x12", reversed = "0x48", @@ -1088,6 +1091,9 @@ impl u16 { rot = 4, rot_op = "0xa003", rot_result = "0x3a", + fsh_op = "0x2de", + fshl_result = "0x30", + fshr_result = "0x302d", swap_op = "0x1234", swapped = "0x3412", reversed = "0x2c48", @@ -1135,6 +1141,9 @@ impl u32 { rot = 8, rot_op = "0x10000b3", rot_result = "0xb301", + fsh_op = "0x2fe78e45", + fshl_result = "0xb32f", + fshr_result = "0xb32fe78e", swap_op = "0x12345678", swapped = "0x78563412", reversed = "0x1e6a2c48", @@ -1158,6 +1167,9 @@ impl u64 { rot = 12, rot_op = "0xaa00000000006e1", rot_result = "0x6e10aa", + fsh_op = "0x2fe78e45983acd98", + fshl_result = "0x6e12fe", + fshr_result = "0x6e12fe78e45983ac", swap_op = "0x1234567890123456", swapped = "0x5634129078563412", reversed = "0x6a2c48091e6a2c48", @@ -1181,6 +1193,9 @@ impl u128 { rot = 16, rot_op = "0x13f40000000000000000000000004f76", rot_result = "0x4f7613f4", + fsh_op = "0x2fe78e45983acd98039000008736273", + fshl_result = "0x4f7602fe", + fshr_result = "0x4f7602fe78e45983acd9803900000873", swap_op = "0x12345678901234567890123456789012", swapped = "0x12907856341290785634129078563412", reversed = "0x48091e6a2c48091e6a2c48091e6a2c48", @@ -1207,6 +1222,9 @@ impl usize { rot = 4, rot_op = "0xa003", rot_result = "0x3a", + fsh_op = "0x2fe78e45983acd98039000008736273", + fshl_result = "0x4f7602fe", + fshr_result = "0x4f7602fe78e45983acd9803900000873", swap_op = "0x1234", swapped = "0x3412", reversed = "0x2c48", @@ -1231,6 +1249,9 @@ impl usize { rot = 8, rot_op = "0x10000b3", rot_result = "0xb301", + fsh_op = "0x2fe78e45", + fshl_result = "0xb32f", + fshr_result = "0xb32fe78e", swap_op = "0x12345678", swapped = "0x78563412", reversed = "0x1e6a2c48", @@ -1255,6 +1276,9 @@ impl usize { rot = 12, rot_op = "0xaa00000000006e1", rot_result = "0x6e10aa", + fsh_op = "0x2fe78e45983acd98", + fshl_result = "0x6e12fe", + fshr_result = "0x6e12fe78e45983ac", swap_op = "0x1234567890123456", swapped = "0x5634129078563412", reversed = "0x6a2c48091e6a2c48", @@ -1378,7 +1402,7 @@ const fn from_ascii_radix_panic(radix: u32) -> ! { macro_rules! from_str_int_impl { ($signedness:ident $($int_ty:ty)+) => {$( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const FromStr for $int_ty { type Err = ParseIntError; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index e02d9260a16..0f38081c355 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -297,7 +297,7 @@ where } #[stable(feature = "from_nonzero", since = "1.31.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T> const From<NonZero<T>> for T where T: ZeroablePrimitive, diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index c1e656fdea2..0ce9c259c40 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -14,6 +14,9 @@ macro_rules! uint_impl { rot = $rot:literal, rot_op = $rot_op:literal, rot_result = $rot_result:literal, + fsh_op = $fsh_op:literal, + fshl_result = $fshl_result:literal, + fshr_result = $fshr_result:literal, swap_op = $swap_op:literal, swapped = $swapped:literal, reversed = $reversed:literal, @@ -375,6 +378,76 @@ macro_rules! uint_impl { return intrinsics::rotate_right(self, n); } + /// Performs a left funnel shift (concatenates `self` with `rhs`, with `self` + /// making up the most significant half, then shifts the combined value left + /// by `n`, and most significant half is extracted to produce the result). + /// + /// Please note this isn't the same operation as the `<<` shifting operator or + /// [`rotate_left`](Self::rotate_left), although `a.funnel_shl(a, n)` is *equivalent* + /// to `a.rotate_left(n)`. + /// + /// # Panics + /// + /// If `n` is greater than or equal to the number of bits in `self` + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(funnel_shifts)] + #[doc = concat!("let a = ", $rot_op, stringify!($SelfT), ";")] + #[doc = concat!("let b = ", $fsh_op, stringify!($SelfT), ";")] + #[doc = concat!("let m = ", $fshl_result, ";")] + /// + #[doc = concat!("assert_eq!(a.funnel_shl(b, ", $rot, "), m);")] + /// ``` + #[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")] + #[unstable(feature = "funnel_shifts", issue = "145686")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn funnel_shl(self, rhs: Self, n: u32) -> Self { + assert!(n < Self::BITS, "attempt to funnel shift left with overflow"); + // SAFETY: just checked that `shift` is in-range + unsafe { intrinsics::unchecked_funnel_shl(self, rhs, n) } + } + + /// Performs a right funnel shift (concatenates `self` and `rhs`, with `self` + /// making up the most significant half, then shifts the combined value right + /// by `n`, and least significant half is extracted to produce the result). + /// + /// Please note this isn't the same operation as the `>>` shifting operator or + /// [`rotate_right`](Self::rotate_right), although `a.funnel_shr(a, n)` is *equivalent* + /// to `a.rotate_right(n)`. + /// + /// # Panics + /// + /// If `n` is greater than or equal to the number of bits in `self` + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(funnel_shifts)] + #[doc = concat!("let a = ", $rot_op, stringify!($SelfT), ";")] + #[doc = concat!("let b = ", $fsh_op, stringify!($SelfT), ";")] + #[doc = concat!("let m = ", $fshr_result, ";")] + /// + #[doc = concat!("assert_eq!(a.funnel_shr(b, ", $rot, "), m);")] + /// ``` + #[rustc_const_unstable(feature = "funnel_shifts", issue = "145686")] + #[unstable(feature = "funnel_shifts", issue = "145686")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn funnel_shr(self, rhs: Self, n: u32) -> Self { + assert!(n < Self::BITS, "attempt to funnel shift right with overflow"); + // SAFETY: just checked that `shift` is in-range + unsafe { intrinsics::unchecked_funnel_shr(self, rhs, n) } + } + /// Reverses the byte order of the integer. /// /// # Examples @@ -1620,7 +1693,7 @@ macro_rules! uint_impl { /// /// ```should_panic #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")] - /// + /// ``` #[stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_stable(feature = "strict_overflow_ops", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 5f68c1f55c2..877b83d3a61 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -136,7 +136,7 @@ use crate::marker::PointeeSized; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Deref"] #[const_trait] -#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] pub trait Deref: PointeeSized { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] @@ -152,7 +152,7 @@ pub trait Deref: PointeeSized { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T: ?Sized> const Deref for &T { type Target = T; @@ -166,7 +166,7 @@ impl<T: ?Sized> const Deref for &T { impl<T: ?Sized> !DerefMut for &T {} #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T: ?Sized> const Deref for &mut T { type Target = T; @@ -268,7 +268,7 @@ impl<T: ?Sized> const Deref for &mut T { #[doc(alias = "*")] #[stable(feature = "rust1", since = "1.0.0")] #[const_trait] -#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] pub trait DerefMut: [const] Deref + PointeeSized { /// Mutably dereferences the value. #[stable(feature = "rust1", since = "1.0.0")] @@ -277,7 +277,7 @@ pub trait DerefMut: [const] Deref + PointeeSized { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T: ?Sized> const DerefMut for &mut T { fn deref_mut(&mut self) -> &mut T { self diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index c0a27775694..58a9431bd84 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -836,6 +836,7 @@ pub trait RangeBounds<T: ?Sized> { /// assert!(!(0.0..1.0).contains(&f32::NAN)); /// assert!(!(0.0..f32::NAN).contains(&0.5)); /// assert!(!(f32::NAN..1.0).contains(&0.5)); + /// ``` #[inline] #[stable(feature = "range_contains", since = "1.35.0")] fn contains<U>(&self, item: &U) -> bool diff --git a/library/core/src/option.rs b/library/core/src/option.rs index fa09409b6da..2a57536500a 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1379,11 +1379,12 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "option_deref", since = "1.40.0")] - pub fn as_deref(&self) -> Option<&T::Target> + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn as_deref(&self) -> Option<&T::Target> where - T: Deref, + T: [const] Deref, { - self.as_ref().map(|t| t.deref()) + self.as_ref().map(Deref::deref) } /// Converts from `Option<T>` (or `&mut Option<T>`) to `Option<&mut T::Target>`. @@ -1402,11 +1403,12 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "option_deref", since = "1.40.0")] - pub fn as_deref_mut(&mut self) -> Option<&mut T::Target> + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target> where - T: DerefMut, + T: [const] DerefMut, { - self.as_mut().map(|t| t.deref_mut()) + self.as_mut().map(DerefMut::deref_mut) } ///////////////////////////////////////////////////////////////////////// @@ -2180,7 +2182,7 @@ const fn expect_failed(msg: &str) -> ! { ///////////////////////////////////////////////////////////////////////////// #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] impl<T> const Clone for Option<T> where // FIXME(const_hack): the T: ~const Destruct should be inferred from the Self: ~const Destruct in clone_from. @@ -2269,7 +2271,7 @@ impl<'a, T> IntoIterator for &'a mut Option<T> { } #[stable(since = "1.12.0", feature = "option_from")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T> const From<T> for Option<T> { /// Moves `val` into a new [`Some`]. /// @@ -2286,7 +2288,7 @@ impl<T> const From<T> for Option<T> { } #[stable(feature = "option_ref_from_ref_option", since = "1.30.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<'a, T> const From<&'a Option<T>> for Option<&'a T> { /// Converts from `&Option<T>` to `Option<&T>`. /// @@ -2314,7 +2316,7 @@ impl<'a, T> const From<&'a Option<T>> for Option<&'a T> { } #[stable(feature = "option_ref_from_ref_option", since = "1.30.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<'a, T> const From<&'a mut Option<T>> for Option<&'a mut T> { /// Converts from `&mut Option<T>` to `Option<&mut T>` /// diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index a60f0799c0e..722af551038 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -248,7 +248,8 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicBool {} impl<T> RefUnwindSafe for crate::sync::atomic::AtomicPtr<T> {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T> Deref for AssertUnwindSafe<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const Deref for AssertUnwindSafe<T> { type Target = T; fn deref(&self) -> &T { @@ -257,7 +258,8 @@ impl<T> Deref for AssertUnwindSafe<T> { } #[stable(feature = "catch_unwind", since = "1.9.0")] -impl<T> DerefMut for AssertUnwindSafe<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const DerefMut for AssertUnwindSafe<T> { fn deref_mut(&mut self) -> &mut T { &mut self.0 } diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 14bf7ba9015..535830f2e74 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1359,7 +1359,11 @@ impl<Ptr: Deref> Pin<Ptr> { /// ruled out by the contract of `Pin::new_unchecked`. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn as_ref(&self) -> Pin<&Ptr::Target> { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn as_ref(&self) -> Pin<&Ptr::Target> + where + Ptr: [const] Deref, + { // SAFETY: see documentation on this function unsafe { Pin::new_unchecked(&*self.pointer) } } @@ -1403,7 +1407,11 @@ impl<Ptr: DerefMut> Pin<Ptr> { /// ``` #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn as_mut(&mut self) -> Pin<&mut Ptr::Target> + where + Ptr: [const] DerefMut, + { // SAFETY: see documentation on this function unsafe { Pin::new_unchecked(&mut *self.pointer) } } @@ -1418,7 +1426,11 @@ impl<Ptr: DerefMut> Pin<Ptr> { #[stable(feature = "pin_deref_mut", since = "1.84.0")] #[must_use = "`self` will be dropped if the result is not used"] #[inline(always)] - pub fn as_deref_mut(self: Pin<&mut Self>) -> Pin<&mut Ptr::Target> { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn as_deref_mut(self: Pin<&mut Self>) -> Pin<&mut Ptr::Target> + where + Ptr: [const] DerefMut, + { // SAFETY: What we're asserting here is that going from // // Pin<&mut Pin<Ptr>> @@ -1669,7 +1681,8 @@ impl<T: ?Sized> Pin<&'static mut T> { } #[stable(feature = "pin", since = "1.33.0")] -impl<Ptr: Deref> Deref for Pin<Ptr> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<Ptr: [const] Deref> const Deref for Pin<Ptr> { type Target = Ptr::Target; fn deref(&self) -> &Ptr::Target { Pin::get_ref(Pin::as_ref(self)) @@ -1677,7 +1690,8 @@ impl<Ptr: Deref> Deref for Pin<Ptr> { } #[stable(feature = "pin", since = "1.33.0")] -impl<Ptr: DerefMut<Target: Unpin>> DerefMut for Pin<Ptr> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<Ptr: [const] DerefMut<Target: Unpin>> const DerefMut for Pin<Ptr> { fn deref_mut(&mut self) -> &mut Ptr::Target { Pin::get_mut(Pin::as_mut(self)) } diff --git a/library/core/src/pin/unsafe_pinned.rs b/library/core/src/pin/unsafe_pinned.rs index ede6e0d6106..ae03809b458 100644 --- a/library/core/src/pin/unsafe_pinned.rs +++ b/library/core/src/pin/unsafe_pinned.rs @@ -148,7 +148,8 @@ impl<T: Default> Default for UnsafePinned<T> { } #[unstable(feature = "unsafe_pinned", issue = "125735")] -impl<T> From<T> for UnsafePinned<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const From<T> for UnsafePinned<T> { /// Creates a new `UnsafePinned<T>` containing the given value. fn from(value: T) -> Self { UnsafePinned::new(value) diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 402634e49b3..bc7d3a1de71 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -171,7 +171,8 @@ impl fmt::Debug for Alignment { } #[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl TryFrom<NonZero<usize>> for Alignment { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const TryFrom<NonZero<usize>> for Alignment { type Error = num::TryFromIntError; #[inline] @@ -181,7 +182,8 @@ impl TryFrom<NonZero<usize>> for Alignment { } #[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl TryFrom<usize> for Alignment { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const TryFrom<usize> for Alignment { type Error = num::TryFromIntError; #[inline] @@ -191,7 +193,7 @@ impl TryFrom<usize> for Alignment { } #[unstable(feature = "ptr_alignment_type", issue = "102070")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<Alignment> for NonZero<usize> { #[inline] fn from(align: Alignment) -> NonZero<usize> { @@ -200,7 +202,7 @@ impl const From<Alignment> for NonZero<usize> { } #[unstable(feature = "ptr_alignment_type", issue = "102070")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<Alignment> for usize { #[inline] fn from(align: Alignment) -> usize { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 3fe4b08d459..ce6eee4f911 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -106,6 +106,7 @@ impl<T: PointeeSized> *mut T { /// /// // This dereference is UB. The pointer only has provenance for `x` but points to `y`. /// println!("{:?}", unsafe { &*bad }); + /// ``` #[unstable(feature = "set_ptr_value", issue = "75091")] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 117eb18826e..10f83120428 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1711,7 +1711,8 @@ impl<T: PointeeSized> hash::Hash for NonNull<T> { } #[unstable(feature = "ptr_internals", issue = "none")] -impl<T: PointeeSized> From<Unique<T>> for NonNull<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: PointeeSized> const From<Unique<T>> for NonNull<T> { #[inline] fn from(unique: Unique<T>) -> Self { unique.as_non_null_ptr() @@ -1719,7 +1720,8 @@ impl<T: PointeeSized> From<Unique<T>> for NonNull<T> { } #[stable(feature = "nonnull", since = "1.25.0")] -impl<T: PointeeSized> From<&mut T> for NonNull<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: PointeeSized> const From<&mut T> for NonNull<T> { /// Converts a `&mut T` to a `NonNull<T>`. /// /// This conversion is safe and infallible since references cannot be null. @@ -1730,7 +1732,8 @@ impl<T: PointeeSized> From<&mut T> for NonNull<T> { } #[stable(feature = "nonnull", since = "1.25.0")] -impl<T: PointeeSized> From<&T> for NonNull<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: PointeeSized> const From<&T> for NonNull<T> { /// Converts a `&T` to a `NonNull<T>`. /// /// This conversion is safe and infallible since references cannot be null. diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index 4302c1b1e44..cdc8b6cc936 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -189,7 +189,8 @@ impl<T: PointeeSized> fmt::Pointer for Unique<T> { } #[unstable(feature = "ptr_internals", issue = "none")] -impl<T: PointeeSized> From<&mut T> for Unique<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: PointeeSized> const From<&mut T> for Unique<T> { /// Converts a `&mut T` to a `Unique<T>`. /// /// This conversion is infallible since references cannot be null. @@ -200,7 +201,8 @@ impl<T: PointeeSized> From<&mut T> for Unique<T> { } #[unstable(feature = "ptr_internals", issue = "none")] -impl<T: PointeeSized> From<NonNull<T>> for Unique<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T: PointeeSized> const From<NonNull<T>> for Unique<T> { /// Converts a `NonNull<T>` to a `Unique<T>`. /// /// This conversion is infallible since `NonNull` cannot be null. diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 7158fa0fcf0..332ae51d848 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -192,7 +192,7 @@ impl<T> IntoBounds<T> for Range<T> { } #[unstable(feature = "new_range_api", issue = "125687")] -#[rustc_const_unstable(feature = "const_index", issue = "143775")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T> const From<Range<T>> for legacy::Range<T> { #[inline] fn from(value: Range<T>) -> Self { @@ -201,7 +201,7 @@ impl<T> const From<Range<T>> for legacy::Range<T> { } #[unstable(feature = "new_range_api", issue = "125687")] -#[rustc_const_unstable(feature = "const_index", issue = "143775")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T> const From<legacy::Range<T>> for Range<T> { #[inline] fn from(value: legacy::Range<T>) -> Self { @@ -377,7 +377,7 @@ impl<T> IntoBounds<T> for RangeInclusive<T> { } #[unstable(feature = "new_range_api", issue = "125687")] -#[rustc_const_unstable(feature = "const_index", issue = "143775")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl<T> const From<RangeInclusive<T>> for legacy::RangeInclusive<T> { #[inline] fn from(value: RangeInclusive<T>) -> Self { @@ -385,7 +385,8 @@ impl<T> const From<RangeInclusive<T>> for legacy::RangeInclusive<T> { } } #[unstable(feature = "new_range_api", issue = "125687")] -impl<T> From<legacy::RangeInclusive<T>> for RangeInclusive<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const From<legacy::RangeInclusive<T>> for RangeInclusive<T> { #[inline] fn from(value: legacy::RangeInclusive<T>) -> Self { assert!( diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 6148bdb866a..7dffab9b316 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1034,11 +1034,12 @@ impl<T, E> Result<T, E> { /// ``` #[inline] #[stable(feature = "inner_deref", since = "1.47.0")] - pub fn as_deref(&self) -> Result<&T::Target, &E> + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn as_deref(&self) -> Result<&T::Target, &E> where - T: Deref, + T: [const] Deref, { - self.as_ref().map(|t| t.deref()) + self.as_ref().map(Deref::deref) } /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut <T as DerefMut>::Target, &mut E>`. @@ -1061,11 +1062,12 @@ impl<T, E> Result<T, E> { /// ``` #[inline] #[stable(feature = "inner_deref", since = "1.47.0")] - pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> where - T: DerefMut, + T: [const] DerefMut, { - self.as_mut().map(|t| t.deref_mut()) + self.as_mut().map(DerefMut::deref_mut) } ///////////////////////////////////////////////////////////////////////// @@ -1347,7 +1349,7 @@ impl<T, E> Result<T, E> { #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")] #[inline] #[rustc_allow_const_fn_unstable(const_precise_live_drops)] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] pub const fn into_ok(self) -> T where E: [const] Into<!>, @@ -1384,7 +1386,7 @@ impl<T, E> Result<T, E> { #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")] #[inline] #[rustc_allow_const_fn_unstable(const_precise_live_drops)] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] pub const fn into_err(self) -> E where T: [const] Into<!>, diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index f1db385e212..04fdaa8143e 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -3078,7 +3078,8 @@ impl str { } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<[u8]> for str { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<[u8]> for str { #[inline] fn as_ref(&self) -> &[u8] { self.as_bytes() diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index dc88f35eca7..971c8e829c6 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -826,7 +826,7 @@ unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[const_trait] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] pub trait FromStr: Sized { /// The associated error which can be returned from parsing. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 7bd68bcd0bc..1b4a54b1b7a 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -2516,7 +2516,7 @@ impl<T> AtomicPtr<T> { #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "atomic_bool_from", since = "1.24.0")] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<bool> for AtomicBool { /// Converts a `bool` into an `AtomicBool`. /// @@ -2535,7 +2535,8 @@ impl const From<bool> for AtomicBool { #[cfg(target_has_atomic_load_store = "ptr")] #[stable(feature = "atomic_from", since = "1.23.0")] -impl<T> From<*mut T> for AtomicPtr<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const From<*mut T> for AtomicPtr<T> { /// Converts a `*mut T` into an `AtomicPtr<T>`. #[inline] fn from(p: *mut T) -> Self { @@ -2614,7 +2615,7 @@ macro_rules! atomic_int { } #[$stable_from] - #[rustc_const_unstable(feature = "const_try", issue = "74935")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From<$int_type> for $atomic_type { #[doc = concat!("Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`.")] #[inline] diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs index 340b0b79e40..cf086bf4f50 100644 --- a/library/core/src/sync/exclusive.rs +++ b/library/core/src/sync/exclusive.rs @@ -163,7 +163,8 @@ impl<T: ?Sized> Exclusive<T> { } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl<T> From<T> for Exclusive<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const From<T> for Exclusive<T> { #[inline] fn from(t: T) -> Self { Self::new(t) diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 59ffe7ad49c..380abac0ae9 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -215,7 +215,8 @@ impl<T, E> Poll<Option<Result<T, E>>> { } #[stable(feature = "futures_api", since = "1.36.0")] -impl<T> From<T> for Poll<T> { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl<T> const From<T> for Poll<T> { /// Moves the value into a [`Poll::Ready`] to make a `Poll<T>`. /// /// # Example diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index bb7efe582f7..97eb9ec7dc5 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -901,7 +901,8 @@ impl Clone for LocalWaker { } #[unstable(feature = "local_waker", issue = "118959")] -impl AsRef<LocalWaker> for Waker { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<LocalWaker> for Waker { fn as_ref(&self) -> &LocalWaker { // SAFETY: LocalWaker is just Waker without thread safety unsafe { transmute(self) } diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 23a0a6877df..2cdee1803a9 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -133,6 +133,7 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[stable(feature = "array_tuple_conv", since = "1.71.0")] + // can't do const From due to https://github.com/rust-lang/rust/issues/144280 impl<T> From<[T; ${count($T)}]> for ($(${ignore($T)} T,)+) { #[inline] #[allow(non_snake_case)] @@ -146,6 +147,7 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[stable(feature = "array_tuple_conv", since = "1.71.0")] + // can't do const From due to https://github.com/rust-lang/rust/issues/144280 impl<T> From<($(${ignore($T)} T,)+)> for [T; ${count($T)}] { #[inline] #[allow(non_snake_case)] diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index 55f64f1e96e..f78983bc339 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -1,4 +1,16 @@ ///! This file is generated by `./x run src/tools/unicode-table-generator`; do not edit manually! +// Alphabetic : 1727 bytes, 142759 codepoints in 757 ranges (U+000041 - U+0323B0) using skiplist +// Case_Ignorable : 1053 bytes, 2749 codepoints in 452 ranges (U+000027 - U+0E01F0) using skiplist +// Cased : 407 bytes, 4578 codepoints in 159 ranges (U+000041 - U+01F18A) using skiplist +// Cc : 9 bytes, 65 codepoints in 2 ranges (U+000000 - U+0000A0) using skiplist +// Grapheme_Extend : 887 bytes, 2193 codepoints in 375 ranges (U+000300 - U+0E01F0) using skiplist +// Lowercase : 935 bytes, 2569 codepoints in 675 ranges (U+000061 - U+01E944) using bitset +// N : 457 bytes, 1911 codepoints in 144 ranges (U+000030 - U+01FBFA) using skiplist +// Uppercase : 799 bytes, 1978 codepoints in 656 ranges (U+000041 - U+01F18A) using bitset +// White_Space : 256 bytes, 25 codepoints in 10 ranges (U+000009 - U+003001) using cascading +// to_lower : 11484 bytes +// to_upper : 13432 bytes +// Total : 31446 bytes #[inline(always)] const fn bitset_search< @@ -747,7 +759,7 @@ pub mod conversions { } } - static LOWERCASE_TABLE: &[(char, u32)] = &[ + static LOWERCASE_TABLE: &[(char, u32); 1434] = &[ ('\u{c0}', 224), ('\u{c1}', 225), ('\u{c2}', 226), ('\u{c3}', 227), ('\u{c4}', 228), ('\u{c5}', 229), ('\u{c6}', 230), ('\u{c7}', 231), ('\u{c8}', 232), ('\u{c9}', 233), ('\u{ca}', 234), ('\u{cb}', 235), ('\u{cc}', 236), ('\u{cd}', 237), ('\u{ce}', 238), @@ -1097,11 +1109,11 @@ pub mod conversions { ('\u{1e921}', 125251), ]; - static LOWERCASE_TABLE_MULTI: &[[char; 3]] = &[ + static LOWERCASE_TABLE_MULTI: &[[char; 3]; 1] = &[ ['i', '\u{307}', '\u{0}'], ]; - static UPPERCASE_TABLE: &[(char, u32)] = &[ + static UPPERCASE_TABLE: &[(char, u32); 1526] = &[ ('\u{b5}', 924), ('\u{df}', 4194304), ('\u{e0}', 192), ('\u{e1}', 193), ('\u{e2}', 194), ('\u{e3}', 195), ('\u{e4}', 196), ('\u{e5}', 197), ('\u{e6}', 198), ('\u{e7}', 199), ('\u{e8}', 200), ('\u{e9}', 201), ('\u{ea}', 202), ('\u{eb}', 203), ('\u{ec}', 204), @@ -1474,7 +1486,7 @@ pub mod conversions { ('\u{1e941}', 125215), ('\u{1e942}', 125216), ('\u{1e943}', 125217), ]; - static UPPERCASE_TABLE_MULTI: &[[char; 3]] = &[ + static UPPERCASE_TABLE_MULTI: &[[char; 3]; 102] = &[ ['S', 'S', '\u{0}'], ['\u{2bc}', 'N', '\u{0}'], ['J', '\u{30c}', '\u{0}'], ['\u{399}', '\u{308}', '\u{301}'], ['\u{3a5}', '\u{308}', '\u{301}'], ['\u{535}', '\u{552}', '\u{0}'], ['H', '\u{331}', '\u{0}'], ['T', '\u{308}', '\u{0}'], diff --git a/library/coretests/tests/iter/adapters/peekable.rs b/library/coretests/tests/iter/adapters/peekable.rs index 7f4341b8902..f0549e8d6c2 100644 --- a/library/coretests/tests/iter/adapters/peekable.rs +++ b/library/coretests/tests/iter/adapters/peekable.rs @@ -271,3 +271,89 @@ fn test_peekable_non_fused() { assert_eq!(iter.peek(), None); assert_eq!(iter.next_back(), None); } + +#[test] +fn test_peekable_next_if_map_mutation() { + fn collatz((mut num, mut len): (u64, u32)) -> Result<u32, (u64, u32)> { + let jump = num.trailing_zeros(); + num >>= jump; + len += jump; + if num == 1 { Ok(len) } else { Err((3 * num + 1, len + 1)) } + } + + let mut iter = once((3, 0)).peekable(); + assert_eq!(iter.peek(), Some(&(3, 0))); + assert_eq!(iter.next_if_map(collatz), None); + assert_eq!(iter.peek(), Some(&(10, 1))); + assert_eq!(iter.next_if_map(collatz), None); + assert_eq!(iter.peek(), Some(&(16, 3))); + assert_eq!(iter.next_if_map(collatz), Some(7)); + assert_eq!(iter.peek(), None); + assert_eq!(iter.next_if_map(collatz), None); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_peekable_next_if_map_panic() { + use core::cell::Cell; + use std::panic::{AssertUnwindSafe, catch_unwind}; + + struct BitsetOnDrop<'a> { + value: u32, + cell: &'a Cell<u32>, + } + impl<'a> Drop for BitsetOnDrop<'a> { + fn drop(&mut self) { + self.cell.update(|v| v | self.value); + } + } + + let cell = &Cell::new(0); + let mut it = [ + BitsetOnDrop { value: 1, cell }, + BitsetOnDrop { value: 2, cell }, + BitsetOnDrop { value: 4, cell }, + BitsetOnDrop { value: 8, cell }, + ] + .into_iter() + .peekable(); + + // sanity check, .peek() won't consume the value, .next() will transfer ownership. + let item = it.peek().unwrap(); + assert_eq!(item.value, 1); + assert_eq!(cell.get(), 0); + let item = it.next().unwrap(); + assert_eq!(item.value, 1); + assert_eq!(cell.get(), 0); + drop(item); + assert_eq!(cell.get(), 1); + + // next_if_map returning Ok should transfer the value out. + let item = it.next_if_map(Ok).unwrap(); + assert_eq!(item.value, 2); + assert_eq!(cell.get(), 1); + drop(item); + assert_eq!(cell.get(), 3); + + // next_if_map returning Err should not drop anything. + assert_eq!(it.next_if_map::<()>(Err), None); + assert_eq!(cell.get(), 3); + assert_eq!(it.peek().unwrap().value, 4); + assert_eq!(cell.get(), 3); + + // next_if_map panicking should consume and drop the item. + let result = catch_unwind({ + let mut it = AssertUnwindSafe(&mut it); + move || it.next_if_map::<()>(|_| panic!()) + }); + assert!(result.is_err()); + assert_eq!(cell.get(), 7); + assert_eq!(it.next().unwrap().value, 8); + assert_eq!(cell.get(), 15); + assert!(it.peek().is_none()); + + // next_if_map should *not* execute the closure if the iterator is exhausted. + assert!(it.next_if_map::<()>(|_| panic!()).is_none()); + assert!(it.peek().is_none()); + assert_eq!(cell.get(), 15); +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index bf0a3ae7870..b5658a9970f 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -15,10 +15,9 @@ #![feature(cfg_target_has_reliable_f16_f128)] #![feature(char_max_len)] #![feature(clone_to_uninit)] -#![feature(const_deref)] +#![feature(const_convert)] #![feature(const_destruct)] #![feature(const_eval_select)] -#![feature(const_from)] #![feature(const_ops)] #![feature(const_option_ops)] #![feature(const_ref_cell)] @@ -51,6 +50,7 @@ #![feature(fmt_internals)] #![feature(formatting_options)] #![feature(freeze)] +#![feature(funnel_shifts)] #![feature(future_join)] #![feature(generic_assert_internals)] #![feature(hasher_prefixfree_extras)] @@ -83,6 +83,7 @@ #![feature(numfmt)] #![feature(option_reduce)] #![feature(pattern)] +#![feature(peekable_next_if_map)] #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index c7d10ea4d88..63be8a45b5c 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -104,6 +104,19 @@ macro_rules! uint_module { assert_eq_const_safe!($T: C.rotate_left(128), C); } + fn test_funnel_shift() { + // Shifting by 0 should have no effect + assert_eq_const_safe!($T: <$T>::funnel_shl(A, B, 0), A); + assert_eq_const_safe!($T: <$T>::funnel_shr(A, B, 0), B); + + assert_eq_const_safe!($T: <$T>::funnel_shl(_0, _1, 4), 0b1111); + assert_eq_const_safe!($T: <$T>::funnel_shr(_0, _1, 4), _1 >> 4); + assert_eq_const_safe!($T: <$T>::funnel_shl(_1, _0, 4), _1 << 4); + + assert_eq_const_safe!($T: <$T>::funnel_shl(_1, _1, 4), <$T>::rotate_left(_1, 4)); + assert_eq_const_safe!($T: <$T>::funnel_shr(_1, _1, 4), <$T>::rotate_right(_1, 4)); + } + fn test_swap_bytes() { assert_eq_const_safe!($T: A.swap_bytes().swap_bytes(), A); assert_eq_const_safe!($T: B.swap_bytes().swap_bytes(), B); @@ -151,6 +164,29 @@ macro_rules! uint_module { } #[test] + #[should_panic = "attempt to funnel shift left with overflow"] + fn test_funnel_shl_overflow() { + let _ = <$T>::funnel_shl(A, B, $T::BITS); + } + + #[test] + #[should_panic = "attempt to funnel shift right with overflow"] + fn test_funnel_shr_overflow() { + let _ = <$T>::funnel_shr(A, B, $T::BITS); + } + + #[test] + fn test_funnel_shifts_runtime() { + for i in 0..$T::BITS - 1 { + assert_eq!(<$T>::funnel_shl(A, 0, i), A << i); + assert_eq!(<$T>::funnel_shl(A, A, i), A.rotate_left(i)); + + assert_eq!(<$T>::funnel_shr(0, A, i), A >> i); + assert_eq!(<$T>::funnel_shr(A, A, i), A.rotate_right(i)); + } + } + + #[test] fn test_isolate_highest_one() { const BITS: $T = <$T>::MAX; const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1); diff --git a/library/portable-simd/crates/core_simd/src/simd/num/int.rs b/library/portable-simd/crates/core_simd/src/simd/num/int.rs index d25050c3e4b..e7253313f03 100644 --- a/library/portable-simd/crates/core_simd/src/simd/num/int.rs +++ b/library/portable-simd/crates/core_simd/src/simd/num/int.rs @@ -58,6 +58,7 @@ pub trait SimdInt: Copy + Sealed { /// let sat = x.saturating_sub(max); /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0])); /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0])); + /// ``` fn saturating_sub(self, second: Self) -> Self; /// Lanewise absolute value, implemented in Rust. diff --git a/library/portable-simd/crates/core_simd/src/simd/num/uint.rs b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs index 45d978068b6..e3ba8658bd8 100644 --- a/library/portable-simd/crates/core_simd/src/simd/num/uint.rs +++ b/library/portable-simd/crates/core_simd/src/simd/num/uint.rs @@ -55,6 +55,7 @@ pub trait SimdUint: Copy + Sealed { /// let sat = x.saturating_sub(max); /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0])); /// assert_eq!(sat, Simd::splat(0)); + /// ``` fn saturating_sub(self, second: Self) -> Self; /// Lanewise absolute difference. diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index eff2562f031..8b78fe53a39 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -80,6 +80,11 @@ wasi = { version = "0.11.0", features = [ 'rustc-dep-of-std', ], default-features = false } +[target.'cfg(all(target_os = "wasi", target_env = "p2"))'.dependencies] +wasip2 = { version = '0.14.3', features = [ + 'rustc-dep-of-std', +], default-features = false, package = 'wasi' } + [target.'cfg(target_os = "uefi")'.dependencies] r-efi = { version = "5.2.0", features = ['rustc-dep-of-std'] } r-efi-alloc = { version = "2.0.0", features = ['rustc-dep-of-std'] } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 1214490caad..a39565d2159 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -828,7 +828,8 @@ impl OsStr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn new<S: [const] AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr { s.as_ref() } @@ -876,14 +877,16 @@ impl OsStr { } #[inline] - fn from_inner(inner: &Slice) -> &OsStr { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + const fn from_inner(inner: &Slice) -> &OsStr { // SAFETY: OsStr is just a wrapper of Slice, // therefore converting &Slice to &OsStr is safe. unsafe { &*(inner as *const Slice as *const OsStr) } } #[inline] - fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + const fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { // SAFETY: OsStr is just a wrapper of Slice, // therefore converting &mut Slice to &mut OsStr is safe. // Any method that mutates OsStr must be careful not to @@ -1681,7 +1684,8 @@ impl ToOwned for OsStr { } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<OsStr> for OsStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<OsStr> for OsStr { #[inline] fn as_ref(&self) -> &OsStr { self diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 5e51d5e5211..f4431cedd18 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -492,6 +492,85 @@ fn file_test_io_read_write_at() { #[test] #[cfg(unix)] +fn test_read_buf_at() { + use crate::os::unix::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_read_buf_at.txt"); + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut file = check!(oo.open(&filename)); + check!(file.write_all(b"0123456789")); + } + { + let mut file = check!(File::open(&filename)); + let mut buf: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5]; + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + + // Fill entire buffer with potentially short reads + while buf.unfilled().capacity() > 0 { + let len = buf.len(); + check!(file.read_buf_at(buf.unfilled(), 2 + len as u64)); + assert!(!buf.filled().is_empty()); + assert!(b"23456".starts_with(buf.filled())); + assert_eq!(check!(file.stream_position()), 0); + } + assert_eq!(buf.filled(), b"23456"); + + // Already full + check!(file.read_buf_at(buf.unfilled(), 3)); + check!(file.read_buf_at(buf.unfilled(), 10)); + assert_eq!(buf.filled(), b"23456"); + assert_eq!(check!(file.stream_position()), 0); + + // Read past eof is noop + check!(file.read_buf_at(buf.clear().unfilled(), 10)); + assert_eq!(buf.filled(), b""); + check!(file.read_buf_at(buf.clear().unfilled(), 11)); + assert_eq!(buf.filled(), b""); + assert_eq!(check!(file.stream_position()), 0); + } + check!(fs::remove_file(&filename)); +} + +#[test] +#[cfg(unix)] +fn test_read_buf_exact_at() { + use crate::os::unix::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_read_buf_exact_at.txt"); + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut file = check!(oo.open(&filename)); + check!(file.write_all(b"0123456789")); + } + { + let mut file = check!(File::open(&filename)); + let mut buf: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5]; + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + + // Exact read + check!(file.read_buf_exact_at(buf.unfilled(), 2)); + assert_eq!(buf.filled(), b"23456"); + assert_eq!(check!(file.stream_position()), 0); + + // Already full + check!(file.read_buf_exact_at(buf.unfilled(), 3)); + check!(file.read_buf_exact_at(buf.unfilled(), 10)); + assert_eq!(buf.filled(), b"23456"); + assert_eq!(check!(file.stream_position()), 0); + + // Non-empty exact read past eof fails + let err = file.read_buf_exact_at(buf.clear().unfilled(), 6).unwrap_err(); + assert_eq!(err.kind(), ErrorKind::UnexpectedEof); + assert_eq!(check!(file.stream_position()), 0); + } + check!(fs::remove_file(&filename)); +} + +#[test] +#[cfg(unix)] fn set_get_unix_permissions() { use crate::os::unix::fs::PermissionsExt; @@ -567,6 +646,39 @@ fn file_test_io_seek_read_write() { } #[test] +#[cfg(windows)] +fn test_seek_read_buf() { + use crate::os::windows::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_seek_read_buf.txt"); + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut file = check!(oo.open(&filename)); + check!(file.write_all(b"0123456789")); + } + { + let mut file = check!(File::open(&filename)); + let mut buf: [MaybeUninit<u8>; 1] = [MaybeUninit::uninit()]; + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + + // Seek read + check!(file.seek_read_buf(buf.unfilled(), 8)); + assert_eq!(buf.filled(), b"8"); + assert_eq!(check!(file.stream_position()), 9); + + // Empty seek read + check!(file.seek_read_buf(buf.unfilled(), 0)); + assert_eq!(buf.filled(), b"8"); + + // Seek read past eof + check!(file.seek_read_buf(buf.clear().unfilled(), 10)); + assert_eq!(buf.filled(), b""); + } + check!(fs::remove_file(&filename)); +} + +#[test] fn file_test_read_buf() { let tmpdir = tmpdir(); let filename = &tmpdir.join("test"); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 7bdc6ff7882..99b380c4793 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -294,6 +294,7 @@ #![feature(f128)] #![feature(ffi_const)] #![feature(formatting_options)] +#![feature(funnel_shifts)] #![feature(hash_map_internals)] #![feature(hash_map_macro)] #![feature(if_let_guard)] @@ -332,6 +333,7 @@ #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(const_cmp)] +#![feature(const_convert)] #![feature(const_ops)] #![feature(const_option_ops)] #![feature(const_try)] diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index b776df3dde1..1d1a138b302 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -11,6 +11,7 @@ use super::platform::fs::MetadataExt as _; // Used for `File::read` on intra-doc links use crate::ffi::OsStr; use crate::fs::{self, OpenOptions, Permissions}; +use crate::io::BorrowedCursor; use crate::os::unix::io::{AsFd, AsRawFd}; use crate::path::Path; use crate::sealed::Sealed; @@ -130,6 +131,91 @@ pub trait FileExt { if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } } + /// Reads some bytes starting from a given offset into the buffer. + /// + /// This equivalent to the [`read_at`](FileExt::read_at) method, except that it is passed a + /// [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The new + /// data will be appended to any existing contents of `buf`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(core_io_borrowed_buf)] + /// #![feature(read_buf_at)] + /// + /// use std::io; + /// use std::io::BorrowedBuf; + /// use std::fs::File; + /// use std::mem::MaybeUninit; + /// use std::os::unix::prelude::*; + /// + /// fn main() -> io::Result<()> { + /// let mut file = File::open("pi.txt")?; + /// + /// // Read some bytes starting from offset 2 + /// let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10]; + /// let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + /// file.read_buf_at(buf.unfilled(), 2)?; + /// + /// assert!(buf.filled().starts_with(b"1")); + /// + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "read_buf_at", issue = "140771")] + fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + io::default_read_buf(|b| self.read_at(b, offset), buf) + } + + /// Reads the exact number of bytes required to fill the buffer from a given offset. + /// + /// This is equivalent to the [`read_exact_at`](FileExt::read_exact_at) method, except that it + /// is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized + /// buffers. The new data will be appended to any existing contents of `buf`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(core_io_borrowed_buf)] + /// #![feature(read_buf_at)] + /// + /// use std::io; + /// use std::io::BorrowedBuf; + /// use std::fs::File; + /// use std::mem::MaybeUninit; + /// use std::os::unix::prelude::*; + /// + /// fn main() -> io::Result<()> { + /// let mut file = File::open("pi.txt")?; + /// + /// // Read exactly 10 bytes starting from offset 2 + /// let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10]; + /// let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + /// file.read_buf_exact_at(buf.unfilled(), 2)?; + /// + /// assert_eq!(buf.filled(), b"1415926535"); + /// + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "read_buf_at", issue = "140771")] + fn read_buf_exact_at(&self, mut buf: BorrowedCursor<'_>, mut offset: u64) -> io::Result<()> { + while buf.capacity() > 0 { + let prev_written = buf.written(); + match self.read_buf_at(buf.reborrow(), offset) { + Ok(()) => {} + Err(e) if e.is_interrupted() => {} + Err(e) => return Err(e), + } + let n = buf.written() - prev_written; + offset += n as u64; + if n == 0 { + return Err(io::Error::READ_EXACT_EOF); + } + } + Ok(()) + } + /// Writes a number of bytes starting from a given offset. /// /// Returns the number of bytes written. @@ -264,6 +350,9 @@ impl FileExt for fs::File { fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { self.as_inner().read_at(buf, offset) } + fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + self.as_inner().read_buf_at(buf, offset) + } fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> { self.as_inner().read_vectored_at(bufs, offset) } diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index ddb8dbd8fee..b445f368aeb 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -5,6 +5,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::fs::{self, Metadata, OpenOptions}; +use crate::io::BorrowedCursor; use crate::path::Path; use crate::sealed::Sealed; use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; @@ -49,6 +50,44 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; + /// Seeks to a given position and reads some bytes into the buffer. + /// + /// This is equivalent to the [`seek_read`](FileExt::seek_read) method, except that it is passed + /// a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The + /// new data will be appended to any existing contents of `buf`. + /// + /// Reading beyond the end of the file will always succeed without reading any bytes. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(core_io_borrowed_buf)] + /// #![feature(read_buf_at)] + /// + /// use std::io; + /// use std::io::BorrowedBuf; + /// use std::fs::File; + /// use std::mem::MaybeUninit; + /// use std::os::windows::prelude::*; + /// + /// fn main() -> io::Result<()> { + /// let mut file = File::open("pi.txt")?; + /// + /// // Read some bytes starting from offset 2 + /// let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10]; + /// let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + /// file.seek_read_buf(buf.unfilled(), 2)?; + /// + /// assert!(buf.filled().starts_with(b"1")); + /// + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "read_buf_at", issue = "140771")] + fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + io::default_read_buf(|b| self.seek_read(b, offset), buf) + } + /// Seeks to a given position and writes a number of bytes. /// /// Returns the number of bytes written. @@ -89,6 +128,10 @@ impl FileExt for fs::File { self.as_inner().read_at(buf, offset) } + fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + self.as_inner().read_buf_at(buf, offset) + } + fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> { self.as_inner().write_at(buf, offset) } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 470d300d2d9..531a1aa4215 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1575,8 +1575,6 @@ impl PathBuf { /// # Examples /// /// ``` - /// #![feature(path_add_extension)] - /// /// use std::path::{Path, PathBuf}; /// /// let mut p = PathBuf::from("/feel/the"); @@ -1596,7 +1594,7 @@ impl PathBuf { /// p.add_extension(""); /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path()); /// ``` - #[unstable(feature = "path_add_extension", issue = "127292")] + #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")] pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool { self._add_extension(extension.as_ref()) } @@ -2264,11 +2262,13 @@ impl Path { /// assert_eq!(from_string, from_path); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn new<S: [const] AsRef<OsStr> + ?Sized>(s: &S) -> &Path { unsafe { &*(s.as_ref() as *const OsStr as *const Path) } } - fn from_inner_mut(inner: &mut OsStr) -> &mut Path { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + const fn from_inner_mut(inner: &mut OsStr) -> &mut Path { // SAFETY: Path is just a wrapper around OsStr, // therefore converting &mut OsStr to &mut Path is safe. unsafe { &mut *(inner as *mut OsStr as *mut Path) } @@ -2878,8 +2878,6 @@ impl Path { /// # Examples /// /// ``` - /// #![feature(path_add_extension)] - /// /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("foo.rs"); @@ -2890,7 +2888,7 @@ impl Path { /// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz")); /// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt")); /// ``` - #[unstable(feature = "path_add_extension", issue = "127292")] + #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")] pub fn with_added_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf { let mut new_path = self.to_path_buf(); new_path.add_extension(extension); @@ -3337,7 +3335,8 @@ unsafe impl CloneToUninit for Path { } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<OsStr> for Path { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<OsStr> for Path { #[inline] fn as_ref(&self) -> &OsStr { &self.inner @@ -3507,7 +3506,8 @@ impl Ord for Path { } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<Path> for Path { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<Path> for Path { #[inline] fn as_ref(&self) -> &Path { self @@ -3515,7 +3515,8 @@ impl AsRef<Path> for Path { } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<Path> for OsStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<Path> for OsStr { #[inline] fn as_ref(&self) -> &Path { Path::new(self) diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index c9627322276..e11e8e5430f 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -32,9 +32,13 @@ cfg_select! { mod uefi; pub use uefi::*; } - target_os = "wasi" => { - mod wasi; - pub use wasi::*; + all(target_os = "wasi", target_env = "p1") => { + mod wasip1; + pub use wasip1::*; + } + all(target_os = "wasi", target_env = "p2") => { + mod wasip2; + pub use wasip2::*; } target_os = "xous" => { mod xous; diff --git a/library/std/src/sys/args/wasi.rs b/library/std/src/sys/args/wasip1.rs index 72063a87dc9..72063a87dc9 100644 --- a/library/std/src/sys/args/wasi.rs +++ b/library/std/src/sys/args/wasip1.rs diff --git a/library/std/src/sys/args/wasip2.rs b/library/std/src/sys/args/wasip2.rs new file mode 100644 index 00000000000..a57e4b97786 --- /dev/null +++ b/library/std/src/sys/args/wasip2.rs @@ -0,0 +1,6 @@ +pub use super::common::Args; + +/// Returns the command line arguments +pub fn args() -> Args { + Args::new(wasip2::cli::environment::get_arguments().into_iter().map(|arg| arg.into()).collect()) +} diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index a12f692e754..2b2dfe48e89 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -18,6 +18,21 @@ use libc::off_t as off64_t; ))] use libc::off64_t; +cfg_select! { + any( + all(target_os = "linux", not(target_env = "musl")), + target_os = "android", + target_os = "hurd", + ) => { + // Prefer explicit pread64 for 64-bit offset independently of libc + // #[cfg(gnu_file_offset_bits64)]. + use libc::pread64; + } + _ => { + use libc::pread as pread64; + } +} + use crate::cmp; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; @@ -146,42 +161,47 @@ impl FileDesc { (&mut me).read_to_end(buf) } - #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))] pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - #[cfg(not(any( - all(target_os = "linux", not(target_env = "musl")), - target_os = "android", - target_os = "hurd" - )))] - use libc::pread as pread64; - #[cfg(any( - all(target_os = "linux", not(target_env = "musl")), - target_os = "android", - target_os = "hurd" - ))] - use libc::pread64; - - unsafe { - cvt(pread64( + cvt(unsafe { + pread64( self.as_raw_fd(), buf.as_mut_ptr() as *mut libc::c_void, cmp::min(buf.len(), READ_LIMIT), - offset as off64_t, - )) - .map(|n| n as usize) - } + offset as off64_t, // EINVAL if offset + count overflows + ) + }) + .map(|n| n as usize) } pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { + // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes let ret = cvt(unsafe { libc::read( self.as_raw_fd(), - cursor.as_mut().as_mut_ptr() as *mut libc::c_void, + cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(), + cmp::min(cursor.capacity(), READ_LIMIT), + ) + })?; + + // SAFETY: `ret` bytes were written to the initialized portion of the buffer + unsafe { + cursor.advance_unchecked(ret as usize); + } + Ok(()) + } + + pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes + let ret = cvt(unsafe { + pread64( + self.as_raw_fd(), + cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(), cmp::min(cursor.capacity(), READ_LIMIT), + offset as off64_t, // EINVAL if offset + count overflows ) })?; - // Safety: `ret` bytes were written to the initialized portion of the buffer + // SAFETY: `ret` bytes were written to the initialized portion of the buffer unsafe { cursor.advance_unchecked(ret as usize); } @@ -369,7 +389,6 @@ impl FileDesc { ))) } - #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))] pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { #[cfg(not(any( all(target_os = "linux", not(target_env = "musl")), diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index a89c3bbacfb..3b525406223 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1463,6 +1463,10 @@ impl File { self.0.read_buf(cursor) } + pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + self.0.read_buf_at(cursor, offset) + } + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { self.0.read_vectored_at(bufs, offset) } diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index bac278f7c8f..ccfe410627f 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -605,6 +605,10 @@ impl File { self.handle.read_buf(cursor) } + pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + self.handle.read_buf_at(cursor, offset) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.handle.write(buf) } diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index 9376f5249f1..513121c6d30 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -49,9 +49,9 @@ cfg_select! { mod wasip2; pub use self::wasip2::*; } - target_os = "wasi" => { - mod wasi; - pub use self::wasi::*; + all(target_os = "wasi", target_env = "p1") => { + mod wasip1; + pub use self::wasip1::*; } target_family = "wasm" => { mod wasm; diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasip1/helpers.rs index 404747f0dc7..404747f0dc7 100644 --- a/library/std/src/sys/pal/wasi/helpers.rs +++ b/library/std/src/sys/pal/wasip1/helpers.rs diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasip1/mod.rs index 61dd1c3f98b..61dd1c3f98b 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasip1/mod.rs diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasip1/os.rs index 151ba254ec4..151ba254ec4 100644 --- a/library/std/src/sys/pal/wasi/os.rs +++ b/library/std/src/sys/pal/wasip1/os.rs diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasip1/thread.rs index e062b49bd7a..e062b49bd7a 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasip1/thread.rs diff --git a/library/std/src/sys/pal/wasi/time.rs b/library/std/src/sys/pal/wasip1/time.rs index 892661b312b..892661b312b 100644 --- a/library/std/src/sys/pal/wasi/time.rs +++ b/library/std/src/sys/pal/wasip1/time.rs diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 47fe3221c90..5f3fb6d6ddf 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -10,13 +10,11 @@ #[path = "../wasm/atomics/futex.rs"] pub mod futex; -#[path = "../wasi/os.rs"] +#[path = "../wasip1/os.rs"] pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../wasi/thread.rs"] pub mod thread; -#[path = "../wasi/time.rs"] pub mod time; #[path = "../unsupported/common.rs"] @@ -26,7 +24,7 @@ mod common; pub use common::*; -#[path = "../wasi/helpers.rs"] +#[path = "../wasip1/helpers.rs"] mod helpers; // The following exports are listed individually to work around Rust's glob diff --git a/library/std/src/sys/pal/wasip2/thread.rs b/library/std/src/sys/pal/wasip2/thread.rs new file mode 100644 index 00000000000..ad52918f15a --- /dev/null +++ b/library/std/src/sys/pal/wasip2/thread.rs @@ -0,0 +1,73 @@ +use crate::ffi::CStr; +use crate::io; +use crate::num::NonZero; +use crate::time::{Duration, Instant}; + +pub struct Thread(!); + +pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; + +impl Thread { + pub unsafe fn new( + _stack: usize, + _name: Option<&str>, + _p: Box<dyn FnOnce()>, + ) -> io::Result<Thread> { + // Note that unlike WASIp1 even if the wasm `atomics` feature is enabled + // there is no support for threads, not even experimentally, not even in + // wasi-libc. Thus this is unconditionally unsupported. + crate::sys::unsupported() + } + + pub fn yield_now() { + // no API for this in WASIp2, but there's also no threads, so that's + // sort of expected. + } + + pub fn set_name(_name: &CStr) { + // nope + } + + pub fn sleep(dur: Duration) { + // Sleep in increments of `u64::MAX` nanoseconds until the `dur` is + // entirely drained. + let mut remaining = dur.as_nanos(); + while remaining > 0 { + let amt = u64::try_from(remaining).unwrap_or(u64::MAX); + wasip2::clocks::monotonic_clock::subscribe_duration(amt).block(); + remaining -= u128::from(amt); + } + } + + pub fn sleep_until(deadline: Instant) { + match u64::try_from(deadline.into_inner().as_duration().as_nanos()) { + // If the point in time we're sleeping to fits within a 64-bit + // number of nanoseconds then directly use `subscribe_instant`. + Ok(deadline) => { + wasip2::clocks::monotonic_clock::subscribe_instant(deadline).block(); + } + // ... otherwise we're sleeping for 500+ years relative to the + // "start" of what the system is using as a clock so speed/accuracy + // is not so much of a concern. Use `sleep` instead. + Err(_) => { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + } + } + + pub fn join(self) { + self.0 + } +} + +pub(crate) fn current_os_id() -> Option<u64> { + None +} + +pub fn available_parallelism() -> io::Result<NonZero<usize>> { + crate::sys::unsupported() +} diff --git a/library/std/src/sys/pal/wasip2/time.rs b/library/std/src/sys/pal/wasip2/time.rs new file mode 100644 index 00000000000..f1f6839774b --- /dev/null +++ b/library/std/src/sys/pal/wasip2/time.rs @@ -0,0 +1,69 @@ +use crate::time::Duration; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(Duration); + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(Duration); + +pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); + +impl Instant { + pub fn now() -> Instant { + Instant(Duration::from_nanos(wasip2::clocks::monotonic_clock::now())) + } + + pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> { + self.0.checked_sub(other.0) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> { + Some(Instant(self.0.checked_add(*other)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> { + Some(Instant(self.0.checked_sub(*other)?)) + } + + pub(super) fn as_duration(&self) -> &Duration { + &self.0 + } +} + +impl SystemTime { + pub fn now() -> SystemTime { + let now = wasip2::clocks::wall_clock::now(); + SystemTime(Duration::new(now.seconds, now.nanoseconds)) + } + + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { + SystemTime(Duration::from_nanos(ts)) + } + + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> { + // FIXME: const TryInto + let ns = self.0.as_nanos(); + if ns <= u64::MAX as u128 { Some(ns as u64) } else { None } + } + + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + // FIXME: ok_or_else with const closures + match self.0.checked_sub(other.0) { + Some(duration) => Ok(duration), + None => Err(other.0 - self.0), + } + } + + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + Some(SystemTime(self.0.checked_add(*other)?)) + } + + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + Some(SystemTime(self.0.checked_sub(*other)?)) + } +} diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 82a880faf5f..76c8aa939d3 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -136,6 +136,19 @@ impl Handle { } } + pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes + let read = unsafe { + self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), Some(offset)) + }?; + + // SAFETY: `read` bytes were written to the initialized portion of the buffer + unsafe { + cursor.advance_unchecked(read); + } + Ok(()) + } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { let mut me = self; diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index a7fbae86099..1e0eec07b50 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -86,9 +86,13 @@ cfg_select! { mod vxworks; pub use vxworks::fill_bytes; } - target_os = "wasi" => { - mod wasi; - pub use wasi::fill_bytes; + all(target_os = "wasi", target_env = "p1") => { + mod wasip1; + pub use wasip1::fill_bytes; + } + all(target_os = "wasi", target_env = "p2") => { + mod wasip2; + pub use wasip2::{fill_bytes, hashmap_random_keys}; } target_os = "zkvm" => { mod zkvm; @@ -110,6 +114,7 @@ cfg_select! { target_os = "linux", target_os = "android", all(target_family = "wasm", target_os = "unknown"), + all(target_os = "wasi", target_env = "p2"), target_os = "xous", )))] pub fn hashmap_random_keys() -> (u64, u64) { diff --git a/library/std/src/sys/random/wasi.rs b/library/std/src/sys/random/wasip1.rs index d41da3751fc..d41da3751fc 100644 --- a/library/std/src/sys/random/wasi.rs +++ b/library/std/src/sys/random/wasip1.rs diff --git a/library/std/src/sys/random/wasip2.rs b/library/std/src/sys/random/wasip2.rs new file mode 100644 index 00000000000..a67c8a6428d --- /dev/null +++ b/library/std/src/sys/random/wasip2.rs @@ -0,0 +1,9 @@ +pub fn fill_bytes(bytes: &mut [u8]) { + bytes.copy_from_slice(&wasip2::random::random::get_random_bytes( + u64::try_from(bytes.len()).unwrap(), + )); +} + +pub fn hashmap_random_keys() -> (u64, u64) { + wasip2::random::insecure_seed::insecure_seed() +} diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index e1576a0d423..3577f0d9c7b 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -1,4 +1,4 @@ -#![feature(clone_to_uninit, path_add_extension, maybe_uninit_slice, normalize_lexically)] +#![feature(clone_to_uninit, maybe_uninit_slice, normalize_lexically)] use std::clone::CloneToUninit; use std::ffi::OsStr; diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 1535d087033..fe832652d25 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -269,14 +269,14 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "filetime" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" dependencies = [ "cfg-if", "libc", "libredox", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -322,11 +322,11 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -364,12 +364,12 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "junction" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72bbdfd737a243da3dfc1f99ee8d6e166480f17ab4ac84d7c34aacd73fc7bd16" +checksum = "c52f6e1bf39a7894f618c9d378904a11dbd7e10fe3ec20d1173600e79b1408d8" dependencies = [ "scopeguard", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -434,6 +434,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] +name = "normpath" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] name = "ntapi" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -497,12 +506,13 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opener" -version = "0.5.2" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" +checksum = "771b9704f8cd8b424ec747a320b30b47517a6966ba2c7da90047c16f4a962223" dependencies = [ "bstr", - "winapi", + "normpath", + "windows-sys 0.59.0", ] [[package]] @@ -757,15 +767,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.19.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600" +checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" dependencies = [ "fastrand", "getrandom", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -929,11 +939,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1045,20 +1055,20 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.2", ] [[package]] @@ -1067,14 +1077,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -1084,48 +1110,96 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] name = "wit-bindgen-rt" version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index c7175584465..9a76a7dda2a 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -42,7 +42,7 @@ home = "0.5" ignore = "0.4" libc = "0.2" object = { version = "0.36.3", default-features = false, features = ["archive", "coff", "read_core", "std", "unaligned"] } -opener = "0.5" +opener = "0.8" semver = "1.0" serde = "1.0" # Directly use serde_derive rather than through the derive feature of serde to allow building both @@ -67,7 +67,7 @@ tracing-subscriber = { version = "0.3", optional = true, features = ["env-filter tempfile = { version = "3.15.0", optional = true } [target.'cfg(windows)'.dependencies.junction] -version = "1.0.0" +version = "1.3.0" [target.'cfg(windows)'.dependencies.windows] version = "0.61" diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index a604e7c0585..49d12b64da5 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -389,7 +389,7 @@ impl Step for Rustc { /// Represents a compiler that can check something. /// -/// If the compiler was created for `Mode::ToolRustc` or `Mode::Codegen`, it will also contain +/// If the compiler was created for `Mode::ToolRustcPrivate` or `Mode::Codegen`, it will also contain /// .rmeta artifacts from rustc that was already checked using `build_compiler`. /// /// All steps that use this struct in a "general way" (i.e. they don't know exactly what kind of @@ -469,7 +469,7 @@ pub fn prepare_compiler_for_check( build_compiler } } - Mode::ToolRustc | Mode::Codegen => { + Mode::ToolRustcPrivate | Mode::Codegen => { // Check Rustc to produce the required rmeta artifacts for rustc_private, and then // return the build compiler that was used to check rustc. // We do not need to check examples/tests/etc. of Rustc for rustc_private, so we pass @@ -767,19 +767,22 @@ fn run_tool_check_step( tool_check_step!(Rustdoc { path: "src/tools/rustdoc", alt_path: "src/librustdoc", - mode: |_builder| Mode::ToolRustc + mode: |_builder| Mode::ToolRustcPrivate }); // Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead // of a submodule. Since the SourceType only drives the deny-warnings // behavior, treat it as in-tree so that any new warnings in clippy will be // rejected. -tool_check_step!(Clippy { path: "src/tools/clippy", mode: |_builder| Mode::ToolRustc }); -tool_check_step!(Miri { path: "src/tools/miri", mode: |_builder| Mode::ToolRustc }); -tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: |_builder| Mode::ToolRustc }); -tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: |_builder| Mode::ToolRustc }); +tool_check_step!(Clippy { path: "src/tools/clippy", mode: |_builder| Mode::ToolRustcPrivate }); +tool_check_step!(Miri { path: "src/tools/miri", mode: |_builder| Mode::ToolRustcPrivate }); +tool_check_step!(CargoMiri { + path: "src/tools/miri/cargo-miri", + mode: |_builder| Mode::ToolRustcPrivate +}); +tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: |_builder| Mode::ToolRustcPrivate }); tool_check_step!(RustAnalyzer { path: "src/tools/rust-analyzer", - mode: |_builder| Mode::ToolRustc, + mode: |_builder| Mode::ToolRustcPrivate, allow_features: tool::RustAnalyzer::ALLOW_FEATURES, enable_features: ["in-rust-tree"], }); diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 05f8b240291..2083c675e1f 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -366,8 +366,13 @@ impl Step for CodegenGcc { ); self.build_compiler.configure_cargo(&mut cargo); - let _guard = - builder.msg(Kind::Clippy, "rustc_codegen_gcc", Mode::ToolRustc, build_compiler, target); + let _guard = builder.msg( + Kind::Clippy, + "rustc_codegen_gcc", + Mode::ToolRustcPrivate, + build_compiler, + target, + ); let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, Mode::Codegen, target)) .with_prefix("rustc_codegen_gcc-check"); @@ -478,8 +483,8 @@ lint_any!( Bootstrap, "src/bootstrap", "bootstrap", Mode::ToolTarget; BuildHelper, "src/build_helper", "build_helper", Mode::ToolTarget; BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::ToolTarget; - CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", Mode::ToolRustc; - Clippy, "src/tools/clippy", "clippy", Mode::ToolRustc; + CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", Mode::ToolRustcPrivate; + Clippy, "src/tools/clippy", "clippy", Mode::ToolRustcPrivate; CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata", Mode::ToolTarget; Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolTarget; CoverageDump, "src/tools/coverage-dump", "coverage-dump", Mode::ToolTarget; @@ -487,14 +492,14 @@ lint_any!( Jsondoclint, "src/tools/jsondoclint", "jsondoclint", Mode::ToolTarget; LintDocs, "src/tools/lint-docs", "lint-docs", Mode::ToolTarget; LlvmBitcodeLinker, "src/tools/llvm-bitcode-linker", "llvm-bitcode-linker", Mode::ToolTarget; - Miri, "src/tools/miri", "miri", Mode::ToolRustc; + Miri, "src/tools/miri", "miri", Mode::ToolRustcPrivate; MiroptTestTools, "src/tools/miropt-test-tools", "miropt-test-tools", Mode::ToolTarget; OptDist, "src/tools/opt-dist", "opt-dist", Mode::ToolTarget; RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::ToolTarget; RemoteTestServer, "src/tools/remote-test-server", "remote-test-server", Mode::ToolTarget; - RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer", Mode::ToolRustc; - Rustdoc, "src/librustdoc", "clippy", Mode::ToolRustc; - Rustfmt, "src/tools/rustfmt", "rustfmt", Mode::ToolRustc; + RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer", Mode::ToolRustcPrivate; + Rustdoc, "src/librustdoc", "clippy", Mode::ToolRustcPrivate; + Rustfmt, "src/tools/rustfmt", "rustfmt", Mode::ToolRustcPrivate; RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::ToolTarget; Tidy, "src/tools/tidy", "tidy", Mode::ToolTarget; TestFloatParse, "src/tools/test-float-parse", "test-float-parse", Mode::ToolStd; diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index f113dd7683d..820dda5a652 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -823,6 +823,18 @@ pub struct RustcDev { target: TargetSelection, } +impl RustcDev { + pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self { + Self { + // We currently always ship a stage 2 rustc-dev component, so we build it with the + // stage 1 compiler. This might change in the future. + // The precise stage used here is important, so we hard-code it. + build_compiler: builder.compiler(1, builder.config.host_target), + target, + } + } +} + impl Step for RustcDev { type Output = Option<GeneratedTarball>; const DEFAULT: bool = true; @@ -833,13 +845,7 @@ impl Step for RustcDev { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(RustcDev { - // We currently always ship a stage 2 rustc-dev component, so we build it with the - // stage 1 compiler. This might change in the future. - // The precise stage used here is important, so we hard-code it. - build_compiler: run.builder.compiler(1, run.builder.config.host_target), - target: run.target, - }); + run.builder.ensure(RustcDev::new(run.builder, run.target)); } fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 0789eefa894..eb198a0051a 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -995,7 +995,7 @@ macro_rules! tool_doc { // Build rustc docs so that we generate relative links. run.builder.ensure(Rustc::from_build_compiler(run.builder, compilers.build_compiler(), target)); - (compilers.build_compiler(), Mode::ToolRustc) + (compilers.build_compiler(), Mode::ToolRustcPrivate) } else { // bootstrap/host tools have to be documented with the stage 0 compiler (prepare_doc_compiler(run.builder, run.builder.host_target, 1), Mode::ToolBootstrap) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index d47c1495838..83ed7430c39 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -205,6 +205,7 @@ pub(crate) fn is_ci_llvm_available_for_target( // tier 1 ("aarch64-unknown-linux-gnu", false), ("aarch64-apple-darwin", false), + ("aarch64-pc-windows-msvc", false), ("i686-pc-windows-gnu", false), ("i686-pc-windows-msvc", false), ("i686-unknown-linux-gnu", false), @@ -213,7 +214,6 @@ pub(crate) fn is_ci_llvm_available_for_target( ("x86_64-pc-windows-gnu", true), ("x86_64-pc-windows-msvc", true), // tier 2 with host tools - ("aarch64-pc-windows-msvc", false), ("aarch64-unknown-linux-musl", false), ("arm-unknown-linux-gnueabi", false), ("arm-unknown-linux-gnueabihf", false), diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index d9de6b7ef96..9f7248b80f7 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -161,7 +161,7 @@ impl Step for Miri { let mut miri = tool::prepare_tool_cargo( builder, compilers.build_compiler(), - Mode::ToolRustc, + Mode::ToolRustcPrivate, host, Kind::Run, "src/tools/miri", @@ -487,7 +487,7 @@ impl Step for Rustfmt { let mut rustfmt = tool::prepare_tool_cargo( builder, rustfmt_build.build_compiler, - Mode::ToolRustc, + Mode::ToolRustcPrivate, host, Kind::Run, "src/tools/rustfmt", diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index ee2cbe9385e..cb81d738666 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -455,7 +455,7 @@ impl Step for RustAnalyzer { let mut cargo = tool::prepare_tool_cargo( builder, self.compilers.build_compiler(), - Mode::ToolRustc, + Mode::ToolRustcPrivate, host, Kind::Test, crate_path, @@ -518,7 +518,7 @@ impl Step for Rustfmt { let mut cargo = tool::prepare_tool_cargo( builder, build_compiler, - Mode::ToolRustc, + Mode::ToolRustcPrivate, target, Kind::Test, "src/tools/rustfmt", @@ -571,7 +571,8 @@ impl Miri { cargo.env("MIRI_SYSROOT", &miri_sysroot); let mut cargo = BootstrapCommand::from(cargo); - let _guard = builder.msg(Kind::Build, "miri sysroot", Mode::ToolRustc, compiler, target); + let _guard = + builder.msg(Kind::Build, "miri sysroot", Mode::ToolRustcPrivate, compiler, target); cargo.run(builder); // # Determine where Miri put its sysroot. @@ -648,7 +649,7 @@ impl Step for Miri { let mut cargo = tool::prepare_tool_cargo( builder, miri.build_compiler, - Mode::ToolRustc, + Mode::ToolRustcPrivate, host, Kind::Test, "src/tools/miri", @@ -861,7 +862,7 @@ impl Step for Clippy { let mut cargo = tool::prepare_tool_cargo( builder, build_compiler, - Mode::ToolRustc, + Mode::ToolRustcPrivate, target, Kind::Test, "src/tools/clippy", @@ -872,7 +873,7 @@ impl Step for Clippy { cargo.env("RUSTC_TEST_SUITE", builder.rustc(build_compiler)); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(build_compiler)); let host_libs = - builder.stage_out(build_compiler, Mode::ToolRustc).join(builder.cargo_dir()); + builder.stage_out(build_compiler, Mode::ToolRustcPrivate).join(builder.cargo_dir()); cargo.env("HOST_LIBS", host_libs); // Build the standard library that the tests can use. @@ -2411,7 +2412,7 @@ impl BookTest { let libs = if !self.dependencies.is_empty() { let mut lib_paths = vec![]; for dep in self.dependencies { - let mode = Mode::ToolRustc; + let mode = Mode::ToolRustcPrivate; let target = builder.config.host_target; let cargo = tool::prepare_tool_cargo( builder, @@ -2996,7 +2997,7 @@ impl Step for CrateRustdoc { let mut cargo = tool::prepare_tool_cargo( builder, compiler, - Mode::ToolRustc, + Mode::ToolRustcPrivate, target, builder.kind, "src/tools/rustdoc", @@ -3182,6 +3183,7 @@ impl Step for Distcheck { /// check steps from those sources. /// - Check that selected dist components (`rust-src` only at the moment) at least have expected /// directory shape and crate manifests that cargo can generate a lockfile from. + /// - Check that we can run `cargo metadata` on the workspace in the `rustc-dev` component /// /// FIXME(#136822): dist components are under-tested. fn run(self, builder: &Builder<'_>) { @@ -3189,61 +3191,91 @@ impl Step for Distcheck { // local source code, built artifacts or configuration by accident let root_dir = std::env::temp_dir().join("distcheck"); - // Check that we can build some basic things from the plain source tarball - builder.info("Distcheck plain source tarball"); - let plain_src_tarball = builder.ensure(dist::PlainSourceTarball); - let plain_src_dir = root_dir.join("distcheck-plain-src"); - builder.clear_dir(&plain_src_dir); - - let configure_args: Vec<String> = std::env::var("DISTCHECK_CONFIGURE_ARGS") - .map(|args| args.split(" ").map(|s| s.to_string()).collect::<Vec<String>>()) - .unwrap_or_default(); - - command("tar") - .arg("-xf") - .arg(plain_src_tarball.tarball()) - .arg("--strip-components=1") - .current_dir(&plain_src_dir) - .run(builder); - command("./configure") - .arg("--set") - .arg("rust.omit-git-hash=false") - .args(&configure_args) - .arg("--enable-vendor") - .current_dir(&plain_src_dir) - .run(builder); - command(helpers::make(&builder.config.host_target.triple)) - .arg("check") - // Do not run the build as if we were in CI, otherwise git would be assumed to be - // present, but we build from a tarball here - .env("GITHUB_ACTIONS", "0") - .current_dir(&plain_src_dir) - .run(builder); - - // Now make sure that rust-src has all of libstd's dependencies - builder.info("Distcheck rust-src"); - let src_tarball = builder.ensure(dist::Src); - let src_dir = root_dir.join("distcheck-src"); - builder.clear_dir(&src_dir); - - command("tar") - .arg("-xf") - .arg(src_tarball.tarball()) - .arg("--strip-components=1") - .current_dir(&src_dir) - .run(builder); - - let toml = src_dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml"); - command(&builder.initial_cargo) - // Will read the libstd Cargo.toml - // which uses the unstable `public-dependency` feature. - .env("RUSTC_BOOTSTRAP", "1") - .arg("generate-lockfile") - .arg("--manifest-path") - .arg(&toml) - .current_dir(&src_dir) - .run(builder); - } + distcheck_plain_source_tarball(builder, &root_dir.join("distcheck-rustc-src")); + distcheck_rust_src(builder, &root_dir.join("distcheck-rust-src")); + distcheck_rustc_dev(builder, &root_dir.join("distcheck-rustc-dev")); + } +} + +/// Check that we can build some basic things from the plain source tarball +fn distcheck_plain_source_tarball(builder: &Builder<'_>, plain_src_dir: &Path) { + builder.info("Distcheck plain source tarball"); + let plain_src_tarball = builder.ensure(dist::PlainSourceTarball); + builder.clear_dir(plain_src_dir); + + let configure_args: Vec<String> = std::env::var("DISTCHECK_CONFIGURE_ARGS") + .map(|args| args.split(" ").map(|s| s.to_string()).collect::<Vec<String>>()) + .unwrap_or_default(); + + command("tar") + .arg("-xf") + .arg(plain_src_tarball.tarball()) + .arg("--strip-components=1") + .current_dir(plain_src_dir) + .run(builder); + command("./configure") + .arg("--set") + .arg("rust.omit-git-hash=false") + .args(&configure_args) + .arg("--enable-vendor") + .current_dir(plain_src_dir) + .run(builder); + command(helpers::make(&builder.config.host_target.triple)) + .arg("check") + // Do not run the build as if we were in CI, otherwise git would be assumed to be + // present, but we build from a tarball here + .env("GITHUB_ACTIONS", "0") + .current_dir(plain_src_dir) + .run(builder); +} + +/// Check that rust-src has all of libstd's dependencies +fn distcheck_rust_src(builder: &Builder<'_>, src_dir: &Path) { + builder.info("Distcheck rust-src"); + let src_tarball = builder.ensure(dist::Src); + builder.clear_dir(src_dir); + + command("tar") + .arg("-xf") + .arg(src_tarball.tarball()) + .arg("--strip-components=1") + .current_dir(src_dir) + .run(builder); + + let toml = src_dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml"); + command(&builder.initial_cargo) + // Will read the libstd Cargo.toml + // which uses the unstable `public-dependency` feature. + .env("RUSTC_BOOTSTRAP", "1") + .arg("generate-lockfile") + .arg("--manifest-path") + .arg(&toml) + .current_dir(src_dir) + .run(builder); +} + +/// Check that rustc-dev's compiler crate source code can be loaded with `cargo metadata` +fn distcheck_rustc_dev(builder: &Builder<'_>, dir: &Path) { + builder.info("Distcheck rustc-dev"); + let tarball = builder.ensure(dist::RustcDev::new(builder, builder.host_target)).unwrap(); + builder.clear_dir(dir); + + command("tar") + .arg("-xf") + .arg(tarball.tarball()) + .arg("--strip-components=1") + .current_dir(dir) + .run(builder); + + command(&builder.initial_cargo) + .arg("metadata") + .arg("--manifest-path") + .arg("rustc-dev/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml") + .env("RUSTC_BOOTSTRAP", "1") + // We might not have a globally available `rustc` binary on CI + .env("RUSTC", &builder.initial_rustc) + .current_dir(dir) + .run(builder); } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -3294,9 +3326,7 @@ impl Step for Bootstrap { .env("INSTA_WORKSPACE_ROOT", &builder.src) .env("RUSTC_BOOTSTRAP", "1"); - // bootstrap tests are racy on directory creation so just run them one at a time. - // Since there's not many this shouldn't be a problem. - run_cargo_test(cargo, &["--test-threads=1"], &[], None, host, builder); + run_cargo_test(cargo, &[], &[], None, host, builder); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 65c4c499086..c5308034fe3 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -82,7 +82,7 @@ impl Step for ToolBuild { let path = self.path; match self.mode { - Mode::ToolRustc => { + Mode::ToolRustcPrivate => { // FIXME: remove this, it's only needed for download-rustc... if !self.build_compiler.is_forced_compiler() && builder.download_rustc() { builder.std(self.build_compiler, self.build_compiler.host); @@ -123,7 +123,7 @@ impl Step for ToolBuild { // Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer) // could use the additional optimizations. - if self.mode == Mode::ToolRustc && is_lto_stage(&self.build_compiler) { + if self.mode == Mode::ToolRustcPrivate && is_lto_stage(&self.build_compiler) { let lto = match builder.config.rust_lto { RustcLto::Off => Some("off"), RustcLto::Thin => Some("thin"), @@ -607,7 +607,7 @@ impl Step for ErrorIndex { build_compiler: self.compilers.build_compiler, target: self.compilers.target(), tool: "error_index_generator", - mode: Mode::ToolRustc, + mode: Mode::ToolRustcPrivate, path: "src/tools/error_index_generator", source_type: SourceType::InTree, extra_features: Vec::new(), @@ -671,7 +671,7 @@ impl Step for RemoteTestServer { /// Represents `Rustdoc` that either comes from the external stage0 sysroot or that is built /// locally. /// Rustdoc is special, because it both essentially corresponds to a `Compiler` (that can be -/// externally provided), but also to a `ToolRustc` tool. +/// externally provided), but also to a `ToolRustcPrivate` tool. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Rustdoc { /// If the stage of `target_compiler` is `0`, then rustdoc is externally provided. @@ -759,7 +759,7 @@ impl Step for Rustdoc { // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" // rustdoc a different name. tool: "rustdoc_tool_binary", - mode: Mode::ToolRustc, + mode: Mode::ToolRustcPrivate, path: "src/tools/rustdoc", source_type: SourceType::InTree, extra_features, @@ -1048,7 +1048,7 @@ impl Step for RustAnalyzer { build_compiler, target, tool: "rust-analyzer", - mode: Mode::ToolRustc, + mode: Mode::ToolRustcPrivate, path: "src/tools/rust-analyzer", extra_features: vec!["in-rust-tree".to_owned()], source_type: SourceType::InTree, @@ -1105,7 +1105,7 @@ impl Step for RustAnalyzerProcMacroSrv { build_compiler: self.compilers.build_compiler, target: self.compilers.target(), tool: "rust-analyzer-proc-macro-srv", - mode: Mode::ToolRustc, + mode: Mode::ToolRustcPrivate, path: "src/tools/rust-analyzer/crates/proc-macro-srv-cli", extra_features: vec!["in-rust-tree".to_owned()], source_type: SourceType::InTree, @@ -1352,7 +1352,7 @@ impl RustcPrivateCompilers { } } -/// Creates a step that builds an extended `Mode::ToolRustc` tool +/// Creates a step that builds an extended `Mode::ToolRustcPrivate` tool /// and installs it into the sysroot of a corresponding compiler. macro_rules! tool_rustc_extended { ( @@ -1466,7 +1466,7 @@ fn build_extended_rustc_tool( build_compiler, target, tool: tool_name, - mode: Mode::ToolRustc, + mode: Mode::ToolRustcPrivate, path, extra_features, source_type: SourceType::InTree, diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index cdf6fe573e5..cca0c803e63 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -533,7 +533,7 @@ impl Builder<'_> { if cmd_kind == Kind::Doc { let my_out = match mode { // This is the intended out directory for compiler documentation. - Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap => { + Mode::Rustc | Mode::ToolRustcPrivate | Mode::ToolBootstrap => { self.compiler_doc_out(target) } Mode::Std => { @@ -583,7 +583,7 @@ impl Builder<'_> { // We synthetically interpret a stage0 compiler used to build tools as a // "raw" compiler in that it's the exact snapshot we download. For things like - // ToolRustc, we would have to use the artificial stage0-sysroot compiler instead. + // ToolRustcPrivate, we would have to use the artificial stage0-sysroot compiler instead. let use_snapshot = mode == Mode::ToolBootstrap || (mode == Mode::ToolTarget && build_compiler_stage == 0); assert!(!use_snapshot || build_compiler_stage == 0 || self.local_rebuild); @@ -643,7 +643,8 @@ impl Builder<'_> { // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native // library unnecessary. This can be removed when windows-rs enables raw-dylib // unconditionally. - if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap | Mode::ToolTarget = mode { + if let Mode::Rustc | Mode::ToolRustcPrivate | Mode::ToolBootstrap | Mode::ToolTarget = mode + { rustflags.arg("--cfg=windows_raw_dylib"); } @@ -657,7 +658,7 @@ impl Builder<'_> { // - rust-analyzer, due to the rowan crate // so we exclude an entire category of steps here due to lack of fine-grained control over // rustflags. - if self.config.rust_randomize_layout && mode != Mode::ToolRustc { + if self.config.rust_randomize_layout && mode != Mode::ToolRustcPrivate { rustflags.arg("-Zrandomize-layout"); } @@ -717,7 +718,7 @@ impl Builder<'_> { match mode { Mode::Std | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => {} - Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { + Mode::Rustc | Mode::Codegen | Mode::ToolRustcPrivate => { // Build proc macros both for the host and the target unless proc-macros are not // supported by the target. if target != compiler.host && cmd_kind != Kind::Check { @@ -778,7 +779,7 @@ impl Builder<'_> { "binary-dep-depinfo,proc_macro_span,proc_macro_span_shrink,proc_macro_diagnostic" .to_string() } - Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => String::new(), + Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustcPrivate => String::new(), }; cargo.arg("-j").arg(self.jobs().to_string()); @@ -825,7 +826,7 @@ impl Builder<'_> { // rustc step and one that we just built. This isn't always a // problem, somehow -- not really clear why -- but we know that this // fixes things. - Mode::ToolRustc => metadata.push_str("tool-rustc"), + Mode::ToolRustcPrivate => metadata.push_str("tool-rustc"), // Same for codegen backends. Mode::Codegen => metadata.push_str("codegen"), _ => {} @@ -877,8 +878,11 @@ impl Builder<'_> { .env("RUSTC_LIBDIR", libdir) .env("RUSTDOC", self.bootstrap_out.join("rustdoc")) .env("RUSTDOC_REAL", rustdoc_path) - .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()) - .env("RUSTC_BREAK_ON_ICE", "1"); + .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()); + + if self.config.rust_break_on_ice { + cargo.env("RUSTC_BREAK_ON_ICE", "1"); + } // Set RUSTC_WRAPPER to the bootstrap shim, which switches between beta and in-tree // sysroot depending on whether we're building build scripts. @@ -917,7 +921,7 @@ impl Builder<'_> { let debuginfo_level = match mode { Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc, Mode::Std => self.config.rust_debuginfo_level_std, - Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => { + Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustcPrivate | Mode::ToolTarget => { self.config.rust_debuginfo_level_tools } }; @@ -930,7 +934,7 @@ impl Builder<'_> { match mode { Mode::Std => self.config.std_debug_assertions, Mode::Rustc | Mode::Codegen => self.config.rustc_debug_assertions, - Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => { + Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustcPrivate | Mode::ToolTarget => { self.config.tools_debug_assertions } } @@ -1005,7 +1009,7 @@ impl Builder<'_> { } Mode::Std | Mode::ToolBootstrap - | Mode::ToolRustc + | Mode::ToolRustcPrivate | Mode::ToolStd | Mode::ToolTarget => { if let Some(ref map_to) = @@ -1078,7 +1082,7 @@ impl Builder<'_> { // requirement, but the `-L` library path is not propagated across // separate Cargo projects. We can add LLVM's library path to the // rustc args as a workaround. - if (mode == Mode::ToolRustc || mode == Mode::Codegen) + if (mode == Mode::ToolRustcPrivate || mode == Mode::Codegen) && let Some(llvm_config) = self.llvm_config(target) { let llvm_libdir = diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index ef01f14f5e9..9e8c13eb4de 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -10,8 +10,8 @@ use crate::core::build_steps::doc::DocumentationFormat; use crate::core::config::Config; use crate::utils::cache::ExecutedStep; use crate::utils::helpers::get_host_target; -use crate::utils::tests::ConfigBuilder; use crate::utils::tests::git::{GitCtx, git_test}; +use crate::utils::tests::{ConfigBuilder, TestCtx}; static TEST_TRIPLE_1: &str = "i686-unknown-haiku"; static TEST_TRIPLE_2: &str = "i686-unknown-hurd-gnu"; @@ -22,38 +22,13 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { } fn configure_with_args(cmd: &[&str], host: &[&str], target: &[&str]) -> Config { - let cmd = cmd.iter().copied().map(String::from).collect::<Vec<_>>(); - let mut config = Config::parse(Flags::parse(&cmd)); - // don't save toolstates - config.save_toolstates = None; - config.set_dry_run(DryRun::SelfCheck); - - // Ignore most submodules, since we don't need them for a dry run, and the - // tests run much faster without them. - // - // The src/doc/book submodule is needed because TheBook step tries to - // access files even during a dry-run (may want to consider just skipping - // that in a dry run). - let submodule_build = Build::new(Config { - // don't include LLVM, so CI doesn't require ninja/cmake to be installed - rust_codegen_backends: vec![], - ..Config::parse(Flags::parse(&["check".to_owned()])) - }); - submodule_build.require_submodule("src/doc/book", None); - config.submodules = Some(false); - - config.ninja_in_file = false; - // try to avoid spurious failures in dist where we create/delete each others file - // HACK: rather than pull in `tempdir`, use the one that cargo has conveniently created for us - let dir = Path::new(env!("OUT_DIR")) - .join("tmp-rustbuild-tests") - .join(&thread::current().name().unwrap_or("unknown").replace(":", "-")); - t!(fs::create_dir_all(&dir)); - config.out = dir; - config.host_target = TargetSelection::from_user(TEST_TRIPLE_1); - config.hosts = host.iter().map(|s| TargetSelection::from_user(s)).collect(); - config.targets = target.iter().map(|s| TargetSelection::from_user(s)).collect(); - config + TestCtx::new() + .config(cmd[0]) + .args(&cmd[1..]) + .hosts(host) + .targets(target) + .args(&["--build", TEST_TRIPLE_1]) + .create_config() } fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> { @@ -547,8 +522,8 @@ mod snapshot { use crate::core::build_steps::{compile, dist, doc, test, tool}; use crate::core::builder::tests::{ - RenderConfig, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, configure, configure_with_args, - first, host_target, render_steps, run_build, + RenderConfig, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, configure, first, host_target, + render_steps, run_build, }; use crate::core::builder::{Builder, Kind, StepDescription, StepMetadata}; use crate::core::config::TargetSelection; diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index d12cc962187..678a9b63952 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -221,6 +221,7 @@ pub struct Config { pub rust_lto: RustcLto, pub rust_validate_mir_opts: Option<u32>, pub rust_std_features: BTreeSet<String>, + pub rust_break_on_ice: bool, pub llvm_profile_use: Option<String>, pub llvm_profile_generate: bool, pub llvm_libunwind_default: Option<LlvmLibunwind>, @@ -550,6 +551,7 @@ impl Config { strip: rust_strip, lld_mode: rust_lld_mode, std_features: rust_std_features, + break_on_ice: rust_break_on_ice, } = toml.rust.unwrap_or_default(); let Llvm { @@ -1269,6 +1271,7 @@ impl Config { reproducible_artifacts: flags_reproducible_artifact, reuse: build_reuse.map(PathBuf::from), rust_analyzer_info, + rust_break_on_ice: rust_break_on_ice.unwrap_or(true), rust_codegen_backends: rust_codegen_backends .map(|backends| parse_codegen_backends(backends, "rust")) .unwrap_or(vec![CodegenBackendKind::Llvm]), diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index c54df456d52..4832a1d37b7 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -65,6 +65,7 @@ define_config! { lto: Option<String> = "lto", validate_mir_opts: Option<u32> = "validate-mir-opts", std_features: Option<BTreeSet<String>> = "std-features", + break_on_ice: Option<bool> = "break-on-ice", } } @@ -355,6 +356,7 @@ pub fn check_incompatible_options_for_ci_rustc( download_rustc: _, validate_mir_opts: _, frame_pointers: _, + break_on_ice: _, } = ci_rust_config; // There are two kinds of checks for CI rustc incompatible options: diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 099ec488397..04cf63f1c6d 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -397,6 +397,16 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake ); } } + + // For testing `wasm32-wasip2`-and-beyond it's required to have + // `wasm-component-ld`. This is enabled by default via `tool_enabled` + // but if it's disabled then double-check it's present on the system. + if target.contains("wasip") + && !target.contains("wasip1") + && !build.tool_enabled("wasm-component-ld") + { + cmd_finder.must_have("wasm-component-ld"); + } } if let Some(ref s) = build.config.ccache { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 59c0f9faaca..a2aeed20948 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -85,12 +85,12 @@ const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"]; const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[ (Some(Mode::Rustc), "bootstrap", None), (Some(Mode::Codegen), "bootstrap", None), - (Some(Mode::ToolRustc), "bootstrap", None), + (Some(Mode::ToolRustcPrivate), "bootstrap", None), (Some(Mode::ToolStd), "bootstrap", None), (Some(Mode::Rustc), "llvm_enzyme", None), (Some(Mode::Codegen), "llvm_enzyme", None), - (Some(Mode::ToolRustc), "llvm_enzyme", None), - (Some(Mode::ToolRustc), "rust_analyzer", None), + (Some(Mode::ToolRustcPrivate), "llvm_enzyme", None), + (Some(Mode::ToolRustcPrivate), "rust_analyzer", None), (Some(Mode::ToolStd), "rust_analyzer", None), // Any library specific cfgs like `target_os`, `target_arch` should be put in // priority the `[lints.rust.unexpected_cfgs.check-cfg]` table @@ -334,17 +334,18 @@ pub enum Mode { /// compiletest which needs libtest. ToolStd, - /// Build a tool which uses the locally built rustc and the target std, + /// Build a tool which uses the `rustc_private` mechanism, and thus + /// the locally built rustc rlib artifacts, /// placing the output in the "stageN-tools" directory. This is used for - /// anything that needs a fully functional rustc, such as rustdoc, clippy, - /// cargo, rustfmt, miri, etc. - ToolRustc, + /// everything that links to rustc as a library, such as rustdoc, clippy, + /// rustfmt, miri, etc. + ToolRustcPrivate, } impl Mode { pub fn is_tool(&self) -> bool { match self { - Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd | Mode::ToolTarget => true, + Mode::ToolBootstrap | Mode::ToolRustcPrivate | Mode::ToolStd | Mode::ToolTarget => true, Mode::Std | Mode::Codegen | Mode::Rustc => false, } } @@ -353,7 +354,7 @@ impl Mode { match self { Mode::Std | Mode::Codegen => true, Mode::ToolBootstrap - | Mode::ToolRustc + | Mode::ToolRustcPrivate | Mode::ToolStd | Mode::ToolTarget | Mode::Rustc => false, @@ -924,7 +925,7 @@ impl Build { Mode::Rustc => (Some(build_compiler.stage + 1), "rustc"), Mode::Codegen => (Some(build_compiler.stage + 1), "codegen"), Mode::ToolBootstrap => bootstrap_tool(), - Mode::ToolStd | Mode::ToolRustc => (Some(build_compiler.stage + 1), "tools"), + Mode::ToolStd | Mode::ToolRustcPrivate => (Some(build_compiler.stage + 1), "tools"), Mode::ToolTarget => { // If we're not cross-compiling (the common case), share the target directory with // bootstrap tools to reuse the build cache. @@ -1145,7 +1146,7 @@ impl Build { | Mode::ToolBootstrap | Mode::ToolTarget | Mode::ToolStd - | Mode::ToolRustc, + | Mode::ToolRustcPrivate, ) | None => target_and_stage.stage + 1, }; diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index bed03c18aaa..a6233e6b61c 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -3,7 +3,8 @@ use std::{env, iter}; use super::*; use crate::core::config::{Target, TargetSelection}; -use crate::{Build, Config, Flags}; +use crate::utils::tests::TestCtx; +use crate::{Build, Config, Flags, t}; #[test] fn test_ndk_compiler_c() { @@ -68,7 +69,8 @@ fn test_language_clang() { #[test] fn test_new_cc_build() { - let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); + let config = TestCtx::new().config("build").create_config(); + let build = Build::new(config); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let cfg = new_cc_build(&build, target.clone()); let compiler = cfg.get_compiler(); @@ -77,7 +79,8 @@ fn test_new_cc_build() { #[test] fn test_default_compiler_wasi() { - let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); + let config = TestCtx::new().config("build").create_config(); + let mut build = Build::new(config); let target = TargetSelection::from_user("wasm32-wasi"); let wasi_sdk = PathBuf::from("/wasi-sdk"); build.wasi_sdk_path = Some(wasi_sdk.clone()); @@ -98,7 +101,8 @@ fn test_default_compiler_wasi() { #[test] fn test_default_compiler_fallback() { - let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); + let config = TestCtx::new().config("build").create_config(); + let build = Build::new(config); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let mut cfg = cc::Build::new(); let result = default_compiler(&mut cfg, Language::C, target, &build); @@ -107,7 +111,8 @@ fn test_default_compiler_fallback() { #[test] fn test_find_target_with_config() { - let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); + let config = TestCtx::new().config("build").create_config(); + let mut build = Build::new(config); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let mut target_config = Target::default(); target_config.cc = Some(PathBuf::from("dummy-cc")); @@ -128,7 +133,8 @@ fn test_find_target_with_config() { #[test] fn test_find_target_without_config() { - let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); + let config = TestCtx::new().config("build").create_config(); + let mut build = Build::new(config); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); build.config.target_config.clear(); fill_target_compiler(&mut build, target.clone()); @@ -141,7 +147,8 @@ fn test_find_target_without_config() { #[test] fn test_find() { - let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); + let config = TestCtx::new().config("build").create_config(); + let mut build = Build::new(config); let target1 = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let target2 = TargetSelection::from_user("x86_64-unknown-openbsd"); build.targets.push(target1.clone()); diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 2cc2fb486fa..01309072927 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -536,4 +536,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "It is no longer possible to `x test` with stage 0, except for running compiletest and opting into `build.compiletest-allow-stage0`.", }, + ChangeInfo { + change_id: 145976, + severity: ChangeSeverity::Info, + summary: "Added a new option `rust.break-on-ice` to control if internal compiler errors cause a debug break on Windows.", + }, ]; diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 70ff5d0d2c7..7e0fb5794f4 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -3,7 +3,8 @@ set -euo pipefail # https://github.com/rust-lang/rust/pull/144443 -LINUX_VERSION=7770d51bce622b13195b2d3c85407282fc9c27e5 +# https://github.com/rust-lang/rust/pull/145928 +LINUX_VERSION=8851e27d2cb947ea8bbbe8e812068f7bf5cbd00b # Build rustc, rustdoc, cargo, clippy-driver and rustfmt ../x.py build --stage 2 library rustdoc clippy rustfmt diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md index 41d0cf8d9fb..c3660e24b15 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md @@ -11,11 +11,8 @@ There are three types of tools you can write in bootstrap: Use this for tools that rely on the locally built std. The output goes into the "stageN-tools" directory. This mode is rarely used, mainly for `compiletest` which requires `libtest`. -- **`Mode::ToolRustc`** - Use this for tools that depend on both the locally built `rustc` and the target `std`. This is more complex than - the other modes because the tool must be built with the same compiler used for `rustc` and placed in the "stageN-tools" - directory. When you choose `Mode::ToolRustc`, `ToolBuild` implementation takes care of this automatically. - If you need to use the builder’s compiler for something specific, you can get it from `ToolBuildResult`, which is +- **`Mode::ToolRustcPrivate`** + Use this for tools that use the `rustc_private` mechanism, and thus depend on the locally built `rustc` and its rlib artifacts. This is more complex than the other modes because the tool must be built with the same compiler used for `rustc` and placed in the "stageN-tools" directory. When you choose `Mode::ToolRustcPrivate`, `ToolBuild` implementation takes care of this automatically. If you need to use the builder’s compiler for something specific, you can get it from `ToolBuildResult`, which is returned by the tool's [`Step`]. Regardless of the tool type you must return `ToolBuildResult` from the tool’s [`Step`] implementation and use `ToolBuild` inside it. diff --git a/src/doc/rustc/src/command-line-arguments/print-options.md b/src/doc/rustc/src/command-line-arguments/print-options.md index fed19d6b667..f37b27d88c3 100644 --- a/src/doc/rustc/src/command-line-arguments/print-options.md +++ b/src/doc/rustc/src/command-line-arguments/print-options.md @@ -184,7 +184,7 @@ Example: ```bash $ rustc --print native-static-libs --crate-type staticlib a.rs -note: Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms. +note: link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms. note: native-static-libs: -lgcc_s -lutil [REDACTED] -lpthread -lm -ldl -lc ``` diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index dfe193e6e8a..6c5b48d8c8f 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -33,6 +33,7 @@ All tier 1 targets with host tools support the full standard library. target | notes -------|------- [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) +[`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+) [`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI] @@ -88,7 +89,6 @@ so Rustup may install the documentation for a similar tier 1 target instead. target | notes -------|------- [`aarch64-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ARM64 MinGW (Windows 10+), LLVM ABI -[`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC [`aarch64-unknown-linux-musl`](platform-support/aarch64-unknown-linux-musl.md) | ARM64 Linux with musl 1.2.3 [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17) diff --git a/src/doc/rustc/src/platform-support/windows-msvc.md b/src/doc/rustc/src/platform-support/windows-msvc.md index 71dc4ddc2e6..826c75b79c5 100644 --- a/src/doc/rustc/src/platform-support/windows-msvc.md +++ b/src/doc/rustc/src/platform-support/windows-msvc.md @@ -4,13 +4,10 @@ Windows MSVC targets. **Tier 1 with host tools:** +- `aarch64-pc-windows-msvc`: Windows on ARM64. - `i686-pc-windows-msvc`: Windows on 32-bit x86. - `x86_64-pc-windows-msvc`: Windows on 64-bit x86. -**Tier 2 with host tools:** - -- `aarch64-pc-windows-msvc`: Windows on ARM64. - ## Target maintainers [@ChrisDenton](https://github.com/ChrisDenton) diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index 8d7f7341c2e..46a3a1602ac 100755 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -247,7 +247,7 @@ class CachedFiles(object): paths = list(Path(self.root).glob(path)) if len(paths) != 1: raise FailedCheck("glob path does not resolve to one file") - path = str(paths[0]) + return str(paths[0]) return os.path.join(self.root, path) def get_file(self, path): diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 450ac04b40d..d7f6fa347be 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -454,15 +454,22 @@ impl Options { return None; } - let mut emit = Vec::new(); + let mut emit = FxIndexMap::<_, EmitType>::default(); for list in matches.opt_strs("emit") { for kind in list.split(',') { match kind.parse() { - Ok(kind) => emit.push(kind), + Ok(kind) => { + // De-duplicate emit types and the last wins. + // Only one instance for each type is allowed + // regardless the actual data it carries. + // This matches rustc's `--emit` behavior. + emit.insert(std::mem::discriminant(&kind), kind); + } Err(()) => dcx.fatal(format!("unrecognized emission type: {kind}")), } } } + let emit = emit.into_values().collect::<Vec<_>>(); let show_coverage = matches.opt_present("show-coverage"); let output_format_s = matches.opt_str("output-format"); @@ -814,7 +821,8 @@ impl Options { let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx); let with_examples = matches.opt_strs("with-examples"); - let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx); + let call_locations = + crate::scrape_examples::load_call_locations(with_examples, dcx, &mut loaded_paths); let doctest_build_args = matches.opt_strs("doctest-build-arg"); let unstable_features = diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 16034c11827..471e966e2c2 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -333,14 +333,11 @@ pub(crate) fn run( pub(crate) fn load_call_locations( with_examples: Vec<String>, dcx: DiagCtxtHandle<'_>, + loaded_paths: &mut Vec<PathBuf>, ) -> AllCallLocations { let mut all_calls: AllCallLocations = FxIndexMap::default(); for path in with_examples { - // FIXME: Figure out why this line is causing this feature to crash in specific contexts. - // Full issue backlog is available here: <https://github.com/rust-lang/rust/pull/144600>. - // - // Can be checked with `tests/run-make/rustdoc-scrape-examples-paths`. - // loaded_paths.push(path.clone().into()); + loaded_paths.push(path.clone().into()); let bytes = match fs::read(&path) { Ok(bytes) => bytes, Err(e) => dcx.fatal(format!("failed to load examples: {e}")), diff --git a/src/tools/cargo b/src/tools/cargo -Subproject a6c58d43051d01d83f55a3e61ef5f5b2b0dd6bd +Subproject 761c4658d0079d607e6d33cf0c060e61a617cad diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 89b1b4f84b6..62fdee98735 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -667,6 +667,10 @@ pub struct Config { /// to avoid `!nocapture` double-negatives. pub nocapture: bool, + /// True if the experimental new output-capture implementation should be + /// used, avoiding the need for `#![feature(internal_output_capture)]`. + pub new_output_capture: bool, + /// Needed both to construct [`build_helper::git::GitConfig`]. pub nightly_branch: String, pub git_merge_commit_email: String, @@ -784,6 +788,7 @@ impl Config { builtin_cfg_names: Default::default(), supported_crate_types: Default::default(), nocapture: Default::default(), + new_output_capture: Default::default(), nightly_branch: Default::default(), git_merge_commit_email: Default::default(), profiler_runtime: Default::default(), diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 5519ef1af1f..b0dc24798b6 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -13,6 +13,7 @@ use std::sync::{Arc, Mutex, mpsc}; use std::{env, hint, io, mem, panic, thread}; use crate::common::{Config, TestPaths}; +use crate::output_capture::{self, ConsoleOut}; use crate::panic_hook; mod deadline; @@ -120,28 +121,28 @@ fn run_test_inner( runnable_test: RunnableTest, completion_sender: mpsc::Sender<TestCompletion>, ) { - let is_capture = !runnable_test.config.nocapture; + let capture = CaptureKind::for_config(&runnable_test.config); // Install a panic-capture buffer for use by the custom panic hook. - if is_capture { + if capture.should_set_panic_hook() { panic_hook::set_capture_buf(Default::default()); } - let capture_buf = is_capture.then(|| Arc::new(Mutex::new(vec![]))); - if let Some(capture_buf) = &capture_buf { - io::set_output_capture(Some(Arc::clone(capture_buf))); + if let CaptureKind::Old { ref buf } = capture { + io::set_output_capture(Some(Arc::clone(buf))); } - let panic_payload = panic::catch_unwind(move || runnable_test.run()).err(); + let stdout = capture.stdout(); + let stderr = capture.stderr(); + + let panic_payload = panic::catch_unwind(move || runnable_test.run(stdout, stderr)).err(); if let Some(panic_buf) = panic_hook::take_capture_buf() { let panic_buf = panic_buf.lock().unwrap_or_else(|e| e.into_inner()); - // For now, forward any captured panic message to (captured) stderr. - // FIXME(Zalathar): Once we have our own output-capture buffer for - // non-panic output, append the panic message to that buffer instead. - eprint!("{panic_buf}"); + // Forward any captured panic message to (captured) stderr. + write!(stderr, "{panic_buf}"); } - if is_capture { + if matches!(capture, CaptureKind::Old { .. }) { io::set_output_capture(None); } @@ -152,11 +153,70 @@ fn run_test_inner( TestOutcome::Failed { message: Some("test did not panic as expected") } } }; - let stdout = capture_buf.map(|mutex| mutex.lock().unwrap_or_else(|e| e.into_inner()).to_vec()); + let stdout = capture.into_inner(); completion_sender.send(TestCompletion { id, outcome, stdout }).unwrap(); } +enum CaptureKind { + /// Do not capture test-runner output, for `--no-capture`. + /// + /// (This does not affect `rustc` and other subprocesses spawned by test + /// runners, whose output is always captured.) + None, + + /// Use the old output-capture implementation, which relies on the unstable + /// library feature `#![feature(internal_output_capture)]`. + Old { buf: Arc<Mutex<Vec<u8>>> }, + + /// Use the new output-capture implementation, which only uses stable Rust. + New { buf: output_capture::CaptureBuf }, +} + +impl CaptureKind { + fn for_config(config: &Config) -> Self { + if config.nocapture { + Self::None + } else if config.new_output_capture { + Self::New { buf: output_capture::CaptureBuf::new() } + } else { + // Create a capure buffer for `io::set_output_capture`. + Self::Old { buf: Default::default() } + } + } + + fn should_set_panic_hook(&self) -> bool { + match self { + Self::None => false, + Self::Old { .. } => true, + Self::New { .. } => true, + } + } + + fn stdout(&self) -> &dyn ConsoleOut { + self.capture_buf_or(&output_capture::Stdout) + } + + fn stderr(&self) -> &dyn ConsoleOut { + self.capture_buf_or(&output_capture::Stderr) + } + + fn capture_buf_or<'a>(&'a self, fallback: &'a dyn ConsoleOut) -> &'a dyn ConsoleOut { + match self { + Self::None | Self::Old { .. } => fallback, + Self::New { buf } => buf, + } + } + + fn into_inner(self) -> Option<Vec<u8>> { + match self { + Self::None => None, + Self::Old { buf } => Some(buf.lock().unwrap_or_else(|e| e.into_inner()).to_vec()), + Self::New { buf } => Some(buf.into_inner().into()), + } + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] struct TestId(usize); @@ -174,10 +234,12 @@ impl RunnableTest { Self { config, testpaths, revision } } - fn run(&self) { + fn run(&self, stdout: &dyn ConsoleOut, stderr: &dyn ConsoleOut) { __rust_begin_short_backtrace(|| { crate::runtest::run( Arc::clone(&self.config), + stdout, + stderr, &self.testpaths, self.revision.as_deref(), ); diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index fa84691a46f..f647f96a9bf 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -15,6 +15,7 @@ pub mod directives; pub mod errors; mod executor; mod json; +mod output_capture; mod panic_hook; mod raise_fd_limit; mod read2; @@ -177,6 +178,12 @@ pub fn parse_config(args: Vec<String>) -> Config { // FIXME: Temporarily retained so we can point users to `--no-capture` .optflag("", "nocapture", "") .optflag("", "no-capture", "don't capture stdout/stderr of tests") + .optopt( + "N", + "new-output-capture", + "enables or disables the new output-capture implementation", + "off|on", + ) .optflag("", "profiler-runtime", "is the profiler runtime enabled for this target") .optflag("h", "help", "show this message") .reqopt("", "channel", "current Rust channel", "CHANNEL") @@ -461,6 +468,14 @@ pub fn parse_config(args: Vec<String>) -> Config { supported_crate_types: OnceLock::new(), nocapture: matches.opt_present("no-capture"), + new_output_capture: { + let value = matches + .opt_str("new-output-capture") + .or_else(|| env::var("COMPILETEST_NEW_OUTPUT_CAPTURE").ok()) + .unwrap_or_else(|| "off".to_owned()); + parse_bool_option(&value) + .unwrap_or_else(|| panic!("unknown `--new-output-capture` value `{value}` given")) + }, nightly_branch: matches.opt_str("nightly-branch").unwrap(), git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(), @@ -476,6 +491,19 @@ pub fn parse_config(args: Vec<String>) -> Config { } } +/// Parses the same set of boolean values accepted by rustc command-line arguments. +/// +/// Accepting all of these values is more complicated than just picking one +/// pair, but has the advantage that contributors who are used to rustc +/// shouldn't have to think about which values are legal. +fn parse_bool_option(value: &str) -> Option<bool> { + match value { + "off" | "no" | "n" | "false" => Some(false), + "on" | "yes" | "y" | "true" => Some(true), + _ => None, + } +} + pub fn opt_str(maybestr: &Option<String>) -> &str { match *maybestr { None => "(none)", diff --git a/src/tools/compiletest/src/output_capture.rs b/src/tools/compiletest/src/output_capture.rs new file mode 100644 index 00000000000..de1aea11ade --- /dev/null +++ b/src/tools/compiletest/src/output_capture.rs @@ -0,0 +1,52 @@ +use std::fmt; +use std::panic::RefUnwindSafe; +use std::sync::Mutex; + +pub trait ConsoleOut: fmt::Debug + RefUnwindSafe { + fn write_fmt(&self, args: fmt::Arguments<'_>); +} + +#[derive(Debug)] +pub(crate) struct Stdout; + +impl ConsoleOut for Stdout { + fn write_fmt(&self, args: fmt::Arguments<'_>) { + print!("{args}"); + } +} + +#[derive(Debug)] +pub(crate) struct Stderr; + +impl ConsoleOut for Stderr { + fn write_fmt(&self, args: fmt::Arguments<'_>) { + eprint!("{args}"); + } +} + +pub(crate) struct CaptureBuf { + inner: Mutex<String>, +} + +impl CaptureBuf { + pub(crate) fn new() -> Self { + Self { inner: Mutex::new(String::new()) } + } + + pub(crate) fn into_inner(self) -> String { + self.inner.into_inner().unwrap_or_else(|e| e.into_inner()) + } +} + +impl fmt::Debug for CaptureBuf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("CaptureBuf").finish_non_exhaustive() + } +} + +impl ConsoleOut for CaptureBuf { + fn write_fmt(&self, args: fmt::Arguments<'_>) { + let mut s = self.inner.lock().unwrap_or_else(|e| e.into_inner()); + <String as fmt::Write>::write_fmt(&mut s, args).unwrap(); + } +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 867624cc8fa..89fb8eb4357 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -23,6 +23,7 @@ use crate::common::{ }; use crate::directives::TestProps; use crate::errors::{Error, ErrorKind, load_errors}; +use crate::output_capture::ConsoleOut; use crate::read2::{Truncated, read2_abbreviated}; use crate::runtest::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; use crate::util::{Utf8PathBufExt, add_dylib_path, static_regex}; @@ -108,7 +109,13 @@ fn dylib_name(name: &str) -> String { format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION) } -pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) { +pub fn run( + config: Arc<Config>, + stdout: &dyn ConsoleOut, + stderr: &dyn ConsoleOut, + testpaths: &TestPaths, + revision: Option<&str>, +) { match &*config.target { "arm-linux-androideabi" | "armv7-linux-androideabi" @@ -131,7 +138,7 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) { if config.verbose { // We're going to be dumping a lot of info. Start on a new line. - print!("\n\n"); + write!(stdout, "\n\n"); } debug!("running {}", testpaths.file); let mut props = TestProps::from_file(&testpaths.file, revision, &config); @@ -143,7 +150,7 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) { props.incremental_dir = Some(incremental_dir(&config, testpaths, revision)); } - let cx = TestCx { config: &config, props: &props, testpaths, revision }; + let cx = TestCx { config: &config, stdout, stderr, props: &props, testpaths, revision }; if let Err(e) = create_dir_all(&cx.output_base_dir()) { panic!("failed to create output base directory {}: {e}", cx.output_base_dir()); @@ -162,6 +169,8 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) { revision_props.incremental_dir = props.incremental_dir.clone(); let rev_cx = TestCx { config: &config, + stdout, + stderr, props: &revision_props, testpaths, revision: Some(revision), @@ -212,6 +221,8 @@ pub fn compute_stamp_hash(config: &Config) -> String { #[derive(Copy, Clone, Debug)] struct TestCx<'test> { config: &'test Config, + stdout: &'test dyn ConsoleOut, + stderr: &'test dyn ConsoleOut, props: &'test TestProps, testpaths: &'test TestPaths, revision: Option<&'test str>, @@ -603,7 +614,8 @@ impl<'test> TestCx<'test> { ); } else { for pattern in missing_patterns { - println!( + writeln!( + self.stdout, "\n{prefix}: error pattern '{pattern}' not found!", prefix = self.error_prefix() ); @@ -783,7 +795,8 @@ impl<'test> TestCx<'test> { }; format!("{file_name}:{line_num}{opt_col_num}") }; - let print_error = |e| println!("{}: {}: {}", line_str(e), e.kind, e.msg.cyan()); + let print_error = + |e| writeln!(self.stdout, "{}: {}: {}", line_str(e), e.kind, e.msg.cyan()); let push_suggestion = |suggestions: &mut Vec<_>, e: &Error, kind, line, msg, color, rank| { let mut ret = String::new(); @@ -811,7 +824,7 @@ impl<'test> TestCx<'test> { if let Some(&(_, top_rank)) = suggestions.first() { for (suggestion, rank) in suggestions { if rank == top_rank { - println!(" {} {suggestion}", prefix.color(color)); + writeln!(self.stdout, " {} {suggestion}", prefix.color(color)); } } } @@ -824,7 +837,8 @@ impl<'test> TestCx<'test> { // - only known line - meh, but suggested // - others are not worth suggesting if !unexpected.is_empty() { - println!( + writeln!( + self.stdout, "\n{prefix}: {n} diagnostics reported in JSON output but not expected in test file", prefix = self.error_prefix(), n = unexpected.len(), @@ -858,7 +872,8 @@ impl<'test> TestCx<'test> { } } if !not_found.is_empty() { - println!( + writeln!( + self.stdout, "\n{prefix}: {n} diagnostics expected in test file but not reported in JSON output", prefix = self.error_prefix(), n = not_found.len(), @@ -978,6 +993,8 @@ impl<'test> TestCx<'test> { self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config); let aux_cx = TestCx { config: self.config, + stdout: self.stdout, + stderr: self.stderr, props: &props_for_aux, testpaths: &aux_testpaths, revision: self.revision, @@ -1343,6 +1360,8 @@ impl<'test> TestCx<'test> { let aux_output = TargetLocation::ThisDirectory(aux_dir.clone()); let aux_cx = TestCx { config: self.config, + stdout: self.stdout, + stderr: self.stderr, props: &aux_props, testpaths: &aux_testpaths, revision: self.revision, @@ -1948,11 +1967,11 @@ impl<'test> TestCx<'test> { } else { path.file_name().unwrap().into() }; - println!("------{proc_name} stdout------------------------------"); - println!("{}", out); - println!("------{proc_name} stderr------------------------------"); - println!("{}", err); - println!("------------------------------------------"); + writeln!(self.stdout, "------{proc_name} stdout------------------------------"); + writeln!(self.stdout, "{}", out); + writeln!(self.stdout, "------{proc_name} stderr------------------------------"); + writeln!(self.stdout, "{}", err); + writeln!(self.stdout, "------------------------------------------"); } fn dump_output_file(&self, out: &str, extension: &str) { @@ -2014,7 +2033,7 @@ impl<'test> TestCx<'test> { debug!("{message}"); if self.config.verbose { // Note: `./x test ... --verbose --no-capture` is needed to see this print. - println!("{message}"); + writeln!(self.stdout, "{message}"); } } @@ -2030,7 +2049,7 @@ impl<'test> TestCx<'test> { #[track_caller] fn fatal(&self, err: &str) -> ! { - println!("\n{prefix}: {err}", prefix = self.error_prefix()); + writeln!(self.stdout, "\n{prefix}: {err}", prefix = self.error_prefix()); error!("fatal error, panic: {:?}", err); panic!("fatal error"); } @@ -2048,15 +2067,15 @@ impl<'test> TestCx<'test> { proc_res: &ProcRes, callback_before_unwind: impl FnOnce(), ) -> ! { - println!("\n{prefix}: {err}", prefix = self.error_prefix()); + writeln!(self.stdout, "\n{prefix}: {err}", prefix = self.error_prefix()); // Some callers want to print additional notes after the main error message. if let Some(note) = extra_note { - println!("{note}"); + writeln!(self.stdout, "{note}"); } // Print the details and output of the subprocess that caused this test to fail. - println!("{}", proc_res.format_info()); + writeln!(self.stdout, "{}", proc_res.format_info()); // Some callers want print more context or show a custom diff before the unwind occurs. callback_before_unwind(); @@ -2126,7 +2145,7 @@ impl<'test> TestCx<'test> { if !self.config.has_html_tidy { return; } - println!("info: generating a diff against nightly rustdoc"); + writeln!(self.stdout, "info: generating a diff against nightly rustdoc"); let suffix = self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly"); @@ -2162,7 +2181,7 @@ impl<'test> TestCx<'test> { let proc_res = new_rustdoc.document(&compare_dir, &new_rustdoc.testpaths); if !proc_res.status.success() { - eprintln!("failed to run nightly rustdoc"); + writeln!(self.stderr, "failed to run nightly rustdoc"); return; } @@ -2207,6 +2226,7 @@ impl<'test> TestCx<'test> { let diff_filename = format!("build/tmp/rustdoc-compare-{}.diff", std::process::id()); if !write_filtered_diff( + self, &diff_filename, out_dir, &compare_dir, @@ -2227,7 +2247,7 @@ impl<'test> TestCx<'test> { if let Some(pager) = pager { let pager = pager.trim(); if self.config.verbose { - eprintln!("using pager {}", pager); + writeln!(self.stderr, "using pager {}", pager); } let output = Command::new(pager) // disable paging; we want this to be non-interactive @@ -2238,8 +2258,8 @@ impl<'test> TestCx<'test> { .output() .unwrap(); assert!(output.status.success()); - println!("{}", String::from_utf8_lossy(&output.stdout)); - eprintln!("{}", String::from_utf8_lossy(&output.stderr)); + writeln!(self.stdout, "{}", String::from_utf8_lossy(&output.stdout)); + writeln!(self.stderr, "{}", String::from_utf8_lossy(&output.stderr)); } else { warning!("no pager configured, falling back to unified diff"); help!( @@ -2254,7 +2274,7 @@ impl<'test> TestCx<'test> { match diff.read_until(b'\n', &mut line) { Ok(0) => break, Ok(_) => {} - Err(e) => eprintln!("ERROR: {:?}", e), + Err(e) => writeln!(self.stderr, "ERROR: {:?}", e), } match String::from_utf8(line.clone()) { Ok(line) => { @@ -2802,11 +2822,11 @@ impl<'test> TestCx<'test> { if let Err(err) = fs::write(&actual_path, &actual) { self.fatal(&format!("failed to write {stream} to `{actual_path}`: {err}",)); } - println!("Saved the actual {stream} to `{actual_path}`"); + writeln!(self.stdout, "Saved the actual {stream} to `{actual_path}`"); if !self.config.bless { if expected.is_empty() { - println!("normalized {}:\n{}\n", stream, actual); + writeln!(self.stdout, "normalized {}:\n{}\n", stream, actual); } else { self.show_diff( stream, @@ -2830,14 +2850,15 @@ impl<'test> TestCx<'test> { if let Err(err) = fs::write(&expected_path, &actual) { self.fatal(&format!("failed to write {stream} to `{expected_path}`: {err}")); } - println!( + writeln!( + self.stdout, "Blessing the {stream} of `{test_name}` as `{expected_path}`", test_name = self.testpaths.file ); } } - println!("\nThe actual {stream} differed from the expected {stream}"); + writeln!(self.stdout, "\nThe actual {stream} differed from the expected {stream}"); if self.config.bless { CompareOutcome::Blessed } else { CompareOutcome::Differed } } @@ -2852,7 +2873,7 @@ impl<'test> TestCx<'test> { actual: &str, actual_unnormalized: &str, ) { - eprintln!("diff of {stream}:\n"); + writeln!(self.stderr, "diff of {stream}:\n"); if let Some(diff_command) = self.config.diff_command.as_deref() { let mut args = diff_command.split_whitespace(); let name = args.next().unwrap(); @@ -2864,11 +2885,11 @@ impl<'test> TestCx<'test> { } Ok(output) => { let output = String::from_utf8_lossy(&output.stdout); - eprint!("{output}"); + write!(self.stderr, "{output}"); } } } else { - eprint!("{}", write_diff(expected, actual, 3)); + write!(self.stderr, "{}", write_diff(expected, actual, 3)); } // NOTE: argument order is important, we need `actual` to be on the left so the line number match up when we compare it to `actual_unnormalized` below. @@ -2906,9 +2927,16 @@ impl<'test> TestCx<'test> { && !mismatches_unnormalized.is_empty() && !mismatches_normalized.is_empty() { - eprintln!("Note: some mismatched output was normalized before being compared"); + writeln!( + self.stderr, + "Note: some mismatched output was normalized before being compared" + ); // FIXME: respect diff_command - eprint!("{}", write_diff(&mismatches_unnormalized, &mismatches_normalized, 0)); + write!( + self.stderr, + "{}", + write_diff(&mismatches_unnormalized, &mismatches_normalized, 0) + ); } } @@ -2986,7 +3014,7 @@ impl<'test> TestCx<'test> { fs::create_dir_all(&incremental_dir).unwrap(); if self.config.verbose { - println!("init_incremental_test: incremental_dir={incremental_dir}"); + writeln!(self.stdout, "init_incremental_test: incremental_dir={incremental_dir}"); } } } diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs index 44ddcb1d288..16c251c3c9e 100644 --- a/src/tools/compiletest/src/runtest/codegen_units.rs +++ b/src/tools/compiletest/src/runtest/codegen_units.rs @@ -62,13 +62,13 @@ impl TestCx<'_> { if !missing.is_empty() { missing.sort(); - println!("\nThese items should have been contained but were not:\n"); + writeln!(self.stdout, "\nThese items should have been contained but were not:\n"); for item in &missing { - println!("{}", item); + writeln!(self.stdout, "{}", item); } - println!("\n"); + writeln!(self.stdout, "\n"); } if !unexpected.is_empty() { @@ -78,24 +78,32 @@ impl TestCx<'_> { sorted }; - println!("\nThese items were contained but should not have been:\n"); + writeln!(self.stdout, "\nThese items were contained but should not have been:\n"); for item in sorted { - println!("{}", item); + writeln!(self.stdout, "{}", item); } - println!("\n"); + writeln!(self.stdout, "\n"); } if !wrong_cgus.is_empty() { wrong_cgus.sort_by_key(|pair| pair.0.name.clone()); - println!("\nThe following items were assigned to wrong codegen units:\n"); + writeln!(self.stdout, "\nThe following items were assigned to wrong codegen units:\n"); for &(ref expected_item, ref actual_item) in &wrong_cgus { - println!("{}", expected_item.name); - println!(" expected: {}", codegen_units_to_str(&expected_item.codegen_units)); - println!(" actual: {}", codegen_units_to_str(&actual_item.codegen_units)); - println!(); + writeln!(self.stdout, "{}", expected_item.name); + writeln!( + self.stdout, + " expected: {}", + codegen_units_to_str(&expected_item.codegen_units) + ); + writeln!( + self.stdout, + " actual: {}", + codegen_units_to_str(&actual_item.codegen_units) + ); + writeln!(self.stdout); } } diff --git a/src/tools/compiletest/src/runtest/compute_diff.rs b/src/tools/compiletest/src/runtest/compute_diff.rs index 509e7e11703..3363127b3ea 100644 --- a/src/tools/compiletest/src/runtest/compute_diff.rs +++ b/src/tools/compiletest/src/runtest/compute_diff.rs @@ -3,6 +3,8 @@ use std::fs::{File, FileType}; use camino::Utf8Path; +use crate::runtest::TestCx; + #[derive(Debug, PartialEq)] pub enum DiffLine { Context(String), @@ -112,6 +114,7 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S /// /// Returns whether any data was actually written. pub(crate) fn write_filtered_diff<Filter>( + cx: &TestCx<'_>, diff_filename: &str, out_dir: &Utf8Path, compare_dir: &Utf8Path, @@ -147,11 +150,11 @@ where } if !wrote_data { - println!("note: diff is identical to nightly rustdoc"); + writeln!(cx.stdout, "note: diff is identical to nightly rustdoc"); assert!(diff_output.metadata().unwrap().len() == 0); return false; } else if verbose { - eprintln!("printing diff:"); + writeln!(cx.stderr, "printing diff:"); let mut buf = Vec::new(); diff_output.read_to_end(&mut buf).unwrap(); std::io::stderr().lock().write_all(&mut buf).unwrap(); diff --git a/src/tools/compiletest/src/runtest/crashes.rs b/src/tools/compiletest/src/runtest/crashes.rs index da1e74b4a56..0aae7eaa39c 100644 --- a/src/tools/compiletest/src/runtest/crashes.rs +++ b/src/tools/compiletest/src/runtest/crashes.rs @@ -6,10 +6,10 @@ impl TestCx<'_> { let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm)); if std::env::var("COMPILETEST_VERBOSE_CRASHES").is_ok() { - eprintln!("{}", proc_res.status); - eprintln!("{}", proc_res.stdout); - eprintln!("{}", proc_res.stderr); - eprintln!("{}", proc_res.cmdline); + writeln!(self.stderr, "{}", proc_res.status); + writeln!(self.stderr, "{}", proc_res.stdout); + writeln!(self.stderr, "{}", proc_res.stderr); + writeln!(self.stderr, "{}", proc_res.cmdline); } // if a test does not crash, consider it an error diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 88d022b8bba..071c0863b7e 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -245,7 +245,7 @@ impl TestCx<'_> { cmdline, }; if adb.kill().is_err() { - println!("Adb process is already finished."); + writeln!(self.stdout, "Adb process is already finished."); } } else { let rust_pp_module_abs_path = self.config.src_root.join("src").join("etc"); @@ -256,7 +256,11 @@ impl TestCx<'_> { match self.config.gdb_version { Some(version) => { - println!("NOTE: compiletest thinks it is using GDB version {}", version); + writeln!( + self.stdout, + "NOTE: compiletest thinks it is using GDB version {}", + version + ); if !self.props.disable_gdb_pretty_printers && version > extract_gdb_version("7.4").unwrap() @@ -278,7 +282,8 @@ impl TestCx<'_> { } } _ => { - println!( + writeln!( + self.stdout, "NOTE: compiletest does not know which version of \ GDB it is using" ); @@ -376,10 +381,15 @@ impl TestCx<'_> { match self.config.lldb_version { Some(ref version) => { - println!("NOTE: compiletest thinks it is using LLDB version {}", version); + writeln!( + self.stdout, + "NOTE: compiletest thinks it is using LLDB version {}", + version + ); } _ => { - println!( + writeln!( + self.stdout, "NOTE: compiletest does not know which version of \ LLDB it is using" ); diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs index 90cff6bab4d..44eb80300c3 100644 --- a/src/tools/compiletest/src/runtest/incremental.rs +++ b/src/tools/compiletest/src/runtest/incremental.rs @@ -30,7 +30,7 @@ impl TestCx<'_> { assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir"); if self.config.verbose { - print!("revision={:?} props={:#?}", revision, self.props); + write!(self.stdout, "revision={:?} props={:#?}", revision, self.props); } if revision.starts_with("cpass") { diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs index 55043bf4bc2..94487926383 100644 --- a/src/tools/compiletest/src/runtest/mir_opt.rs +++ b/src/tools/compiletest/src/runtest/mir_opt.rs @@ -80,7 +80,7 @@ impl TestCx<'_> { } let expected_string = fs::read_to_string(&expected_file).unwrap(); if dumped_string != expected_string { - print!("{}", write_diff(&expected_string, &dumped_string, 3)); + write!(self.stdout, "{}", write_diff(&expected_string, &dumped_string, 3)); panic!( "Actual MIR output differs from expected MIR output {}", expected_file.display() diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs index 083398f9274..b8da6e2ac52 100644 --- a/src/tools/compiletest/src/runtest/rustdoc_json.rs +++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs @@ -30,8 +30,8 @@ impl TestCx<'_> { if !res.status.success() { self.fatal_proc_rec_general("jsondocck failed!", None, &res, || { - println!("Rustdoc Output:"); - println!("{}", proc_res.format_info()); + writeln!(self.stdout, "Rustdoc Output:"); + writeln!(self.stdout, "{}", proc_res.format_info()); }) } diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index 40b0ee0a399..d683a325c86 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -115,10 +115,14 @@ impl TestCx<'_> { } if errors > 0 { - println!("To update references, rerun the tests and pass the `--bless` flag"); + writeln!( + self.stdout, + "To update references, rerun the tests and pass the `--bless` flag" + ); let relative_path_to_file = self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap()); - println!( + writeln!( + self.stdout, "To only update this specific test, also pass `--test-args {}`", relative_path_to_file, ); diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 1f16a672a98..558e9a58697 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -45,7 +45,7 @@ impl Utf8PathBufExt for Utf8PathBuf { /// The name of the environment variable that holds dynamic library locations. pub fn dylib_env_var() -> &'static str { - if cfg!(windows) { + if cfg!(any(windows, target_os = "cygwin")) { "PATH" } else if cfg!(target_vendor = "apple") { "DYLD_LIBRARY_PATH" diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 7d79c384f85..c0fed96d4e6 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -41,6 +41,11 @@ jobs: multiarch: s390x gcc_cross: s390x-linux-gnu qemu: true + - host_target: powerpc64le-unknown-linux-gnu + os: ubuntu-latest + multiarch: ppc64el + gcc_cross: powerpc64le-linux-gnu + qemu: true - host_target: aarch64-apple-darwin os: macos-latest - host_target: i686-pc-windows-msvc diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 7d78fdddbad..073ad267476 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -255,6 +255,12 @@ when installing the Miri toolchain. Alternatively, set the `RUSTUP_TOOLCHAIN` en [`etc/rust_analyzer_helix.toml`]: https://github.com/rust-lang/miri/blob/master/etc/rust_analyzer_helix.toml +### Zed + +Copy [`etc/rust_analyzer_zed.json`] to `.zed/settings.json` in the project root directory. + +[`etc/rust_analyzer_zed.json`]: https://github.com/rust-lang/miri/blob/master/etc/rust_analyzer_zed.json + ### Advanced configuration If you are building Miri with a locally built rustc, set diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index b46f0f83420..4df17c83c7e 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -1569,9 +1569,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ "sharded-slab", "thread_local", diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 99111092d39..924dfed2bca 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -39,7 +39,7 @@ features = ['unprefixed_malloc_on_supported_platforms'] [target.'cfg(unix)'.dependencies] libc = "0.2" # native-lib dependencies -libffi = { version = "4.0.0", optional = true } +libffi = { version = "4.1.1", optional = true } libloading = { version = "0.8", optional = true } serde = { version = "1.0.219", features = ["derive"], optional = true } diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 7ccd27d7b83..517aa343a6d 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -319,8 +319,14 @@ environment variable. We first document the most relevant and most commonly used Can be used without a value; in that case the range defaults to `0..64`. * `-Zmiri-many-seeds-keep-going` tells Miri to really try all the seeds in the given range, even if a failing seed has already been found. This is useful to determine which fraction of seeds fails. +* `-Zmiri-max-extra-rounding-error` tells Miri to always apply the maximum error to float operations + that do not have a guaranteed precision. The sign of the error is still non-deterministic. * `-Zmiri-no-extra-rounding-error` stops Miri from adding extra rounding errors to float operations that do not have a guaranteed precision. +* `-Zmiri-no-short-fd-operations` stops Miri from artificially forcing `read`/`write` operations + to only process a part of their buffer. Note that whenever Miri uses host operations to + implement `read`/`write` (e.g. for file-backed file descriptors), the host system can still + introduce short reads/writes. * `-Zmiri-num-cpus` states the number of available CPUs to be reported by miri. By default, the number of available CPUs is `1`. Note that this flag does not affect how miri handles threads in any way. diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock index b3f5dafab64..ea9c04a3cb5 100644 --- a/src/tools/miri/cargo-miri/Cargo.lock +++ b/src/tools/miri/cargo-miri/Cargo.lock @@ -429,9 +429,9 @@ dependencies = [ [[package]] name = "rustc-build-sysroot" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb13874a0e55baf4ac3d49d38206aecb31a55b75d6c4d04fd850b53942c8cc8" +checksum = "dd41ead66a69880951b2f7df3139db401d44451b4da123344d27eaa791b89c95" dependencies = [ "anyhow", "rustc_version", diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml index 77cb1df8e74..64b56ea114e 100644 --- a/src/tools/miri/cargo-miri/Cargo.toml +++ b/src/tools/miri/cargo-miri/Cargo.toml @@ -18,7 +18,7 @@ directories = "6" rustc_version = "0.4" serde_json = "1.0.40" cargo_metadata = "0.21" -rustc-build-sysroot = "0.5.8" +rustc-build-sysroot = "0.5.10" # Enable some feature flags that dev-dependencies need but dependencies # do not. This makes `./miri install` after `./miri build` faster. diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index efb9053f69a..0716f4add9d 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -65,16 +65,6 @@ fn forward_patched_extern_arg(args: &mut impl Iterator<Item = String>, cmd: &mut } pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) { - // Check for version and help flags even when invoked as `cargo-miri`. - if has_arg_flag("--help") || has_arg_flag("-h") { - show_help(); - return; - } - if has_arg_flag("--version") || has_arg_flag("-V") { - show_version(); - return; - } - // Require a subcommand before any flags. // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. @@ -85,11 +75,36 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) { "setup" => MiriCommand::Setup, "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand), "clean" => MiriCommand::Clean, - _ => + _ => { + // Check for version and help flags. + if has_arg_flag("--help") || has_arg_flag("-h") { + show_help(); + return; + } + if has_arg_flag("--version") || has_arg_flag("-V") { + show_version(); + return; + } show_error!( "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, `clean`, and `setup`." - ), + ) + } }; + if has_arg_flag("--help") || has_arg_flag("-h") { + match subcommand { + MiriCommand::Forward(verb) => { + println!("`cargo miri {verb}` supports the same flags as `cargo {verb}`:\n"); + let mut cmd = cargo(); + cmd.arg(verb); + cmd.arg("--help"); + exec(cmd); + } + _ => { + show_help(); + return; + } + } + } let verbose = num_arg_flag("-v") + num_arg_flag("--verbose"); let quiet = has_arg_flag("-q") || has_arg_flag("--quiet"); diff --git a/src/tools/miri/doc/img/perfetto_aggregate_statistics.png b/src/tools/miri/doc/img/perfetto_aggregate_statistics.png new file mode 100644 index 00000000000..d4fd3826f47 --- /dev/null +++ b/src/tools/miri/doc/img/perfetto_aggregate_statistics.png Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_aggregate_statistics_sql.png b/src/tools/miri/doc/img/perfetto_aggregate_statistics_sql.png new file mode 100644 index 00000000000..bda92d3885a --- /dev/null +++ b/src/tools/miri/doc/img/perfetto_aggregate_statistics_sql.png Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_span.png b/src/tools/miri/doc/img/perfetto_span.png new file mode 100644 index 00000000000..1a7184f22ae --- /dev/null +++ b/src/tools/miri/doc/img/perfetto_span.png Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_subname_statistics.png b/src/tools/miri/doc/img/perfetto_subname_statistics.png new file mode 100644 index 00000000000..8c86b07e925 --- /dev/null +++ b/src/tools/miri/doc/img/perfetto_subname_statistics.png Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_timeline.png b/src/tools/miri/doc/img/perfetto_timeline.png new file mode 100644 index 00000000000..49f8a1fac1d --- /dev/null +++ b/src/tools/miri/doc/img/perfetto_timeline.png Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_visualize_argument_values.png b/src/tools/miri/doc/img/perfetto_visualize_argument_values.png new file mode 100644 index 00000000000..1dcbacaf9cb --- /dev/null +++ b/src/tools/miri/doc/img/perfetto_visualize_argument_values.png Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_visualize_argument_values_misbehaving.png b/src/tools/miri/doc/img/perfetto_visualize_argument_values_misbehaving.png new file mode 100644 index 00000000000..beeba8a4a3a --- /dev/null +++ b/src/tools/miri/doc/img/perfetto_visualize_argument_values_misbehaving.png Binary files differdiff --git a/src/tools/miri/doc/img/perfetto_visualize_argument_values_sql.png b/src/tools/miri/doc/img/perfetto_visualize_argument_values_sql.png new file mode 100644 index 00000000000..c7b163b0a57 --- /dev/null +++ b/src/tools/miri/doc/img/perfetto_visualize_argument_values_sql.png Binary files differdiff --git a/src/tools/miri/doc/tracing.md b/src/tools/miri/doc/tracing.md new file mode 100644 index 00000000000..d7114af947d --- /dev/null +++ b/src/tools/miri/doc/tracing.md @@ -0,0 +1,292 @@ +# Documentation for the tracing infrastructure in Miri + +Miri can be traced to understand how much time is spent in its various components (e.g. borrow tracker, data race checker, etc.). When tracing is enabled, running Miri will create a `.json` trace file that can be opened and analyzed in [Perfetto](https://ui.perfetto.dev/). For any questions regarding this documentation you may contact [Stypox](https://rust-lang.zulipchat.com/#narrow/dm/627563-Stypox) on Zulip. + +## Obtaining a trace file + +### From the Miri codebase + +All of the tracing functionality in Miri is gated by the `"tracing"` feature flag to ensure it does not create any overhead when unneeded. To compile Miri with this feature enabled, you can pass `--features=tracing` to `./miri`. Then, to make running Miri actually produce a trace file, you also need to set the `MIRI_TRACING` environment variable. For example: + +```sh +MIRI_TRACING=1 ./miri run --features=tracing ./tests/pass/hello.rs +``` + +### From the rustc codebase + +If you are building Miri from within the rustc tree, you need to enable the `"tracing"` feature by adding this line to `bootstrap.toml`: + +```toml +build.tool.miri.features = ["tracing"] +``` + +And then you could run the following: + +```sh +MIRI_TRACING=1 ./x.py run miri --stage 1 --args ./src/tools/miri/tests/pass/hello.rs +``` + +### The trace file + +After running Miri with tracing enabled you will get a `.json` trace file that contains a list of all events and spans that occurred throughout the execution. The file follows [this format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview). + +## Analyzing a trace file + +To analyze traces you can use [Perfetto UI](https://ui.perfetto.dev/), a trace analyzer made by Google that was originally a part of the Chrome browser. Just open Perfetto and drag and drop the `.json` file there. Official documentation for the controls in the UI can be found [here](https://perfetto.dev/docs/visualization/perfetto-ui). + +### The timeline + +You will see the boxes "Global Legacy Events" and "Process 1" on the left of the workspace: after clicking on either of them their timeline will expand and you will be able to zoom in and look at individual spans (and events). + +- "Process 1" contains tracing spans for the various components of Miri, all in a single timeline line (e.g. borrow tracker, data race checker, etc.) +- "Global Legacy Events" contains auxiliary spans on two separate lines that allow understanding what code is being executed at any point in time: + - "frame": what is the current stack frame in the interpreted program + - "step": what statement/terminator in the MIR of the interpreted program is being executed + +Spans are represented as colored boxes in the timeline, while instantaneous events are represented by tiny arrows. (Events exist because rustc and Miri also use the `tracing` crate for debug logging, and those logs turn into events in the trace.) + + + +### Span/event data + +You can click on a span or an event to get more information about it, including some arguments that were passed when the span/event was entered/fired. In the following screenshot you can see the details of a "layouting" span that was generated by the following line in Miri's code: + +```rust +let _trace = enter_trace_span!(M, layouting::fn_abi_of_instance, ?instance, ?extra_args); +``` + + + +### SQL tables + +Perfetto supports querying the span/event database using SQL queries (see the [docs](https://perfetto.dev/docs/analysis/perfetto-sql-syntax)). Just type `:` in the search bar at the top to enter SQL mode, and then you will be able to enter SQL queries there. The relevant SQL tables are: +- `slices`: contains all spans and events; events can be distinguished from spans since their `dur` is 0. Relevant columns are: + - `id`: a unique primary-key ID for the span (assigned by Perfetto, not present in the trace file) + - `ts` and `dur`: the beginning and duration of the span, in nanoseconds + - `name`: the name of the span + - `parent_id`: the parent span ID, or null if there is no parent (assigned by Perfetto based on the timing at which spans occur, i.e. two nested spans must be one the child of the other) + - `arg_set_id`: a foreign key into the table of arguments (1-to-N) +- `args`: contains all of the arguments of the various events/spans. Relevant columns are: + - `arg_set_id`: the key used to join the slices and args tables + - `key`: the name of the argument prepended with "args." + - `display_value`: the value of the argument + +Some useful queries are provided in the following sections. + +### Enhancing the timeline + +On the "Process 1" timeline line there are some spans with the same name, that are actually generated from different places in Miri's code. In those cases the span name indicates the component that was invoked (e.g. the data race checker), but not the specific function that was run. To inspect the specific function, we store a "subname" in an argument with the same name as the span, which unfortunately can be seen only after clicking on the span. + +To make it quicker to look at subnames, you can add a new timeline line that specifically shows the subnames for spans with a specific name. To do so: +1. select any span with the name you care about (call this name `$NAME`) +2. click on the dropdown highlighted in blue next on the argument with name `$NAME` (or `args.$NAME`) +3. click on "Visualize argument values" +4. a new timeline line will appear with only spans originally named `$NAME`, but now with the subname displayed instead + +The following screenshot shows the 4 steps for spans named "data_race": + + + +### Visualizing which "frame" or "step" is being executed + +Unfortunately the instructions in [Enhancing the timeline](#enhancing-the-timeline) only work well with spans under "Process 1", but misbehave with spans under "Global Legacy Events" (see the screenshot below). This might be a bug in Perfetto, but nevertheless a workaround is available: + +1. click on the search bar at the top and write `:` to enter SQL mode +2. copy-paste the following SQL, replace "SPAN_NAME" at the end with either "frame" or "step" (i.e. one of the two span names under "Global Legacy Events"), and press Enter to execute it: + ```sql + select slices.id, ts, dur, track_id, category, args.string_value as name, depth, stack_id, parent_stack_id, parent_id, slices.arg_set_id, thread_ts, thread_instruction_count, thread_instruction_delta, cat, slice_id + from slices inner join args using (arg_set_id) + where args.key = "args." || name and name = "SPAN_NAME" + ``` +3. at the top-right of the box at the bottom, click on "Show debug track" +4. press on "Show" in the popup that just appeared +5. a new debug track will appear with the names of steps or frames + +What the SQL does is to select only spans with the name "SPAN_NAME" and keep all of the span fields untouched, except for the name which is replaced with the subname. As explained in [Enhancing the timeline](#enhancing-the-timeline), remember that the subname is stored in an argument with the same name as the span. + + + +<img src="./img/perfetto_visualize_argument_values_misbehaving.png" width="300px"> + +### Compute aggregate statistics + +The simplest way to get aggregate statistics about a time range is to: + +1. select a time range by drag-clicking along a trace line +2. click on the "Current Selection" tab at the bottom if it's not already open +3. see various tables/visualizations of how much time is spent in each span by clicking on "Slices", "Pivot Table" or "Slice Flamegraph" + +Note that the numbers shown in the "Slices" and "Pivot Table" tabs also include nested spans, so they cannot be used to compute statistics such as "X% of time is spent in spans named Y" because two spans named Y might be nested and their duration would be counted twice. For such statistics use the method in [Compute aggregate statistics (enhanced)](#compute-aggregate-statistics-enhanced). + + + +### Compute aggregate statistics (enhanced) + +The following (long but not complicated) query can be used to find out how much time is spent in spans (grouped by their name). Only spans without a parent are considered towards the computations (see `where parent_id is null`): so for example if `validate_operand` in turn calls `layouting` (which generates a nested/child span), only the `validate_operand` statistics are increased. This query also excludes auxiliary spans (see `name != "frame" and name != "step"`). + +Note that this query does not allow selecting a time range, but that can be done by adding a condition, e.g. `ts + dur > MIN_T and ts < MAX_T` would match only spans that intersect the range `(MIN_T, MAX_T)`. Remember that the time unit is nanoseconds. + +```sql +select "TOTAL PROGRAM DURATION" as name, count(*), max(ts + dur) as "sum(dur)", 100.0 as "%", null as "min(dur)", null as "max(dur)", null as "avg(dur)", null as "stddev(dur)" +from slices + +union select "TOTAL OVER ALL SPANS (excluding events)" as name, count(*), sum(dur), cast(cast(sum(dur) as float) / (select max(ts + dur) from slices) * 1000 as int) / 10.0 as "%", min(dur), max(dur), cast(avg(dur) as int) as "avg(dur)", cast(sqrt(avg(dur*dur)-avg(dur)*avg(dur)) as int) as "stddev(dur)" +from slices +where parent_id is null and name != "frame" and name != "step" and dur > 0 + +union select name, count(*), sum(dur), cast(cast(sum(dur) as float) / (select max(ts + dur) from slices) * 1000 as int) / 10.0 as "%", min(dur), max(dur), cast(avg(dur) as int) as "avg(dur)", cast(sqrt(avg(dur*dur)-avg(dur)*avg(dur)) as int) as "stddev(dur)" +from slices +where parent_id is null and name != "frame" and name != "step" +group by name +order by sum(dur) desc, count(*) desc +``` + +This is the kind of table you would get out: + + + +### Statistics about subnames of a span + +Use the following SQL to see statistics about the subnames of spans with the same name (replace "SPAN_NAME" with the name of the span you want to see subname statistics of): + +```sql +select args.string_value as name, count(*), sum(dur), min(dur), max(dur), cast(avg(dur) as int) as "avg(dur)", cast(sqrt(avg(dur*dur)-avg(dur)*avg(dur)) as int) as "stddev(dur)" +from slices inner join args using (arg_set_id) +where args.key = "args." || name and name = "SPAN_NAME" +group by args.string_value +order by count(*) desc +``` + +For example, this is the table of how much time is spent in each borrow tracker function: + + + +### Finding long periods of time without any tracing + +The following SQL finds the longest periods of time where time is being spent, with the ability to click on IDs in the table of results to quickly reach the corresponding place. This can be useful to spot things that use up a significant amount of time but that are not yet covered by tracing calls. + +```sql +with ordered as ( + select s1.*, row_number() over (order by s1.ts) as rn + from slices as s1 + where s1.parent_id is null and s1.dur > 0 and s1.name != "frame" and s1.name != "step" +) +select a.ts+a.dur as ts, b.ts-a.ts-a.dur as dur, a.id, a.track_id, a.category, a.depth, a.stack_id, a.parent_stack_id, a.parent_id, a.arg_set_id, a.thread_ts, a.thread_instruction_count, a.thread_instruction_delta, a.cat, a.slice_id, "empty" as name +from ordered as a inner join ordered as b on a.rn=b.rn-1 +order by b.ts-a.ts-a.dur desc +``` + +### Saving Perfetto's state as a preset + +Unfortunately Perfetto does not seem to support saving the UI state as a preset that can be used to repeat the same analysis on multiple traces. You have to click through the various menus or run the various SQL queries every time to setup the UI as you want. + +## Adding new tracing calls to the code + +### The "tracing" feature + +Miri is highly interconnected with `rustc_const_eval`, and therefore collecting proper trace data about Miri also involves adding some tracing calls within `rustc_const_eval`'s codebase. As explained in [Obtaining a trace file](#obtaining-a-trace-file), tracing calls are disabled (and optimized out) when Miri's "tracing" feature is not enabled. However, while it is possible to check for the feature from Miri's codebase, it's not possible to do so from `rustc_const_eval` (since it's a separate crate, and it's even in a precompiled `.rlib` in case of out-of-tree builds). + +The solution to make it possible to check whether tracing is enabled at compile time even in `rustc_const_eval` was to add a function with this signature to the `Machine` trait: +```rust +fn enter_trace_span(span: impl FnOnce() -> tracing::Span) -> impl EnteredTraceSpan +``` + +where `EnteredTraceSpan` is just a marker trait implemented by `()` and `tracing::span::EnteredSpan`. This function returns `()` by default (without calling the `span` closure), except in `MiriMachine` where if tracing is enabled it will return `span().entered()`. + +The code in `rustc_const_eval` calls this function when it wants to do tracing, and the compiler will (hopefully) optimize out tracing calls when tracing is disabled. + +### The `enter_trace_span!()` macro + +To add tracing to a section of code in Miri or in `rustc_const_eval`, you can use the `enter_trace_span!()` macro, which takes care of the details explained in [The "tracing" feature](#the-tracing-feature). + +The `enter_trace_span!()` macro accepts the same syntax as `tracing::span!()` ([documentation](https://docs.rs/tracing/latest/tracing/#using-the-macros)) except for a few customizations, and returns an already entered trace span. The returned value is a drop guard that will exit the span when dropped, so **make sure to give it a proper scope** by storing it in a variable like this: + +```rust +let _trace = enter_trace_span!("My span"); +``` + +When calling this macro from `rustc_const_eval` you need to pass a type implementing the `Machine` trait as the first argument (since it will be used to call `Machine::enter_trace_span()`). This is usually available in various parts of `rustc_const_eval` under the name `M`, since most of `rustc_const_eval`'s code is `Machine`-agnostic. + +```rust +let _trace = enter_trace_span!("My span"); // from Miri +let _trace = enter_trace_span!(M, "My span"); // from rustc_const_eval +``` + +You can make sense of the syntaxes explained below also by looking at this Perfetto screenshot from [Span/event data](#spanevent-data). + + + +### Syntax accepted by `tracing::span!()` + +The full documentation for the `tracing::span!()` syntax can be found [here](https://docs.rs/tracing/latest/tracing/#using-the-macros) under "Using the Macros". A few possibly confusing syntaxes are listed here: +```rust +// logs a span named "hello" with a field named "arg" of value 42 (works only because +// 42 implements the tracing::Value trait, otherwise use one of the options below) +let _trace = enter_trace_span!(M, "hello", arg = 42); +// logs a field called "my_display_var" using the Display implementation +let _trace = enter_trace_span!(M, "hello", %my_display_var); +// logs a field called "my_debug_var" using the Debug implementation +let _trace = enter_trace_span!(M, "hello", ?my_debug_var); +``` + +### `NAME::SUBNAME` syntax + +In addition to the syntax accepted by `tracing::span!()`, the `enter_trace_span!()` macro optionally allows passing the span name (i.e. the first macro argument) in the form `NAME::SUBNAME` (without quotes) to indicate that the span has name "NAME" (usually the name of the component) and has an additional more specific name "SUBNAME" (usually the function name). The latter is passed to the tracing crate as a span field with the name "NAME". This allows not being distracted by subnames when looking at the trace in Perfetto, but when deeper introspection is needed within a component, it's still possible to view the subnames directly with a few steps (see [Enhancing the timeline](#enhancing-the-timeline)). +```rust +// for example, the first will expand to the second +let _trace = enter_trace_span!(M, borrow_tracker::on_stack_pop); +let _trace = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_pop"); +``` + +### `tracing_separate_thread` parameter + +Miri saves traces using the the `tracing_chrome` `tracing::Layer` so that they can be visualized in Perfetto. To instruct `tracing_chrome` to put some spans on a separate trace thread/line than other spans when viewed in Perfetto, you can pass `tracing_separate_thread = tracing::field::Empty` to the tracing macros. This is useful to separate out spans which just indicate the current step or program frame being processed by the interpreter. As explained in [The timeline](#the-timeline), those spans end up under the "Global Legacy Events" track. You should use a value of `tracing::field::Empty` so that other tracing layers (e.g. the logger) will ignore the `tracing_separate_thread` field. For example: +```rust +let _trace = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty); +``` + +### Executing something else when tracing is disabled + +The `EnteredTraceSpan` trait contains a `or_if_tracing_disabled()` function that you can use to e.g. log a line as an alternative to the tracing span for when tracing is disabled. For example: +```rust +let _trace = enter_trace_span!(M, step::eval_statement) + .or_if_tracing_disabled(|| tracing::info!("eval_statement")); +``` + +## Implementation details + +Here we explain how tracing is implemented internally. + +The events and spans generated throughout the codebase are collected by [the `tracing` crate](https://crates.io/crates/tracing), which then dispatches them to the code that writes to the trace file, but also to the logger if logging is enabled. + +### Choice of tracing library + +The crate that was chosen for collecting traces is [tracing](https://crates.io/crates/tracing), since: +- it is very well maintained +- it supports various different trace formats through plug-and-play `Layer`s (in Miri we are using `tracing_chrome` to export traces for perfetto, see [The `tracing_chrome` layer](#the-tracing_chrome-layer)) +- spans and events are collected with not just their name, but also file, line, module, and any number of custom arguments +- it was already used in Miri and rustc as a logging framework + +One major drawback of the tracing crate is, however, its big overhead. Entering and exiting a span takes on the order of 100ns, and many of Miri's spans are shorter than that, so their measurements are completely off and the program execution increases significantly. E.g. at the point of writing this documentation, enabling tracing makes Miri 5x slower. Note that this used to be even worse, see [Time measurements](#time-measurements). + +### The `tracing_chrome` layer + +Miri uses [tracing-chrome](https://github.com/thoren-d/tracing-chrome) as the `Layer` that collects spans and events from the tracing crate and saves them to a file that can be opened in Perfetto. Although the crate [is published](https://crates.io/crates/tracing-chrome) on crates.io, it was not possible to depend on it from Miri, because it would bring in a separate compilation of the `tracing` crate. This is because Miri does not directly depend on `tracing`, and instead uses rustc's version through rustc-private, and apparently cargo can't realize that the same library is being built again when rustc-private is involved. + +So the solution was to copy-paste [the only file](https://github.com/thoren-d/tracing-chrome/blob/develop/src/lib.rs) in tracing-chrome into Miri. Nevertheless, this gave the possibility to make some changes to tracing-chrome, which you can read about in documentation at the top of [the file](https://github.com/rust-lang/miri/blob/master/src/bin/log/tracing_chrome.rs) that was copied to Miri. + +### Time measurements + +tracing-chrome originally used `std::time::Instant` to measure time, however on some x86/x86_64 Linux systems it might be unbearably slow since the underlying system call (`clock_gettime`) would take ≈1.3µs. Read more [here](https://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/) about how the Linux kernel chooses the clock source. + +Therefore, on x86/x86_64 Linux systems with a CPU that has an invariant TSC counter, we read from that instead to measure time, which takes only ≈13ns. There are unfortunately a lot of caveats to this approach though, as explained [in the code](https://github.com/rust-lang/miri/blob/master/src/bin/log/tracing_chrome_instant.rs) and [in the PR](https://github.com/rust-lang/miri/pull/4524). The most impactful one is that: every thread spawned in Miri that wants to trace something (which requires measuring time) needs to pin itself to a single CPU core (using `sched_setaffinity`). + +## Other useful stuff + +### Making a flamegraph + +After compiling Miri, you can run the following command to make a flamegraph using Linux' `perf`. It can be useful to spot functions that use up a significant amount of time but that are not yet covered by tracing calls. + +```sh +perf record --call-graph dwarf -F 999 ./miri/target/debug/miri --edition 2021 --sysroot ~/.cache/miri ./tests/pass/hashmap.rs && perf script | inferno-collapse-perf | inferno-flamegraph > flamegraph.svg +``` diff --git a/src/tools/miri/etc/rust_analyzer_zed.json b/src/tools/miri/etc/rust_analyzer_zed.json new file mode 100644 index 00000000000..839914c8b68 --- /dev/null +++ b/src/tools/miri/etc/rust_analyzer_zed.json @@ -0,0 +1,41 @@ +{ + "lsp": { + "rust-analyzer": { + "initialization_options": { + "rustc": { + "source": "discover" + }, + "linkedProjects": [ + "./Cargo.toml", + "./cargo-miri/Cargo.toml", + "./genmc-sys/Cargo.toml", + "./miri-script/Cargo.toml" + ], + "check": { + "invocationStrategy": "once", + "overrideCommand": [ + "./miri", + "clippy", // make this `check` when working with a locally built rustc + "--message-format=json" + ] + }, + "cargo": { + "extraEnv": { + "MIRI_AUTO_OPS": "no", + "MIRI_IN_RA": "1" + }, + // Contrary to what the name suggests, this also affects proc macros. + "buildScripts": { + "invocationStrategy": "once", + "overrideCommand": [ + "./miri", + "check", + "--no-default-features", + "--message-format=json" + ] + } + } + } + } + } +} diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 59adc572eaa..d44488399f8 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -f605b57042ffeb320d7ae44490113a827139b766 +51ff895062ba60a7cba53f57af928c3fb7b0f2f4 diff --git a/src/tools/miri/src/bin/log/mod.rs b/src/tools/miri/src/bin/log/mod.rs index f3b2fdb5348..22f74dd46b5 100644 --- a/src/tools/miri/src/bin/log/mod.rs +++ b/src/tools/miri/src/bin/log/mod.rs @@ -1,2 +1,3 @@ pub mod setup; mod tracing_chrome; +mod tracing_chrome_instant; diff --git a/src/tools/miri/src/bin/log/tracing_chrome.rs b/src/tools/miri/src/bin/log/tracing_chrome.rs index 3379816550c..310887a13a5 100644 --- a/src/tools/miri/src/bin/log/tracing_chrome.rs +++ b/src/tools/miri/src/bin/log/tracing_chrome.rs @@ -7,12 +7,15 @@ //! (`git log -- path/to/tracing_chrome.rs`), but in summary: //! - the file attributes were changed and `extern crate` was added at the top //! - if a tracing span has a field called "tracing_separate_thread", it will be given a separate -//! span ID even in [TraceStyle::Threaded] mode, to make it appear on a separate line when viewing -//! the trace in <https://ui.perfetto.dev>. This is the syntax to trigger this behavior: +//! span ID even in [TraceStyle::Threaded] mode, to make it appear on a separate line when viewing +//! the trace in <https://ui.perfetto.dev>. This is the syntax to trigger this behavior: //! ```rust //! tracing::info_span!("my_span", tracing_separate_thread = tracing::field::Empty, /* ... */) //! ``` -//! - use i64 instead of u64 for the "id" in [ChromeLayer::get_root_id] to be compatible with Perfetto +//! - use i64 instead of u64 for the "id" in [ChromeLayer::get_root_id] to be compatible with +//! Perfetto +//! - use [ChromeLayer::with_elapsed_micros_subtracting_tracing] to make time measurements faster on +//! Linux x86/x86_64 and to subtract time spent tracing from the timestamps in the trace file //! //! Depending on the tracing-chrome crate from crates.io is unfortunately not possible, since it //! depends on `tracing_core` which conflicts with rustc_private's `tracing_core` (meaning it would @@ -50,9 +53,22 @@ use std::{ thread::JoinHandle, }; +use crate::log::tracing_chrome_instant::TracingChromeInstant; + +/// Contains thread-local data for threads that send tracing spans or events. +struct ThreadData { + /// A unique ID for this thread, will populate "tid" field in the output trace file. + tid: usize, + /// A clone of [ChromeLayer::out] to avoid the expensive operation of accessing a mutex + /// every time. This is used to send [Message]s to the thread that saves trace data to file. + out: Sender<Message>, + /// The instant in time this thread was started. All events happening on this thread will be + /// saved to the trace file with a timestamp (the "ts" field) measured relative to this instant. + start: TracingChromeInstant, +} + thread_local! { - static OUT: RefCell<Option<Sender<Message>>> = const { RefCell::new(None) }; - static TID: RefCell<Option<usize>> = const { RefCell::new(None) }; + static THREAD_DATA: RefCell<Option<ThreadData>> = const { RefCell::new(None) }; } type NameFn<S> = Box<dyn Fn(&EventOrSpan<'_, '_, S>) -> String + Send + Sync>; @@ -64,7 +80,6 @@ where S: Subscriber + for<'span> LookupSpan<'span> + Send + Sync, { out: Arc<Mutex<Sender<Message>>>, - start: std::time::Instant, max_tid: AtomicUsize, include_args: bool, include_locations: bool, @@ -323,7 +338,6 @@ where { fn new(mut builder: ChromeLayerBuilder<S>) -> (ChromeLayer<S>, FlushGuard) { let (tx, rx) = mpsc::channel(); - OUT.with(|val| val.replace(Some(tx.clone()))); let out_writer = builder .out_writer @@ -443,7 +457,6 @@ where }; let layer = ChromeLayer { out: Arc::new(Mutex::new(tx)), - start: std::time::Instant::now(), max_tid: AtomicUsize::new(0), name_fn: builder.name_fn.take(), cat_fn: builder.cat_fn.take(), @@ -456,22 +469,7 @@ where (layer, guard) } - fn get_tid(&self) -> (usize, bool) { - TID.with(|value| { - let tid = *value.borrow(); - match tid { - Some(tid) => (tid, false), - None => { - let tid = self.max_tid.fetch_add(1, Ordering::SeqCst); - value.replace(Some(tid)); - (tid, true) - } - } - }) - } - - fn get_callsite(&self, data: EventOrSpan<S>) -> Callsite { - let (tid, new_thread) = self.get_tid(); + fn get_callsite(&self, data: EventOrSpan<S>, tid: usize) -> Callsite { let name = self.name_fn.as_ref().map(|name_fn| name_fn(&data)); let target = self.cat_fn.as_ref().map(|cat_fn| cat_fn(&data)); let meta = match data { @@ -502,14 +500,6 @@ where (None, None) }; - if new_thread { - let name = match std::thread::current().name() { - Some(name) => name.to_owned(), - None => tid.to_string(), - }; - self.send_message(Message::NewThread(tid, name)); - } - Callsite { tid, name, @@ -548,31 +538,55 @@ where } } - fn enter_span(&self, span: SpanRef<S>, ts: f64) { - let callsite = self.get_callsite(EventOrSpan::Span(&span)); + fn enter_span(&self, span: SpanRef<S>, ts: f64, tid: usize, out: &Sender<Message>) { + let callsite = self.get_callsite(EventOrSpan::Span(&span), tid); let root_id = self.get_root_id(span); - self.send_message(Message::Enter(ts, callsite, root_id)); + let _ignored = out.send(Message::Enter(ts, callsite, root_id)); } - fn exit_span(&self, span: SpanRef<S>, ts: f64) { - let callsite = self.get_callsite(EventOrSpan::Span(&span)); + fn exit_span(&self, span: SpanRef<S>, ts: f64, tid: usize, out: &Sender<Message>) { + let callsite = self.get_callsite(EventOrSpan::Span(&span), tid); let root_id = self.get_root_id(span); - self.send_message(Message::Exit(ts, callsite, root_id)); + let _ignored = out.send(Message::Exit(ts, callsite, root_id)); } - fn get_ts(&self) -> f64 { - self.start.elapsed().as_nanos() as f64 / 1000.0 - } + /// Helper function that measures how much time is spent while executing `f` and accounts for it + /// in subsequent calls, with the aim to reduce biases in the data collected by `tracing_chrome` + /// by subtracting the time spent inside tracing functions from the timeline. This makes it so + /// that the time spent inside the `tracing_chrome` functions does not impact the timestamps + /// inside the trace file (i.e. `ts`), even if such functions are slow (e.g. because they need + /// to format arguments on the same thread those arguments are collected on, otherwise memory + /// safety would be broken). + /// + /// `f` is called with the microseconds elapsed since the current thread was started (**not** + /// since the program start!), with the current thread ID (i.e. `tid`), and with a [Sender] that + /// can be used to send a [Message] to the thread that collects [Message]s and saves them to the + /// trace file. + #[inline(always)] + fn with_elapsed_micros_subtracting_tracing(&self, f: impl Fn(f64, usize, &Sender<Message>)) { + THREAD_DATA.with(|value| { + let mut thread_data = value.borrow_mut(); + let (ThreadData { tid, out, start }, new_thread) = match thread_data.as_mut() { + Some(thread_data) => (thread_data, false), + None => { + let tid = self.max_tid.fetch_add(1, Ordering::SeqCst); + let out = self.out.lock().unwrap().clone(); + let start = TracingChromeInstant::setup_for_thread_and_start(tid); + *thread_data = Some(ThreadData { tid, out, start }); + (thread_data.as_mut().unwrap(), true) + } + }; - fn send_message(&self, message: Message) { - OUT.with(move |val| { - if val.borrow().is_some() { - let _ignored = val.borrow().as_ref().unwrap().send(message); - } else { - let out = self.out.lock().unwrap().clone(); - let _ignored = out.send(message); - val.replace(Some(out)); - } + start.with_elapsed_micros_subtracting_tracing(|ts| { + if new_thread { + let name = match std::thread::current().name() { + Some(name) => name.to_owned(), + None => tid.to_string(), + }; + let _ignored = out.send(Message::NewThread(*tid, name)); + } + f(ts, *tid, out); + }); }); } } @@ -586,52 +600,58 @@ where return; } - let ts = self.get_ts(); - self.enter_span(ctx.span(id).expect("Span not found."), ts); + self.with_elapsed_micros_subtracting_tracing(|ts, tid, out| { + self.enter_span(ctx.span(id).expect("Span not found."), ts, tid, out); + }); } fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) { if self.include_args { - let span = ctx.span(id).unwrap(); - let mut exts = span.extensions_mut(); + self.with_elapsed_micros_subtracting_tracing(|_, _, _| { + let span = ctx.span(id).unwrap(); + let mut exts = span.extensions_mut(); - let args = exts.get_mut::<ArgsWrapper>(); + let args = exts.get_mut::<ArgsWrapper>(); - if let Some(args) = args { - let args = Arc::make_mut(&mut args.args); - values.record(&mut JsonVisitor { object: args }); - } + if let Some(args) = args { + let args = Arc::make_mut(&mut args.args); + values.record(&mut JsonVisitor { object: args }); + } + }); } } fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) { - let ts = self.get_ts(); - let callsite = self.get_callsite(EventOrSpan::Event(event)); - self.send_message(Message::Event(ts, callsite)); + self.with_elapsed_micros_subtracting_tracing(|ts, tid, out| { + let callsite = self.get_callsite(EventOrSpan::Event(event), tid); + let _ignored = out.send(Message::Event(ts, callsite)); + }); } fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) { if let TraceStyle::Async = self.trace_style { return; } - let ts = self.get_ts(); - self.exit_span(ctx.span(id).expect("Span not found."), ts); + self.with_elapsed_micros_subtracting_tracing(|ts, tid, out| { + self.exit_span(ctx.span(id).expect("Span not found."), ts, tid, out); + }); } fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) { - if self.include_args { - let mut args = Object::new(); - attrs.record(&mut JsonVisitor { object: &mut args }); - ctx.span(id).unwrap().extensions_mut().insert(ArgsWrapper { - args: Arc::new(args), - }); - } - if let TraceStyle::Threaded = self.trace_style { - return; - } + self.with_elapsed_micros_subtracting_tracing(|ts, tid, out| { + if self.include_args { + let mut args = Object::new(); + attrs.record(&mut JsonVisitor { object: &mut args }); + ctx.span(id).unwrap().extensions_mut().insert(ArgsWrapper { + args: Arc::new(args), + }); + } + if let TraceStyle::Threaded = self.trace_style { + return; + } - let ts = self.get_ts(); - self.enter_span(ctx.span(id).expect("Span not found."), ts); + self.enter_span(ctx.span(id).expect("Span not found."), ts, tid, out); + }); } fn on_close(&self, id: span::Id, ctx: Context<'_, S>) { @@ -639,8 +659,9 @@ where return; } - let ts = self.get_ts(); - self.exit_span(ctx.span(&id).expect("Span not found."), ts); + self.with_elapsed_micros_subtracting_tracing(|ts, tid, out| { + self.exit_span(ctx.span(&id).expect("Span not found."), ts, tid, out); + }); } } diff --git a/src/tools/miri/src/bin/log/tracing_chrome_instant.rs b/src/tools/miri/src/bin/log/tracing_chrome_instant.rs new file mode 100644 index 00000000000..f400bc20a7b --- /dev/null +++ b/src/tools/miri/src/bin/log/tracing_chrome_instant.rs @@ -0,0 +1,183 @@ +//! Code in this class was in part inspired by +//! <https://github.com/tikv/minstant/blob/27c9ec5ec90b5b67113a748a4defee0d2519518c/src/tsc_now.rs>. +//! A useful resource is also +//! <https://www.pingcap.com/blog/how-we-trace-a-kv-database-with-less-than-5-percent-performance-impact/>, +//! although this file does not implement TSC synchronization but insteads pins threads to CPUs, +//! since the former is not reliable (i.e. it might lead to non-monotonic time measurements). +//! Another useful resource for future improvements might be measureme's time measurement utils: +//! <https://github.com/rust-lang/measureme/blob/master/measureme/src/counters.rs>. +//! Documentation about how the Linux kernel chooses a clock source can be found here: +//! <https://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/>. +#![cfg(feature = "tracing")] + +/// This alternative `TracingChromeInstant` implementation was made entirely to suit the needs of +/// [crate::log::tracing_chrome], and shouldn't be used for anything else. It featues two functions: +/// - [TracingChromeInstant::setup_for_thread_and_start], which sets up the current thread to do +/// proper time tracking and returns a point in time to use as "t=0", and +/// - [TracingChromeInstant::with_elapsed_micros_subtracting_tracing], which allows +/// obtaining how much time elapsed since [TracingChromeInstant::setup_for_thread_and_start] was +/// called while accounting for (and subtracting) the time spent inside tracing-related functions. +/// +/// This measures time using [std::time::Instant], except for x86/x86_64 Linux machines, where +/// [std::time::Instant] is too slow (~1.5us) and thus `rdtsc` is used instead (~5ns). +pub enum TracingChromeInstant { + WallTime { + /// The time at which this instant was created, shifted forward to account + /// for time spent in tracing functions as explained in + /// [TracingChromeInstant::with_elapsed_micros_subtracting_tracing]'s comments. + start_instant: std::time::Instant, + }, + #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] + Tsc { + /// The value in the TSC counter when this instant was created, shifted forward to account + /// for time spent in tracing functions as explained in + /// [TracingChromeInstant::with_elapsed_micros_subtracting_tracing]'s comments. + start_tsc: u64, + /// The period of the TSC counter in microseconds. + tsc_to_microseconds: f64, + }, +} + +impl TracingChromeInstant { + /// Can be thought of as the same as [std::time::Instant::now()], but also does some setup to + /// make TSC stable in case TSC is available. This is supposed to be called (at most) once per + /// thread since the thread setup takes a few milliseconds. + /// + /// WARNING: If TSC is available, `incremental_thread_id` is used to pick to which CPU to pin + /// the current thread. Thread IDs should be assigned contiguously starting from 0. Be aware + /// that the current thread will be restricted to one CPU for the rest of the execution! + pub fn setup_for_thread_and_start(incremental_thread_id: usize) -> TracingChromeInstant { + #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] + if *tsc::IS_TSC_AVAILABLE.get_or_init(tsc::is_tsc_available) { + // We need to lock this thread to a specific CPU, because CPUs' TSC timers might be out + // of sync. + tsc::set_cpu_affinity(incremental_thread_id); + + // Can only use tsc_to_microseconds() and rdtsc() after having set the CPU affinity! + // We compute tsc_to_microseconds anew for every new thread just in case some CPU core + // has a different TSC frequency. + let tsc_to_microseconds = tsc::tsc_to_microseconds(); + let start_tsc = tsc::rdtsc(); + return TracingChromeInstant::Tsc { start_tsc, tsc_to_microseconds }; + } + + let _ = incremental_thread_id; // otherwise we get a warning when the TSC branch is disabled + TracingChromeInstant::WallTime { start_instant: std::time::Instant::now() } + } + + /// Calls `f` with the time elapsed in microseconds since this [TracingChromeInstant] was built + /// by [TracingChromeInstant::setup_for_thread_and_start], while subtracting all time previously + /// spent executing other `f`s passed to this function. This behavior allows subtracting time + /// spent in functions that log tracing data (which `f` is supposed to be) from the tracing time + /// measurements. + /// + /// Note: microseconds are used as the time unit since that's what Chrome trace files should + /// contain, see the definition of the "ts" field in + /// <https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview>. + #[inline(always)] + pub fn with_elapsed_micros_subtracting_tracing(&mut self, f: impl Fn(f64)) { + match self { + TracingChromeInstant::WallTime { start_instant } => { + // Obtain the current time (before executing `f`). + let instant_before_f = std::time::Instant::now(); + + // Using the current time (`instant_before_f`) and the `start_instant` stored in + // `self`, calculate the elapsed time (in microseconds) since this instant was + // instantiated, accounting for any time that was previously spent executing `f`. + // The "accounting" part is not computed in this line, but is rather done by + // shifting forward the `start_instant` down below. + let ts = (instant_before_f - *start_instant).as_nanos() as f64 / 1000.0; + + // Run the function (supposedly a function internal to the tracing infrastructure). + f(ts); + + // Measure how much time was spent executing `f` and shift `start_instant` forward + // by that amount. This "removes" that time from the trace. + *start_instant += std::time::Instant::now() - instant_before_f; + } + + #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] + TracingChromeInstant::Tsc { start_tsc, tsc_to_microseconds } => { + // the comments above also apply here, since it's the same logic + let tsc_before_f = tsc::rdtsc(); + let ts = ((tsc_before_f - *start_tsc) as f64) * (*tsc_to_microseconds); + f(ts); + *start_tsc += tsc::rdtsc() - tsc_before_f; + } + } + } +} + +#[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] +mod tsc { + + pub static IS_TSC_AVAILABLE: std::sync::OnceLock<bool> = std::sync::OnceLock::new(); + + /// Reads the timestamp-counter register. Will give monotonic answers only when called from the + /// same thread, because the TSC of different CPUs might be out of sync. + #[inline(always)] + pub(super) fn rdtsc() -> u64 { + #[cfg(target_arch = "x86")] + use core::arch::x86::_rdtsc; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::_rdtsc; + + unsafe { _rdtsc() } + } + + /// Estimates the frequency of the TSC counter by waiting 10ms in a busy loop and + /// looking at how much the TSC increased in the meantime. + pub(super) fn tsc_to_microseconds() -> f64 { + const BUSY_WAIT: std::time::Duration = std::time::Duration::from_millis(10); + let tsc_start = rdtsc(); + let instant_start = std::time::Instant::now(); + while instant_start.elapsed() < BUSY_WAIT { + // `thread::sleep()` is not very precise at waking up the program at the right time, + // so use a busy loop instead. + core::hint::spin_loop(); + } + let tsc_end = rdtsc(); + (BUSY_WAIT.as_nanos() as f64) / 1000.0 / ((tsc_end - tsc_start) as f64) + } + + /// Checks whether the TSC counter is available and runs at a constant rate independently + /// of CPU frequency even across different power states of the CPU (i.e. checks for the + /// `invariant_tsc` CPUID flag). + pub(super) fn is_tsc_available() -> bool { + #[cfg(target_arch = "x86")] + use core::arch::x86::__cpuid; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::__cpuid; + + // implemented like https://docs.rs/raw-cpuid/latest/src/raw_cpuid/extended.rs.html#965-967 + const LEAF: u32 = 0x80000007; // this is the leaf for "advanced power management info" + let cpuid = unsafe { __cpuid(LEAF) }; + (cpuid.edx & (1 << 8)) != 0 // EDX bit 8 indicates invariant TSC + } + + /// Forces the current thread to run on a single CPU, which ensures the TSC counter is monotonic + /// (since TSCs of different CPUs might be out-of-sync). `incremental_thread_id` is used to pick + /// to which CPU to pin the current thread, and should be an incremental number that starts from + /// 0. + pub(super) fn set_cpu_affinity(incremental_thread_id: usize) { + let cpu_id = match std::thread::available_parallelism() { + Ok(available_parallelism) => incremental_thread_id % available_parallelism, + _ => panic!("Could not determine CPU count to properly set CPU affinity"), + }; + + let mut set = unsafe { std::mem::zeroed::<libc::cpu_set_t>() }; + unsafe { libc::CPU_SET(cpu_id, &mut set) }; + + // Set the current thread's core affinity. + if unsafe { + libc::sched_setaffinity( + 0, // Defaults to current thread + size_of::<libc::cpu_set_t>(), + &set as *const _, + ) + } != 0 + { + panic!("Could not set CPU affinity") + } + } +} diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index ae1b25f8857..9b0bee72aef 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -556,7 +556,11 @@ fn main() { } else if arg == "-Zmiri-deterministic-floats" { miri_config.float_nondet = false; } else if arg == "-Zmiri-no-extra-rounding-error" { - miri_config.float_rounding_error = false; + miri_config.float_rounding_error = miri::FloatRoundingErrorMode::None; + } else if arg == "-Zmiri-max-extra-rounding-error" { + miri_config.float_rounding_error = miri::FloatRoundingErrorMode::Max; + } else if arg == "-Zmiri-no-short-fd-operations" { + miri_config.short_fd_operations = false; } else if arg == "-Zmiri-strict-provenance" { miri_config.provenance_mode = ProvenanceMode::Strict; } else if arg == "-Zmiri-permissive-provenance" { diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index ad2a67160f4..bed65440dc9 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -125,81 +125,64 @@ pub struct NewPermission { /// Whether a read access should be performed on the non-frozen /// part on a retag. nonfreeze_access: bool, + /// Permission for memory outside the range. + outside_perm: Permission, /// Whether this pointer is part of the arguments of a function call. /// `protector` is `Some(_)` for all pointers marked `noalias`. protector: Option<ProtectorKind>, } impl<'tcx> NewPermission { - /// Determine NewPermission of the reference from the type of the pointee. - fn from_ref_ty( + /// Determine NewPermission of the reference/Box from the type of the pointee. + /// + /// A `ref_mutability` of `None` indicates a `Box` type. + fn new( pointee: Ty<'tcx>, - mutability: Mutability, - kind: RetagKind, + ref_mutability: Option<Mutability>, + retag_kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>, ) -> Option<Self> { let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env()); - let is_protected = kind == RetagKind::FnEntry; - let protector = is_protected.then_some(ProtectorKind::StrongProtector); - - Some(match mutability { - Mutability::Mut if ty_is_unpin => - NewPermission { - freeze_perm: Permission::new_reserved( - /* ty_is_freeze */ true, - is_protected, - ), - freeze_access: true, - nonfreeze_perm: Permission::new_reserved( - /* ty_is_freeze */ false, - is_protected, - ), - // If we have a mutable reference, then the non-frozen part will - // have state `ReservedIM` or `Reserved`, which can have an initial read access - // performed on it because you cannot have multiple mutable borrows. - nonfreeze_access: true, - protector, - }, - Mutability::Not => - NewPermission { - freeze_perm: Permission::new_frozen(), - freeze_access: true, - nonfreeze_perm: Permission::new_cell(), - // If it is a shared reference, then the non-frozen - // part will have state `Cell`, which should not have an initial access, - // as this can cause data races when using thread-safe data types like - // `Mutex<T>`. - nonfreeze_access: false, - protector, - }, - _ => return None, - }) - } + let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env()); + let is_protected = retag_kind == RetagKind::FnEntry; - /// Compute permission for `Box`-like type (`Box` always, and also `Unique` if enabled). - /// These pointers allow deallocation so need a different kind of protector not handled - /// by `from_ref_ty`. - fn from_unique_ty( - ty: Ty<'tcx>, - kind: RetagKind, - cx: &crate::MiriInterpCx<'tcx>, - ) -> Option<Self> { - let pointee = ty.builtin_deref(true).unwrap(); - pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| { - // Regular `Unpin` box, give it `noalias` but only a weak protector - // because it is valid to deallocate it within the function. - let is_protected = kind == RetagKind::FnEntry; - let protector = is_protected.then_some(ProtectorKind::WeakProtector); - NewPermission { - freeze_perm: Permission::new_reserved(/* ty_is_freeze */ true, is_protected), - freeze_access: true, - nonfreeze_perm: Permission::new_reserved( - /* ty_is_freeze */ false, - is_protected, - ), - nonfreeze_access: true, - protector, - } + if matches!(ref_mutability, Some(Mutability::Mut) | None if !ty_is_unpin) { + // Mutable reference / Box to pinning type: retagging is a NOP. + // FIXME: with `UnsafePinned`, this should do proper per-byte tracking. + return None; + } + + let freeze_perm = match ref_mutability { + // Shared references are frozen. + Some(Mutability::Not) => Permission::new_frozen(), + // Mutable references and Boxes are reserved. + _ => Permission::new_reserved_frz(), + }; + let nonfreeze_perm = match ref_mutability { + // Shared references are "transparent". + Some(Mutability::Not) => Permission::new_cell(), + // *Protected* mutable references and boxes are reserved without regarding for interior mutability. + _ if is_protected => Permission::new_reserved_frz(), + // Unprotected mutable references and boxes start in `ReservedIm`. + _ => Permission::new_reserved_im(), + }; + + // Everything except for `Cell` gets an initial access. + let initial_access = |perm: &Permission| !perm.is_cell(); + + Some(NewPermission { + freeze_perm, + freeze_access: initial_access(&freeze_perm), + nonfreeze_perm, + nonfreeze_access: initial_access(&nonfreeze_perm), + outside_perm: if ty_is_freeze { freeze_perm } else { nonfreeze_perm }, + protector: is_protected.then_some(if ref_mutability.is_some() { + // Strong protector for references + ProtectorKind::StrongProtector + } else { + // Weak protector for boxes + ProtectorKind::WeakProtector + }), }) } } @@ -313,30 +296,20 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let span = this.machine.current_span(); - // Store initial permissions and their corresponding range. - let mut perms_map: DedupRangeMap<LocationState> = DedupRangeMap::new( - ptr_size, - LocationState::new_accessed(Permission::new_disabled(), IdempotentForeignAccess::None), // this will be overwritten - ); - // Keep track of whether the node has any part that allows for interior mutability. - // FIXME: This misses `PhantomData<UnsafeCell<T>>` which could be considered a marker - // for requesting interior mutability. - let mut has_unsafe_cell = false; - // When adding a new node, the SIFA of its parents needs to be updated, potentially across // the entire memory range. For the parts that are being accessed below, the access itself - // trivially takes care of that. However, we have to do some more work to also deal with - // the parts that are not being accessed. Specifically what we do is that we - // call `update_last_accessed_after_retag` on the SIFA of the permission set for the part of - // memory outside `perm_map` -- so that part is definitely taken care of. The remaining concern - // is the part of memory that is in the range of `perms_map`, but not accessed below. - // There we have two cases: - // * If we do have an `UnsafeCell` (`has_unsafe_cell` becomes true), then the non-accessed part - // uses `nonfreeze_perm`, so the `nonfreeze_perm` initialized parts are also fine. We enforce - // the `freeze_perm` parts to be accessed, and thus everything is taken care of. - // * If there is no `UnsafeCell`, then `freeze_perm` is used everywhere (both inside and outside the initial range), - // and we update everything to have the `freeze_perm`'s SIFA, so there are no issues. (And this assert below is not - // actually needed in this case). + // trivially takes care of that. However, we have to do some more work to also deal with the + // parts that are not being accessed. Specifically what we do is that we call + // `update_last_accessed_after_retag` on the SIFA of the permission set for the part of + // memory outside `perm_map` -- so that part is definitely taken care of. The remaining + // concern is the part of memory that is in the range of `perms_map`, but not accessed + // below. There we have two cases: + // * If the type is `!Freeze`, then the non-accessed part uses `nonfreeze_perm`, so the + // `nonfreeze_perm` initialized parts are also fine. We enforce the `freeze_perm` parts to + // be accessed via the assert below, and thus everything is taken care of. + // * If the type is `Freeze`, then `freeze_perm` is used everywhere (both inside and outside + // the initial range), and we update everything to have the `freeze_perm`'s SIFA, so there + // are no issues. (And this assert below is not actually needed in this case). assert!(new_perm.freeze_access); let protected = new_perm.protector.is_some(); @@ -350,66 +323,48 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .get_tree_borrows_params() .precise_interior_mut; - let default_perm = if !precise_interior_mut { - // NOTE: Using `ty_is_freeze` doesn't give the same result as going through the range - // and computing `has_unsafe_cell`. This is because of zero-sized `UnsafeCell`, for which - // `has_unsafe_cell` is false, but `!ty_is_freeze` is true. - let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env()); - let (perm, access) = if ty_is_freeze { + // Compute initial "inside" permissions. + let loc_state = |frozen: bool| -> LocationState { + let (perm, access) = if frozen { (new_perm.freeze_perm, new_perm.freeze_access) } else { (new_perm.nonfreeze_perm, new_perm.nonfreeze_access) }; let sifa = perm.strongest_idempotent_foreign_access(protected); - let new_loc = if access { + if access { LocationState::new_accessed(perm, sifa) } else { LocationState::new_non_accessed(perm, sifa) - }; - - for (_loc_range, loc) in perms_map.iter_mut_all() { - *loc = new_loc; } - - perm + }; + let perms_map = if !precise_interior_mut { + // For `!Freeze` types, just pretend the entire thing is an `UnsafeCell`. + let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env()); + let state = loc_state(ty_is_freeze); + DedupRangeMap::new(ptr_size, state) } else { + // The initial state will be overwritten by the visitor below. + let mut perms_map: DedupRangeMap<LocationState> = DedupRangeMap::new( + ptr_size, + LocationState::new_accessed( + Permission::new_disabled(), + IdempotentForeignAccess::None, + ), + ); this.visit_freeze_sensitive(place, ptr_size, |range, frozen| { - has_unsafe_cell = has_unsafe_cell || !frozen; - - // We are only ever `Frozen` inside the frozen bits. - let (perm, access) = if frozen { - (new_perm.freeze_perm, new_perm.freeze_access) - } else { - (new_perm.nonfreeze_perm, new_perm.nonfreeze_access) - }; - let sifa = perm.strongest_idempotent_foreign_access(protected); - // NOTE: Currently, `access` is false if and only if `perm` is Cell, so this `if` - // doesn't not change whether any code is UB or not. We could just always use - // `new_accessed` and everything would stay the same. But that seems conceptually - // odd, so we keep the initial "accessed" bit of the `LocationState` in sync with whether - // a read access is performed below. - let new_loc = if access { - LocationState::new_accessed(perm, sifa) - } else { - LocationState::new_non_accessed(perm, sifa) - }; - - // Store initial permissions. + let state = loc_state(frozen); for (_loc_range, loc) in perms_map.iter_mut(range.start, range.size) { - *loc = new_loc; + *loc = state; } - interp_ok(()) })?; - - // Allow lazily writing to surrounding data if we found an `UnsafeCell`. - if has_unsafe_cell { new_perm.nonfreeze_perm } else { new_perm.freeze_perm } + perms_map }; let alloc_extra = this.get_alloc_extra(alloc_id)?; let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut(); - for (perm_range, perm) in perms_map.iter_mut_all() { + for (perm_range, perm) in perms_map.iter_all() { if perm.is_accessed() { // Some reborrows incur a read access to the parent. // Adjust range to be relative to allocation start (rather than to `place`). @@ -447,7 +402,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { orig_tag, new_tag, perms_map, - default_perm, + new_perm.outside_perm, protected, span, )?; @@ -514,7 +469,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let new_perm = match val.layout.ty.kind() { &ty::Ref(_, pointee, mutability) => - NewPermission::from_ref_ty(pointee, mutability, kind, this), + NewPermission::new(pointee, Some(mutability), kind, this), _ => None, }; if let Some(new_perm) = new_perm { @@ -571,8 +526,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn visit_box(&mut self, box_ty: Ty<'tcx>, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // Only boxes for the global allocator get any special treatment. if box_ty.is_box_global(*self.ecx.tcx) { + let pointee = place.layout.ty.builtin_deref(true).unwrap(); let new_perm = - NewPermission::from_unique_ty(place.layout.ty, self.kind, self.ecx); + NewPermission::new(pointee, /* not a ref */ None, self.kind, self.ecx); self.retag_ptr_inplace(place, new_perm)?; } interp_ok(()) @@ -591,7 +547,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match place.layout.ty.kind() { &ty::Ref(_, pointee, mutability) => { let new_perm = - NewPermission::from_ref_ty(pointee, mutability, self.kind, self.ecx); + NewPermission::new(pointee, Some(mutability), self.kind, self.ecx); self.retag_ptr_inplace(place, new_perm)?; } ty::RawPtr(_, _) => { @@ -643,14 +599,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // never be ReservedIM, the value of the `ty_is_freeze` // argument doesn't matter // (`ty_is_freeze || true` in `new_reserved` will always be `true`). - freeze_perm: Permission::new_reserved( - /* ty_is_freeze */ true, /* protected */ true, - ), + freeze_perm: Permission::new_reserved_frz(), freeze_access: true, - nonfreeze_perm: Permission::new_reserved( - /* ty_is_freeze */ false, /* protected */ true, - ), + nonfreeze_perm: Permission::new_reserved_frz(), nonfreeze_access: true, + outside_perm: Permission::new_reserved_frz(), protector: Some(ProtectorKind::StrongProtector), }; this.tb_retag_place(place, new_perm) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index 38863ca0734..390435e58d1 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -272,28 +272,15 @@ impl Permission { /// Default initial permission of a reborrowed mutable reference that is either /// protected or not interior mutable. - fn new_reserved_frz() -> Self { + pub fn new_reserved_frz() -> Self { Self { inner: ReservedFrz { conflicted: false } } } /// Default initial permission of an unprotected interior mutable reference. - fn new_reserved_im() -> Self { + pub fn new_reserved_im() -> Self { Self { inner: ReservedIM } } - /// Wrapper around `new_reserved_frz` and `new_reserved_im` that decides - /// which to call based on the interior mutability and the retag kind (whether there - /// is a protector is relevant because being protected takes priority over being - /// interior mutable) - pub fn new_reserved(ty_is_freeze: bool, protected: bool) -> Self { - // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`, - // interior mutability and protectors interact poorly. - // To eliminate the case of Protected Reserved IM we override interior mutability - // in the case of a protected reference: protected references are always considered - // "freeze" in their reservation phase. - if ty_is_freeze || protected { Self::new_reserved_frz() } else { Self::new_reserved_im() } - } - /// Default initial permission of a reborrowed shared reference. pub fn new_frozen() -> Self { Self { inner: Frozen } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs index bb3fc2d80b3..d9b3696e4f8 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs @@ -610,7 +610,7 @@ mod spurious_read { }, y: LocStateProt { state: LocationState::new_non_accessed( - Permission::new_reserved(/* freeze */ true, /* protected */ true), + Permission::new_reserved_frz(), IdempotentForeignAccess::default(), ), prot: true, diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 4c531a8d1f5..caed98f04f3 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -32,65 +32,6 @@ pub enum MiriEntryFnType { /// will hang the program. const MAIN_THREAD_YIELDS_AT_SHUTDOWN: u32 = 256; -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum AlignmentCheck { - /// Do not check alignment. - None, - /// Check alignment "symbolically", i.e., using only the requested alignment for an allocation and not its real base address. - Symbolic, - /// Check alignment on the actual physical integer address. - Int, -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum RejectOpWith { - /// Isolated op is rejected with an abort of the machine. - Abort, - - /// If not Abort, miri returns an error for an isolated op. - /// Following options determine if user should be warned about such error. - /// Do not print warning about rejected isolated op. - NoWarning, - - /// Print a warning about rejected isolated op, with backtrace. - Warning, - - /// Print a warning about rejected isolated op, without backtrace. - WarningWithoutBacktrace, -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum IsolatedOp { - /// Reject an op requiring communication with the host. By - /// default, miri rejects the op with an abort. If not, it returns - /// an error code, and prints a warning about it. Warning levels - /// are controlled by `RejectOpWith` enum. - Reject(RejectOpWith), - - /// Execute op requiring communication with the host, i.e. disable isolation. - Allow, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum BacktraceStyle { - /// Prints a terser backtrace which ideally only contains relevant information. - Short, - /// Prints a backtrace with all possible information. - Full, - /// Prints only the frame that the error occurs in. - Off, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ValidationMode { - /// Do not perform any kind of validation. - No, - /// Validate the interior of the value, but not things behind references. - Shallow, - /// Fully recursively validate references. - Deep, -} - /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { @@ -171,7 +112,9 @@ pub struct MiriConfig { /// Whether floating-point operations can behave non-deterministically. pub float_nondet: bool, /// Whether floating-point operations can have a non-deterministic rounding error. - pub float_rounding_error: bool, + pub float_rounding_error: FloatRoundingErrorMode, + /// Whether Miri artifically introduces short reads/writes on file descriptors. + pub short_fd_operations: bool, } impl Default for MiriConfig { @@ -213,7 +156,8 @@ impl Default for MiriConfig { fixed_scheduling: false, force_intrinsic_fallback: false, float_nondet: true, - float_rounding_error: true, + float_rounding_error: FloatRoundingErrorMode::Random, + short_fd_operations: true, } } } diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index b5e81460773..5e46768b0e6 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -10,7 +10,7 @@ use rustc_abi::Size; use rustc_apfloat::ieee::{IeeeFloat, Semantics}; use rustc_apfloat::{self, Float, Round}; use rustc_middle::mir; -use rustc_middle::ty::{self, FloatTy, ScalarInt}; +use rustc_middle::ty::{self, FloatTy}; use rustc_span::{Symbol, sym}; use self::atomic::EvalContextExt as _; @@ -230,7 +230,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = apply_random_float_error_ulp( this, res, - 2, // log2(4) + 4, ); // Clamp the result to the guaranteed range of this function according to the C standard, @@ -274,7 +274,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = apply_random_float_error_ulp( this, res, - 2, // log2(4) + 4, ); // Clamp the result to the guaranteed range of this function according to the C standard, @@ -336,9 +336,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - apply_random_float_error_ulp( - this, res, 2, // log2(4) - ) + apply_random_float_error_ulp(this, res, 4) }); let res = this.adjust_nan(res, &[f1, f2]); this.write_scalar(res, dest)?; @@ -354,9 +352,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - apply_random_float_error_ulp( - this, res, 2, // log2(4) - ) + apply_random_float_error_ulp(this, res, 4) }); let res = this.adjust_nan(res, &[f1, f2]); this.write_scalar(res, dest)?; @@ -373,9 +369,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - apply_random_float_error_ulp( - this, res, 2, // log2(4) - ) + apply_random_float_error_ulp(this, res, 4) }); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; @@ -391,9 +385,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - apply_random_float_error_ulp( - this, res, 2, // log2(4) - ) + apply_random_float_error_ulp(this, res, 4) }); let res = this.adjust_nan(res, &[f]); this.write_scalar(res, dest)?; @@ -448,7 +440,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Apply a relative error of 4ULP to simulate non-deterministic precision loss // due to optimizations. - let res = apply_random_float_error_to_imm(this, res, 2 /* log2(4) */)?; + let res = crate::math::apply_random_float_error_to_imm(this, res, 4)?; this.write_immediate(*res, dest)?; } @@ -486,31 +478,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } -/// Applies a random ULP floating point error to `val` and returns the new value. -/// So if you want an X ULP error, `ulp_exponent` should be log2(X). -/// -/// Will fail if `val` is not a floating point number. -fn apply_random_float_error_to_imm<'tcx>( - ecx: &mut MiriInterpCx<'tcx>, - val: ImmTy<'tcx>, - ulp_exponent: u32, -) -> InterpResult<'tcx, ImmTy<'tcx>> { - let scalar = val.to_scalar_int()?; - let res: ScalarInt = match val.layout.ty.kind() { - ty::Float(FloatTy::F16) => - apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(), - ty::Float(FloatTy::F32) => - apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(), - ty::Float(FloatTy::F64) => - apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(), - ty::Float(FloatTy::F128) => - apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(), - _ => bug!("intrinsic called with non-float input type"), - }; - - interp_ok(ImmTy::from_scalar_int(res, val.layout)) -} - /// For the intrinsics: /// - sinf32, sinf64 /// - cosf32, cosf64 diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 5ed6d6b346c..0856411b8e8 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -138,15 +138,14 @@ pub use crate::data_structures::mono_hash_map::MonoHashMap; pub use crate::diagnostics::{ EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error, }; -pub use crate::eval::{ - AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, MiriEntryFnType, RejectOpWith, - ValidationMode, create_ecx, eval_entry, -}; +pub use crate::eval::{MiriConfig, MiriEntryFnType, create_ecx, eval_entry}; pub use crate::helpers::{AccessKind, EvalContextExt as _, ToU64 as _, ToUsize as _}; pub use crate::intrinsics::EvalContextExt as _; pub use crate::machine::{ - AllocExtra, DynMachineCallback, FrameExtra, MachineCallback, MemoryKind, MiriInterpCx, - MiriInterpCxExt, MiriMachine, MiriMemoryKind, PrimitiveLayouts, Provenance, ProvenanceExtra, + AlignmentCheck, AllocExtra, BacktraceStyle, DynMachineCallback, FloatRoundingErrorMode, + FrameExtra, IsolatedOp, MachineCallback, MemoryKind, MiriInterpCx, MiriInterpCxExt, + MiriMachine, MiriMemoryKind, PrimitiveLayouts, Provenance, ProvenanceExtra, RejectOpWith, + ValidationMode, }; pub use crate::operator::EvalContextExt as _; pub use crate::provenance_gc::{EvalContextExt as _, LiveAllocs, VisitProvenance, VisitWith}; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 0b2ce900414..e4540fb9bc5 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -49,6 +49,75 @@ pub const SIGRTMAX: i32 = 42; /// base address for each evaluation would produce unbounded memory usage. const ADDRS_PER_ANON_GLOBAL: usize = 32; +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum AlignmentCheck { + /// Do not check alignment. + None, + /// Check alignment "symbolically", i.e., using only the requested alignment for an allocation and not its real base address. + Symbolic, + /// Check alignment on the actual physical integer address. + Int, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum RejectOpWith { + /// Isolated op is rejected with an abort of the machine. + Abort, + + /// If not Abort, miri returns an error for an isolated op. + /// Following options determine if user should be warned about such error. + /// Do not print warning about rejected isolated op. + NoWarning, + + /// Print a warning about rejected isolated op, with backtrace. + Warning, + + /// Print a warning about rejected isolated op, without backtrace. + WarningWithoutBacktrace, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum IsolatedOp { + /// Reject an op requiring communication with the host. By + /// default, miri rejects the op with an abort. If not, it returns + /// an error code, and prints a warning about it. Warning levels + /// are controlled by `RejectOpWith` enum. + Reject(RejectOpWith), + + /// Execute op requiring communication with the host, i.e. disable isolation. + Allow, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum BacktraceStyle { + /// Prints a terser backtrace which ideally only contains relevant information. + Short, + /// Prints a backtrace with all possible information. + Full, + /// Prints only the frame that the error occurs in. + Off, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ValidationMode { + /// Do not perform any kind of validation. + No, + /// Validate the interior of the value, but not things behind references. + Shallow, + /// Fully recursively validate references. + Deep, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum FloatRoundingErrorMode { + /// Apply a random error (the default). + Random, + /// Don't apply any error. + None, + /// Always apply the maximum error (with a random sign). + Max, +} + /// Extra data stored with each stack frame pub struct FrameExtra<'tcx> { /// Extra data for the Borrow Tracker. @@ -599,7 +668,10 @@ pub struct MiriMachine<'tcx> { /// Whether floating-point operations can behave non-deterministically. pub float_nondet: bool, /// Whether floating-point operations can have a non-deterministic rounding error. - pub float_rounding_error: bool, + pub float_rounding_error: FloatRoundingErrorMode, + + /// Whether Miri artifically introduces short reads/writes on file descriptors. + pub short_fd_operations: bool, } impl<'tcx> MiriMachine<'tcx> { @@ -761,6 +833,7 @@ impl<'tcx> MiriMachine<'tcx> { force_intrinsic_fallback: config.force_intrinsic_fallback, float_nondet: config.float_nondet, float_rounding_error: config.float_rounding_error, + short_fd_operations: config.short_fd_operations, } } @@ -937,6 +1010,7 @@ impl VisitProvenance for MiriMachine<'_> { force_intrinsic_fallback: _, float_nondet: _, float_rounding_error: _, + short_fd_operations: _, } = self; threads.visit_provenance(visit); @@ -1077,7 +1151,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { .target_features .iter() .filter(|&feature| { - feature.kind != TargetFeatureKind::Implied && !ecx.tcx.sess.target_features.contains(&feature.name) + feature.kind != TargetFeatureKind::Implied + && !ecx.tcx.sess.target_features.contains(&feature.name) }) .fold(String::new(), |mut s, feature| { if !s.is_empty() { @@ -1208,7 +1283,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx: &mut InterpCx<'tcx, Self>, val: ImmTy<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx>> { - crate::math::apply_random_float_error_to_imm(ecx, val, 2 /* log2(4) */) + crate::math::apply_random_float_error_to_imm(ecx, val, 4) } #[inline(always)] diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index e9e5a1070c9..6427f3ca6e9 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -6,67 +6,99 @@ use rustc_middle::ty::{self, FloatTy, ScalarInt}; use crate::*; /// Disturbes a floating-point result by a relative error in the range (-2^scale, 2^scale). -/// -/// For a 2^N ULP error, you can use an `err_scale` of `-(F::PRECISION - 1 - N)`. -/// In other words, a 1 ULP (absolute) error is the same as a `2^-(F::PRECISION-1)` relative error. -/// (Subtracting 1 compensates for the integer bit.) pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>( ecx: &mut crate::MiriInterpCx<'_>, val: F, err_scale: i32, ) -> F { - if !ecx.machine.float_nondet || !ecx.machine.float_rounding_error { + if !ecx.machine.float_nondet + || matches!(ecx.machine.float_rounding_error, FloatRoundingErrorMode::None) + // relative errors don't do anything to zeros... avoid messing up the sign + || val.is_zero() + // The logic below makes no sense if the input is already non-finite. + || !val.is_finite() + { return val; } - let rng = ecx.machine.rng.get_mut(); + // Generate a random integer in the range [0, 2^PREC). // (When read as binary, the position of the first `1` determines the exponent, // and the remaining bits fill the mantissa. `PREC` is one plus the size of the mantissa, // so this all works out.) - let r = F::from_u128(rng.random_range(0..(1 << F::PRECISION))).value; + let r = F::from_u128(match ecx.machine.float_rounding_error { + FloatRoundingErrorMode::Random => rng.random_range(0..(1 << F::PRECISION)), + FloatRoundingErrorMode::Max => (1 << F::PRECISION) - 1, // force max error + FloatRoundingErrorMode::None => unreachable!(), + }) + .value; // Multiply this with 2^(scale - PREC). The result is between 0 and // 2^PREC * 2^(scale - PREC) = 2^scale. let err = r.scalbn(err_scale.strict_sub(F::PRECISION.try_into().unwrap())); // give it a random sign let err = if rng.random() { -err } else { err }; - // multiple the value with (1+err) - (val * (F::from_u128(1).value + err).value).value + // Compute `val*(1+err)`, distributed out as `val + val*err` to avoid the imprecise addition + // error being amplified by multiplication. + (val + (val * err).value).value } -/// [`apply_random_float_error`] gives instructions to apply a 2^N ULP error. -/// This function implements these instructions such that applying a 2^N ULP error is less error prone. -/// So for a 2^N ULP error, you would pass N as the `ulp_exponent` argument. +/// Applies an error of `[-N, +N]` ULP to the given value. pub(crate) fn apply_random_float_error_ulp<F: rustc_apfloat::Float>( ecx: &mut crate::MiriInterpCx<'_>, val: F, - ulp_exponent: u32, + max_error: u32, ) -> F { - let n = i32::try_from(ulp_exponent) - .expect("`err_scale_for_ulp`: exponent is too large to create an error scale"); - // we know this fits - let prec = i32::try_from(F::PRECISION).unwrap(); - let err_scale = -(prec - n - 1); - apply_random_float_error(ecx, val, err_scale) + // We could try to be clever and reuse `apply_random_float_error`, but that is hard to get right + // (see <https://github.com/rust-lang/miri/pull/4558#discussion_r2316838085> for why) so we + // implement the logic directly instead. + if !ecx.machine.float_nondet + || matches!(ecx.machine.float_rounding_error, FloatRoundingErrorMode::None) + // FIXME: also disturb zeros? That requires a lot more cases in `fixed_float_value` + // and might make the std test suite quite unhappy. + || val.is_zero() + // The logic below makes no sense if the input is already non-finite. + || !val.is_finite() + { + return val; + } + let rng = ecx.machine.rng.get_mut(); + + let max_error = i64::from(max_error); + let error = match ecx.machine.float_rounding_error { + FloatRoundingErrorMode::Random => rng.random_range(-max_error..=max_error), + FloatRoundingErrorMode::Max => + if rng.random() { + max_error + } else { + -max_error + }, + FloatRoundingErrorMode::None => unreachable!(), + }; + // If upwards ULP and downwards ULP differ, we take the average. + let ulp = (((val.next_up().value - val).value + (val - val.next_down().value).value).value + / F::from_u128(2).value) + .value; + // Shift the value by N times the ULP + (val + (ulp * F::from_i128(error.into()).value).value).value } -/// Applies a random 16ULP floating point error to `val` and returns the new value. +/// Applies an error of `[-N, +N]` ULP to the given value. /// Will fail if `val` is not a floating point number. pub(crate) fn apply_random_float_error_to_imm<'tcx>( ecx: &mut MiriInterpCx<'tcx>, val: ImmTy<'tcx>, - ulp_exponent: u32, + max_error: u32, ) -> InterpResult<'tcx, ImmTy<'tcx>> { let scalar = val.to_scalar_int()?; let res: ScalarInt = match val.layout.ty.kind() { ty::Float(FloatTy::F16) => - apply_random_float_error_ulp(ecx, scalar.to_f16(), ulp_exponent).into(), + apply_random_float_error_ulp(ecx, scalar.to_f16(), max_error).into(), ty::Float(FloatTy::F32) => - apply_random_float_error_ulp(ecx, scalar.to_f32(), ulp_exponent).into(), + apply_random_float_error_ulp(ecx, scalar.to_f32(), max_error).into(), ty::Float(FloatTy::F64) => - apply_random_float_error_ulp(ecx, scalar.to_f64(), ulp_exponent).into(), + apply_random_float_error_ulp(ecx, scalar.to_f64(), max_error).into(), ty::Float(FloatTy::F128) => - apply_random_float_error_ulp(ecx, scalar.to_f128(), ulp_exponent).into(), + apply_random_float_error_ulp(ecx, scalar.to_f128(), max_error).into(), _ => bug!("intrinsic called with non-float input type"), }; diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs index 0d4642c6ad0..8c29cb040b5 100644 --- a/src/tools/miri/src/shims/files.rs +++ b/src/tools/miri/src/shims/files.rs @@ -168,8 +168,9 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt { } /// Determines whether this FD non-deterministically has its reads and writes shortened. - fn nondet_short_accesses(&self) -> bool { - true + fn short_fd_operations(&self) -> bool { + // We only enable this for FD kinds where we think short accesses gain useful test coverage. + false } /// Seeks to the given offset (which can be relative to the beginning, end, or current position). @@ -395,6 +396,13 @@ impl FileDescription for FileHandle { communicate_allowed && self.file.is_terminal() } + fn short_fd_operations(&self) -> bool { + // While short accesses on file-backed FDs are very rare (at least for sufficiently small + // accesses), they can realistically happen when a signal interrupts the syscall. + // FIXME: we should return `false` if this is a named pipe... + true + } + fn as_unix<'tcx>(&self, ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription { assert!( ecx.target_os_is_unix(), diff --git a/src/tools/miri/src/shims/native_lib/ffi.rs b/src/tools/miri/src/shims/native_lib/ffi.rs new file mode 100644 index 00000000000..0badf22bb76 --- /dev/null +++ b/src/tools/miri/src/shims/native_lib/ffi.rs @@ -0,0 +1,46 @@ +//! Support code for dealing with libffi. + +use libffi::low::CodePtr; +use libffi::middle::{Arg as ArgPtr, Cif, Type as FfiType}; + +/// Perform the actual FFI call. +/// +/// # Safety +/// +/// The safety invariants of the foreign function being called must be upheld (if any). +pub unsafe fn call<R: libffi::high::CType>(fun: CodePtr, args: &mut [OwnedArg]) -> R { + let arg_ptrs: Vec<_> = args.iter().map(|arg| arg.ptr()).collect(); + let cif = Cif::new(args.iter_mut().map(|arg| arg.ty.take().unwrap()), R::reify().into_middle()); + // SAFETY: Caller upholds that the function is safe to call, and since we + // were passed a slice reference we know the `OwnedArg`s won't have been + // dropped by this point. + unsafe { cif.call(fun, &arg_ptrs) } +} + +/// An argument for an FFI call. +#[derive(Debug, Clone)] +pub struct OwnedArg { + /// The type descriptor for this argument. + ty: Option<FfiType>, + /// Corresponding bytes for the value. + bytes: Box<[u8]>, +} + +impl OwnedArg { + /// Instantiates an argument from a type descriptor and bytes. + pub fn new(ty: FfiType, bytes: Box<[u8]>) -> Self { + Self { ty: Some(ty), bytes } + } + + /// Creates a libffi argument pointer pointing to this argument's bytes. + /// NB: Since `libffi::middle::Arg` ignores the lifetime of the reference + /// it's derived from, it is up to the caller to ensure the `OwnedArg` is + /// not dropped before unsafely calling `libffi::middle::Cif::call()`! + fn ptr(&self) -> ArgPtr { + // FIXME: Using `&self.bytes[0]` to reference the whole array is + // definitely unsound under SB, but we're waiting on + // https://github.com/libffi-rs/libffi-rs/commit/112a37b3b6ffb35bd75241fbcc580de40ba74a73 + // to land in a release so that we don't need to do this. + ArgPtr::new(&self.bytes[0]) + } +} diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 74b9b704fea..da8f785e373 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -2,14 +2,15 @@ use std::ops::Deref; -use libffi::high::call as ffi; use libffi::low::CodePtr; -use rustc_abi::{BackendRepr, HasDataLayout, Size}; -use rustc_middle::mir::interpret::Pointer; -use rustc_middle::ty::{self as ty, IntTy, UintTy}; +use libffi::middle::Type as FfiType; +use rustc_abi::{HasDataLayout, Size}; +use rustc_middle::ty::{self as ty, IntTy, Ty, UintTy}; use rustc_span::Symbol; use serde::{Deserialize, Serialize}; +mod ffi; + #[cfg_attr( not(all( target_os = "linux", @@ -20,6 +21,7 @@ use serde::{Deserialize, Serialize}; )] pub mod trace; +use self::ffi::OwnedArg; use crate::*; /// The final results of an FFI trace, containing every relevant event detected @@ -70,12 +72,12 @@ impl AccessRange { impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Call native host function and return the output as an immediate. - fn call_native_with_args<'a>( + fn call_native_with_args( &mut self, link_name: Symbol, dest: &MPlaceTy<'tcx>, - ptr: CodePtr, - libffi_args: Vec<libffi::high::Arg<'a>>, + fun: CodePtr, + libffi_args: &mut [OwnedArg], ) -> InterpResult<'tcx, (crate::ImmTy<'tcx>, Option<MemEvents>)> { let this = self.eval_context_mut(); #[cfg(target_os = "linux")] @@ -93,55 +95,55 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Unsafe because of the call to native code. // Because this is calling a C function it is not necessarily sound, // but there is no way around this and we've checked as much as we can. - let x = unsafe { ffi::call::<i8>(ptr, libffi_args.as_slice()) }; + let x = unsafe { ffi::call::<i8>(fun, libffi_args) }; Scalar::from_i8(x) } ty::Int(IntTy::I16) => { - let x = unsafe { ffi::call::<i16>(ptr, libffi_args.as_slice()) }; + let x = unsafe { ffi::call::<i16>(fun, libffi_args) }; Scalar::from_i16(x) } ty::Int(IntTy::I32) => { - let x = unsafe { ffi::call::<i32>(ptr, libffi_args.as_slice()) }; + let x = unsafe { ffi::call::<i32>(fun, libffi_args) }; Scalar::from_i32(x) } ty::Int(IntTy::I64) => { - let x = unsafe { ffi::call::<i64>(ptr, libffi_args.as_slice()) }; + let x = unsafe { ffi::call::<i64>(fun, libffi_args) }; Scalar::from_i64(x) } ty::Int(IntTy::Isize) => { - let x = unsafe { ffi::call::<isize>(ptr, libffi_args.as_slice()) }; + let x = unsafe { ffi::call::<isize>(fun, libffi_args) }; Scalar::from_target_isize(x.try_into().unwrap(), this) } // uints ty::Uint(UintTy::U8) => { - let x = unsafe { ffi::call::<u8>(ptr, libffi_args.as_slice()) }; + let x = unsafe { ffi::call::<u8>(fun, libffi_args) }; Scalar::from_u8(x) } ty::Uint(UintTy::U16) => { - let x = unsafe { ffi::call::<u16>(ptr, libffi_args.as_slice()) }; + let x = unsafe { ffi::call::<u16>(fun, libffi_args) }; Scalar::from_u16(x) } ty::Uint(UintTy::U32) => { - let x = unsafe { ffi::call::<u32>(ptr, libffi_args.as_slice()) }; + let x = unsafe { ffi::call::<u32>(fun, libffi_args) }; Scalar::from_u32(x) } ty::Uint(UintTy::U64) => { - let x = unsafe { ffi::call::<u64>(ptr, libffi_args.as_slice()) }; + let x = unsafe { ffi::call::<u64>(fun, libffi_args) }; Scalar::from_u64(x) } ty::Uint(UintTy::Usize) => { - let x = unsafe { ffi::call::<usize>(ptr, libffi_args.as_slice()) }; + let x = unsafe { ffi::call::<usize>(fun, libffi_args) }; Scalar::from_target_usize(x.try_into().unwrap(), this) } // Functions with no declared return type (i.e., the default return) // have the output_type `Tuple([])`. ty::Tuple(t_list) if (*t_list).deref().is_empty() => { - unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) }; + unsafe { ffi::call::<()>(fun, libffi_args) }; return interp_ok(ImmTy::uninit(dest.layout)); } ty::RawPtr(..) => { - let x = unsafe { ffi::call::<*const ()>(ptr, libffi_args.as_slice()) }; - let ptr = Pointer::new(Provenance::Wildcard, Size::from_bytes(x.addr())); + let x = unsafe { ffi::call::<*const ()>(fun, libffi_args) }; + let ptr = StrictPointer::new(Provenance::Wildcard, Size::from_bytes(x.addr())); Scalar::from_pointer(ptr, this) } _ => @@ -267,6 +269,150 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(()) } + + /// Extract the value from the result of reading an operand from the machine + /// and convert it to a `OwnedArg`. + fn op_to_ffi_arg(&self, v: &OpTy<'tcx>, tracing: bool) -> InterpResult<'tcx, OwnedArg> { + let this = self.eval_context_ref(); + + // This should go first so that we emit unsupported before doing a bunch + // of extra work for types that aren't supported yet. + let ty = this.ty_to_ffitype(v.layout.ty)?; + + // Helper to print a warning when a pointer is shared with the native code. + let expose = |prov: Provenance| -> InterpResult<'tcx> { + // The first time this happens, print a warning. + if !this.machine.native_call_mem_warned.replace(true) { + // Newly set, so first time we get here. + this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem { tracing }); + } + + this.expose_provenance(prov)?; + interp_ok(()) + }; + + // Compute the byte-level representation of the argument. If there's a pointer in there, we + // expose it inside the AM. Later in `visit_reachable_allocs`, the "meta"-level provenance + // for accessing the pointee gets exposed; this is crucial to justify the C code effectively + // casting the integer in `byte` to a pointer and using that. + let bytes = match v.as_mplace_or_imm() { + either::Either::Left(mplace) => { + // Get the alloc id corresponding to this mplace, alongside + // a pointer that's offset to point to this particular + // mplace (not one at the base addr of the allocation). + let sz = mplace.layout.size.bytes_usize(); + if sz == 0 { + throw_unsup_format!("attempting to pass a ZST over FFI"); + } + let (id, ofs, _) = this.ptr_get_alloc_id(mplace.ptr(), sz.try_into().unwrap())?; + let ofs = ofs.bytes_usize(); + let range = ofs..ofs.strict_add(sz); + // Expose all provenances in the allocation within the byte range of the struct, if + // any. These pointers are being directly passed to native code by-value. + let alloc = this.get_alloc_raw(id)?; + for prov in alloc.provenance().get_range(this, range.clone().into()) { + expose(prov)?; + } + // Read the bytes that make up this argument. We cannot use the normal getter as + // those would fail if any part of the argument is uninitialized. Native code + // is kind of outside the interpreter, after all... + Box::from(alloc.inspect_with_uninit_and_ptr_outside_interpreter(range)) + } + either::Either::Right(imm) => { + let mut bytes: Box<[u8]> = vec![0; imm.layout.size.bytes_usize()].into(); + + // A little helper to write scalars to our byte array. + let mut write_scalar = |this: &MiriInterpCx<'tcx>, sc: Scalar, pos: usize| { + // If a scalar is a pointer, then expose its provenance. + if let interpret::Scalar::Ptr(p, _) = sc { + expose(p.provenance)?; + } + write_target_uint( + this.data_layout().endian, + &mut bytes[pos..][..sc.size().bytes_usize()], + sc.to_scalar_int()?.to_bits_unchecked(), + ) + .unwrap(); + interp_ok(()) + }; + + // Write the scalar into the `bytes` buffer. + match *imm { + Immediate::Scalar(sc) => write_scalar(this, sc, 0)?, + Immediate::ScalarPair(sc_first, sc_second) => { + // The first scalar has an offset of zero; compute the offset of the 2nd. + let ofs_second = { + let rustc_abi::BackendRepr::ScalarPair(a, b) = imm.layout.backend_repr + else { + span_bug!( + this.cur_span(), + "op_to_ffi_arg: invalid scalar pair layout: {:#?}", + imm.layout + ) + }; + a.size(this).align_to(b.align(this).abi).bytes_usize() + }; + + write_scalar(this, sc_first, 0)?; + write_scalar(this, sc_second, ofs_second)?; + } + Immediate::Uninit => { + // Nothing to write. + } + } + + bytes + } + }; + interp_ok(OwnedArg::new(ty, bytes)) + } + + /// Parses an ADT to construct the matching libffi type. + fn adt_to_ffitype( + &self, + orig_ty: Ty<'_>, + adt_def: ty::AdtDef<'tcx>, + args: &'tcx ty::List<ty::GenericArg<'tcx>>, + ) -> InterpResult<'tcx, FfiType> { + // TODO: Certain non-C reprs should be okay also. + if !adt_def.repr().c() { + throw_unsup_format!("passing a non-#[repr(C)] struct over FFI: {orig_ty}") + } + // TODO: unions, etc. + if !adt_def.is_struct() { + throw_unsup_format!( + "unsupported argument type for native call: {orig_ty} is an enum or union" + ); + } + + let this = self.eval_context_ref(); + let mut fields = vec![]; + for field in &adt_def.non_enum_variant().fields { + fields.push(this.ty_to_ffitype(field.ty(*this.tcx, args))?); + } + + interp_ok(FfiType::structure(fields)) + } + + /// Gets the matching libffi type for a given Ty. + fn ty_to_ffitype(&self, ty: Ty<'tcx>) -> InterpResult<'tcx, FfiType> { + interp_ok(match ty.kind() { + ty::Int(IntTy::I8) => FfiType::i8(), + ty::Int(IntTy::I16) => FfiType::i16(), + ty::Int(IntTy::I32) => FfiType::i32(), + ty::Int(IntTy::I64) => FfiType::i64(), + ty::Int(IntTy::Isize) => FfiType::isize(), + // the uints + ty::Uint(UintTy::U8) => FfiType::u8(), + ty::Uint(UintTy::U16) => FfiType::u16(), + ty::Uint(UintTy::U32) => FfiType::u32(), + ty::Uint(UintTy::U64) => FfiType::u64(), + ty::Uint(UintTy::Usize) => FfiType::usize(), + ty::RawPtr(..) => FfiType::pointer(), + ty::Adt(adt_def, args) => self.adt_to_ffitype(ty, *adt_def, args)?, + _ => throw_unsup_format!("unsupported argument type for native call: {}", ty), + }) + } } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -295,36 +441,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Do we have ptrace? let tracing = trace::Supervisor::is_enabled(); - // Get the function arguments, and convert them to `libffi`-compatible form. - let mut libffi_args = Vec::<CArg>::with_capacity(args.len()); + // Get the function arguments, copy them, and prepare the type descriptions. + let mut libffi_args = Vec::<OwnedArg>::with_capacity(args.len()); for arg in args.iter() { - if !matches!(arg.layout.backend_repr, BackendRepr::Scalar(_)) { - throw_unsup_format!("only scalar argument types are supported for native calls") - } - let imm = this.read_immediate(arg)?; - libffi_args.push(imm_to_carg(&imm, this)?); - // If we are passing a pointer, expose its provenance. Below, all exposed memory - // (previously exposed and new exposed) will then be properly prepared. - if matches!(arg.layout.ty.kind(), ty::RawPtr(..)) { - let ptr = imm.to_scalar().to_pointer(this)?; - let Some(prov) = ptr.provenance else { - // Pointer without provenance may not access any memory anyway, skip. - continue; - }; - // The first time this happens, print a warning. - if !this.machine.native_call_mem_warned.replace(true) { - // Newly set, so first time we get here. - this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem { tracing }); - } - - this.expose_provenance(prov)?; - } + libffi_args.push(this.op_to_ffi_arg(arg, tracing)?); } - // Convert arguments to `libffi::high::Arg` type. - let libffi_args = libffi_args - .iter() - .map(|arg| arg.arg_downcast()) - .collect::<Vec<libffi::high::Arg<'_>>>(); // Prepare all exposed memory (both previously exposed, and just newly exposed since a // pointer was passed as argument). Uninitialised memory is left as-is, but any data @@ -343,8 +464,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance()); if !tracing { - // Expose all provenances in this allocation, since the native code can do $whatever. - // Can be skipped when tracing; in that case we'll expose just the actually-read parts later. + // Expose all provenances in this allocation, since the native code can do + // $whatever. Can be skipped when tracing; in that case we'll expose just the + // actually-read parts later. for prov in alloc.provenance().provenances() { this.expose_provenance(prov)?; } @@ -354,7 +476,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if info.mutbl.is_mut() { let (alloc, cx) = this.get_alloc_raw_mut(alloc_id)?; // These writes could initialize everything and wreck havoc with the pointers. - // We can skip that when tracing; in that case we'll later do that only for the memory that got actually written. + // We can skip that when tracing; in that case we'll later do that only for the + // memory that got actually written. if !tracing { alloc.process_native_write(&cx.tcx, None); } @@ -367,7 +490,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Call the function and store output, depending on return type in the function signature. let (ret, maybe_memevents) = - this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?; + this.call_native_with_args(link_name, dest, code_ptr, &mut libffi_args)?; if tracing { this.tracing_apply_accesses(maybe_memevents.unwrap())?; @@ -377,83 +500,3 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(true) } } - -#[derive(Debug, Clone)] -/// Enum of supported arguments to external C functions. -// We introduce this enum instead of just calling `ffi::arg` and storing a list -// of `libffi::high::Arg` directly, because the `libffi::high::Arg` just wraps a reference -// to the value it represents: https://docs.rs/libffi/latest/libffi/high/call/struct.Arg.html -// and we need to store a copy of the value, and pass a reference to this copy to C instead. -enum CArg { - /// 8-bit signed integer. - Int8(i8), - /// 16-bit signed integer. - Int16(i16), - /// 32-bit signed integer. - Int32(i32), - /// 64-bit signed integer. - Int64(i64), - /// isize. - ISize(isize), - /// 8-bit unsigned integer. - UInt8(u8), - /// 16-bit unsigned integer. - UInt16(u16), - /// 32-bit unsigned integer. - UInt32(u32), - /// 64-bit unsigned integer. - UInt64(u64), - /// usize. - USize(usize), - /// Raw pointer, stored as C's `void*`. - RawPtr(*mut std::ffi::c_void), -} - -impl<'a> CArg { - /// Convert a `CArg` to a `libffi` argument type. - fn arg_downcast(&'a self) -> libffi::high::Arg<'a> { - match self { - CArg::Int8(i) => ffi::arg(i), - CArg::Int16(i) => ffi::arg(i), - CArg::Int32(i) => ffi::arg(i), - CArg::Int64(i) => ffi::arg(i), - CArg::ISize(i) => ffi::arg(i), - CArg::UInt8(i) => ffi::arg(i), - CArg::UInt16(i) => ffi::arg(i), - CArg::UInt32(i) => ffi::arg(i), - CArg::UInt64(i) => ffi::arg(i), - CArg::USize(i) => ffi::arg(i), - CArg::RawPtr(i) => ffi::arg(i), - } - } -} - -/// Extract the scalar value from the result of reading a scalar from the machine, -/// and convert it to a `CArg`. -fn imm_to_carg<'tcx>(v: &ImmTy<'tcx>, cx: &impl HasDataLayout) -> InterpResult<'tcx, CArg> { - interp_ok(match v.layout.ty.kind() { - // If the primitive provided can be converted to a type matching the type pattern - // then create a `CArg` of this primitive value with the corresponding `CArg` constructor. - // the ints - ty::Int(IntTy::I8) => CArg::Int8(v.to_scalar().to_i8()?), - ty::Int(IntTy::I16) => CArg::Int16(v.to_scalar().to_i16()?), - ty::Int(IntTy::I32) => CArg::Int32(v.to_scalar().to_i32()?), - ty::Int(IntTy::I64) => CArg::Int64(v.to_scalar().to_i64()?), - ty::Int(IntTy::Isize) => - CArg::ISize(v.to_scalar().to_target_isize(cx)?.try_into().unwrap()), - // the uints - ty::Uint(UintTy::U8) => CArg::UInt8(v.to_scalar().to_u8()?), - ty::Uint(UintTy::U16) => CArg::UInt16(v.to_scalar().to_u16()?), - ty::Uint(UintTy::U32) => CArg::UInt32(v.to_scalar().to_u32()?), - ty::Uint(UintTy::U64) => CArg::UInt64(v.to_scalar().to_u64()?), - ty::Uint(UintTy::Usize) => - CArg::USize(v.to_scalar().to_target_usize(cx)?.try_into().unwrap()), - ty::RawPtr(..) => { - let s = v.to_scalar().to_pointer(cx)?.addr(); - // This relies on the `expose_provenance` in the `visit_reachable_allocs` callback - // above. - CArg::RawPtr(std::ptr::with_exposed_provenance_mut(s.bytes_usize())) - } - _ => throw_unsup_format!("unsupported argument type for native call: {}", v.layout.ty), - }) -} diff --git a/src/tools/miri/src/shims/native_lib/trace/child.rs b/src/tools/miri/src/shims/native_lib/trace/child.rs index b998ba822dd..95b0617a026 100644 --- a/src/tools/miri/src/shims/native_lib/trace/child.rs +++ b/src/tools/miri/src/shims/native_lib/trace/child.rs @@ -90,14 +90,6 @@ impl Supervisor { // Unwinding might be messed up due to partly protected memory, so let's abort if something // breaks inside here. let res = std::panic::abort_unwind(|| { - // SAFETY: We do not access machine memory past this point until the - // supervisor is ready to allow it. - // FIXME: this is sketchy, as technically the memory is still in the Rust Abstract Machine, - // and the compiler would be allowed to reorder accesses below this block... - unsafe { - Self::protect_pages(alloc.pages(), mman::ProtFlags::PROT_NONE).unwrap(); - } - // Send over the info. // NB: if we do not wait to receive a blank confirmation response, it is // possible that the supervisor is alerted of the SIGSTOP *before* it has @@ -110,16 +102,14 @@ impl Supervisor { // count. signal::raise(signal::SIGSTOP).unwrap(); - let res = f(); + // SAFETY: We have coordinated with the supervisor to ensure that this memory will keep + // working as normal, just with extra tracing. So even if the compiler moves memory + // accesses down to after the `mprotect`, they won't actually segfault. + unsafe { + Self::protect_pages(alloc.pages(), mman::ProtFlags::PROT_NONE).unwrap(); + } - // We can't use IPC channels here to signal that FFI mode has ended, - // since they might allocate memory which could get us stuck in a SIGTRAP - // with no easy way out! While this could be worked around, it is much - // simpler and more robust to simply use the signals which are left for - // arbitrary usage. Since this will block until we are continued by the - // supervisor, we can assume past this point that everything is back to - // normal. - signal::raise(signal::SIGUSR1).unwrap(); + let res = f(); // SAFETY: We set memory back to normal, so this is safe. unsafe { @@ -130,6 +120,12 @@ impl Supervisor { .unwrap(); } + // Signal the supervisor that we are done. Will block until the supervisor continues us. + // This will also shut down the segfault handler, so it's important that all memory is + // reset back to normal above. There must not be a window in time where accessing the + // pages we protected above actually causes the program to abort. + signal::raise(signal::SIGUSR1).unwrap(); + res }); diff --git a/src/tools/miri/src/shims/native_lib/trace/parent.rs b/src/tools/miri/src/shims/native_lib/trace/parent.rs index 83f6c7a13fc..3ae98259ab3 100644 --- a/src/tools/miri/src/shims/native_lib/trace/parent.rs +++ b/src/tools/miri/src/shims/native_lib/trace/parent.rs @@ -18,6 +18,11 @@ const ARCH_WORD_SIZE: usize = 4; #[cfg(target_arch = "x86_64")] const ARCH_WORD_SIZE: usize = 8; +// x86 max instruction length is 15 bytes: +// https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html +// See vol. 3B section 24.25. +const ARCH_MAX_INSTR_SIZE: usize = 15; + /// The address of the page set to be edited, initialised to a sentinel null /// pointer. static PAGE_ADDR: AtomicPtr<u8> = AtomicPtr::new(std::ptr::null_mut()); @@ -132,10 +137,10 @@ impl Iterator for ChildListener { return Some(ExecEvent::Syscall(pid)); }, // Child with the given pid was stopped by the given signal. - // It's somewhat dubious when this is returned instead of - // WaitStatus::Stopped, but for our purposes they are the - // same thing. - wait::WaitStatus::PtraceEvent(pid, signal, _) => + // It's somewhat unclear when which of these two is returned; + // we just treat them the same. + wait::WaitStatus::Stopped(pid, signal) + | wait::WaitStatus::PtraceEvent(pid, signal, _) => if self.attached { // This is our end-of-FFI signal! if signal == signal::SIGUSR1 { @@ -148,19 +153,6 @@ impl Iterator for ChildListener { // Just pass along the signal. ptrace::cont(pid, signal).unwrap(); }, - // Child was stopped at the given signal. Same logic as for - // WaitStatus::PtraceEvent. - wait::WaitStatus::Stopped(pid, signal) => - if self.attached { - if signal == signal::SIGUSR1 { - self.attached = false; - return Some(ExecEvent::End); - } else { - return Some(ExecEvent::Status(pid, signal)); - } - } else { - ptrace::cont(pid, signal).unwrap(); - }, _ => (), }, // This case should only trigger when all children died. @@ -250,7 +242,7 @@ pub fn sv_loop( // We can't trust simply calling `Pid::this()` in the child process to give the right // PID for us, so we get it this way. curr_pid = wait_for_signal(None, signal::SIGSTOP, InitialCont::No).unwrap(); - + // Continue until next syscall. ptrace::syscall(curr_pid, None).unwrap(); } // Child wants to end tracing. @@ -289,8 +281,7 @@ pub fn sv_loop( } } }, - // Child entered a syscall; we wait for exits inside of this, so it - // should never trigger on return from a syscall we care about. + // Child entered or exited a syscall. For now we ignore this and just continue. ExecEvent::Syscall(pid) => { ptrace::syscall(pid, None).unwrap(); } @@ -344,8 +335,8 @@ fn wait_for_signal( return Err(ExecEnd(Some(code))); } wait::WaitStatus::Signaled(_, _, _) => return Err(ExecEnd(None)), - wait::WaitStatus::Stopped(pid, signal) => (signal, pid), - wait::WaitStatus::PtraceEvent(pid, signal, _) => (signal, pid), + wait::WaitStatus::Stopped(pid, signal) + | wait::WaitStatus::PtraceEvent(pid, signal, _) => (signal, pid), // This covers PtraceSyscall and variants that are impossible with // the flags set (e.g. WaitStatus::StillAlive). _ => { @@ -486,7 +477,27 @@ fn handle_segfault( let stack_ptr = ch_stack.strict_add(CALLBACK_STACK_SIZE / 2); let regs_bak = ptrace::getregs(pid).unwrap(); let mut new_regs = regs_bak; - let ip_prestep = regs_bak.ip(); + + // Read at least one instruction from the ip. It's possible that the instruction + // that triggered the segfault was short and at the end of the mapped text area, + // so some of these reads may fail; in that case, just write empty bytes. If all + // reads failed, the disassembler will report an error. + let instr = (0..(ARCH_MAX_INSTR_SIZE.div_ceil(ARCH_WORD_SIZE))) + .flat_map(|ofs| { + // This reads one word of memory; we divided by `ARCH_WORD_SIZE` above to compensate for that. + ptrace::read( + pid, + std::ptr::without_provenance_mut( + regs_bak.ip().strict_add(ARCH_WORD_SIZE.strict_mul(ofs)), + ), + ) + .unwrap_or_default() + .to_ne_bytes() + }) + .collect::<Vec<_>>(); + + // Now figure out the size + type of access and log it down. + capstone_disassemble(&instr, addr, cs, acc_events).expect("Failed to disassemble instruction"); // Move the instr ptr into the deprotection code. #[expect(clippy::as_conversions)] @@ -526,33 +537,8 @@ fn handle_segfault( ptrace::write(pid, std::ptr::with_exposed_provenance_mut(a), 0).unwrap(); } - // Save registers and grab the bytes that were executed. This would - // be really nasty if it was a jump or similar but those thankfully - // won't do memory accesses and so can't trigger this! let regs_bak = ptrace::getregs(pid).unwrap(); new_regs = regs_bak; - let ip_poststep = regs_bak.ip(); - - // Ensure that we've actually gone forwards. - assert!(ip_poststep > ip_prestep); - // But not by too much. 64 bytes should be "big enough" on ~any architecture. - assert!(ip_prestep.strict_add(64) > ip_poststep); - - // We need to do reads/writes in word-sized chunks. - let diff = (ip_poststep.strict_sub(ip_prestep)).div_ceil(ARCH_WORD_SIZE); - let instr = (ip_prestep..ip_prestep.strict_add(diff)).fold(vec![], |mut ret, ip| { - // This only needs to be a valid pointer in the child process, not ours. - ret.append( - &mut ptrace::read(pid, std::ptr::without_provenance_mut(ip)) - .unwrap() - .to_ne_bytes() - .to_vec(), - ); - ret - }); - - // Now figure out the size + type of access and log it down. - capstone_disassemble(&instr, addr, cs, acc_events).expect("Failed to disassemble instruction"); // Reprotect everything and continue. #[expect(clippy::as_conversions)] diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index e226a55d8b1..95e26ef5d5d 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -264,14 +264,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return this.set_last_error_and_return(LibcError("EBADF"), dest); }; + // Handle the zero-sized case. The man page says: + // > If count is zero, read() may detect the errors described below. In the absence of any + // > errors, or if read() does not check for errors, a read() with a count of 0 returns zero + // > and has no other effects. + if count == 0 { + this.write_null(dest)?; + return interp_ok(()); + } // Non-deterministically decide to further reduce the count, simulating a partial read (but - // never to 0, that has different behavior). - let count = - if fd.nondet_short_accesses() && count >= 2 && this.machine.rng.get_mut().random() { - count / 2 - } else { - count - }; + // never to 0, that would indicate EOF). + let count = if this.machine.short_fd_operations + && fd.short_fd_operations() + && count >= 2 + && this.machine.rng.get_mut().random() + { + count / 2 // since `count` is at least 2, the result is still at least 1 + } else { + count + }; trace!("read: FD mapped to {fd:?}"); // We want to read at most `count` bytes. We are sure that `count` is not negative @@ -338,14 +349,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return this.set_last_error_and_return(LibcError("EBADF"), dest); }; - // Non-deterministically decide to further reduce the count, simulating a partial write (but - // never to 0, that has different behavior). - let count = - if fd.nondet_short_accesses() && count >= 2 && this.machine.rng.get_mut().random() { - count / 2 - } else { - count - }; + // Handle the zero-sized case. The man page says: + // > If count is zero and fd refers to a regular file, then write() may return a failure + // > status if one of the errors below is detected. If no errors are detected, or error + // > detection is not performed, 0 is returned without causing any other effect. If count + // > is zero and fd refers to a file other than a regular file, the results are not + // > specified. + if count == 0 { + // For now let's not open the can of worms of what exactly "not specified" could mean... + this.write_null(dest)?; + return interp_ok(()); + } + // Non-deterministically decide to further reduce the count, simulating a partial write. + // We avoid reducing the write size to 0: the docs seem to be entirely fine with that, + // but the standard library is not (https://github.com/rust-lang/rust/issues/145959). + let count = if this.machine.short_fd_operations + && fd.short_fd_operations() + && count >= 2 + && this.machine.rng.get_mut().random() + { + count / 2 + } else { + count + }; let finish = { let dest = dest.clone(); diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs index 2d35ef064db..ee7deb8d383 100644 --- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs @@ -37,11 +37,6 @@ impl FileDescription for EventFd { "event" } - fn nondet_short_accesses(&self) -> bool { - // We always read and write exactly one `u64`. - false - } - fn close<'tcx>( self, _communicate_allowed: bool, diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index 817ddd7954d..7eb82851033 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -123,6 +123,14 @@ impl FileDescription for AnonSocket { anonsocket_write(self, ptr, len, ecx, finish) } + fn short_fd_operations(&self) -> bool { + // Pipes guarantee that sufficiently small accesses are not broken apart: + // <https://pubs.opengroup.org/onlinepubs/9799919799/functions/write.html#tag_17_699_08>. + // For now, we don't bother checking for the size, and just entirely disable + // short accesses on pipes. + matches!(self.fd_type, AnonSocketType::Socketpair) + } + fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription { self } diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 8a965ea316d..92d6321bed1 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -289,9 +289,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } if this.ptr_is_null(target_handle_ptr)? { - throw_unsup_format!( - "`DuplicateHandle` `lpTargetHandle` parameter is null, which is unsupported" - ); + throw_machine_stop!(TerminationInfo::Abort( + "`DuplicateHandle` `lpTargetHandle` parameter must not be null, as otherwise the \ + newly created handle is leaked" + .to_string() + )); } if options != this.eval_windows("c", "DUPLICATE_SAME_ACCESS") { diff --git a/src/tools/miri/tests/deps/Cargo.lock b/src/tools/miri/tests/deps/Cargo.lock index 4b783ebdc4e..65ca4215c60 100644 --- a/src/tools/miri/tests/deps/Cargo.lock +++ b/src/tools/miri/tests/deps/Cargo.lock @@ -296,9 +296,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "socket2" diff --git a/src/tools/miri/tests/fail/intrinsics/funnel_shl.rs b/src/tools/miri/tests/fail/intrinsics/funnel_shl.rs new file mode 100644 index 00000000000..40b61f65ebe --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/funnel_shl.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics, funnel_shifts)] + +fn main() { + unsafe { + std::intrinsics::unchecked_funnel_shl(1_u32, 2, 32); //~ ERROR: Undefined Behavior + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/funnel_shl.stderr b/src/tools/miri/tests/fail/intrinsics/funnel_shl.stderr new file mode 100644 index 00000000000..fc828021b13 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/funnel_shl.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `assume` called with `false` + --> tests/fail/intrinsics/funnel_shl.rs:LL:CC + | +LL | std::intrinsics::unchecked_funnel_shl(1_u32, 2, 32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/intrinsics/funnel_shl.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/intrinsics/funnel_shr.rs b/src/tools/miri/tests/fail/intrinsics/funnel_shr.rs new file mode 100644 index 00000000000..95822656397 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/funnel_shr.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics, funnel_shifts)] + +fn main() { + unsafe { + std::intrinsics::unchecked_funnel_shr(1_u32, 2, 32); //~ ERROR: Undefined Behavior + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/funnel_shr.stderr b/src/tools/miri/tests/fail/intrinsics/funnel_shr.stderr new file mode 100644 index 00000000000..7361df1b4c7 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/funnel_shr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `assume` called with `false` + --> tests/fail/intrinsics/funnel_shr.rs:LL:CC + | +LL | std::intrinsics::unchecked_funnel_shr(1_u32, 2, 32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/intrinsics/funnel_shr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.rs b/src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.rs new file mode 100644 index 00000000000..7d51050f32b --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.rs @@ -0,0 +1,9 @@ +//@compile-flags: -Zmiri-tree-borrows + +fn main() { + // Since the "inside" part is `!Freeze`, the permission to mutate is gone. + let pair = ((), 1); + let x = &pair.0; + let ptr = (&raw const *x).cast::<i32>().cast_mut(); + unsafe { ptr.write(0) }; //~ERROR: /write access .* forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.stderr b/src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.stderr new file mode 100644 index 00000000000..e9800468c57 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.stderr @@ -0,0 +1,21 @@ +error: Undefined Behavior: write access through <TAG> at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.rs:LL:CC + | +LL | unsafe { ptr.write(0) }; + | ^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag <TAG> has state Frozen which forbids this child write access +help: the accessed tag <TAG> was created here, in the initial state Frozen + --> tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.rs:LL:CC + | +LL | let x = &pair.0; + | ^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/tree_borrows/frozen-lazy-write-to-surrounding.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/native-lib/aggregate_arguments.c b/src/tools/miri/tests/native-lib/aggregate_arguments.c new file mode 100644 index 00000000000..8ad687f2aec --- /dev/null +++ b/src/tools/miri/tests/native-lib/aggregate_arguments.c @@ -0,0 +1,52 @@ +#include <stdint.h> + +// See comments in build_native_lib() +#define EXPORT __attribute__((visibility("default"))) + +/* Test: fail/pass_struct_expose_only_range */ + +typedef struct HasPointer { + uint8_t *ptr; +} HasPointer; + +EXPORT uint8_t access_struct_ptr(const HasPointer s) { + return *s.ptr; +} + +/* Test: test_pass_struct */ + +typedef struct PassMe { + int32_t value; + int64_t other_value; +} PassMe; + +EXPORT int64_t pass_struct(const PassMe pass_me) { + return pass_me.value + pass_me.other_value; +} + +/* Test: test_pass_struct_complex */ + +typedef struct Part1 { + uint16_t high; + uint16_t low; +} Part1; + +typedef struct Part2 { + uint32_t bits; +} Part2; + +typedef struct ComplexStruct { + Part1 part_1; + Part2 part_2; + uint32_t part_3; +} ComplexStruct; + +EXPORT int32_t pass_struct_complex(const ComplexStruct complex, uint16_t high, uint16_t low, uint32_t bits) { + if (complex.part_1.high == high && complex.part_1.low == low + && complex.part_2.bits == bits + && complex.part_3 == bits) + return 0; + else { + return 1; + } +} diff --git a/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.rs b/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.rs new file mode 100644 index 00000000000..a2b43031a29 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.rs @@ -0,0 +1,23 @@ +//@compile-flags: -Zmiri-permissive-provenance + +#[repr(C)] +#[derive(Copy, Clone)] +struct HasPointer { + ptr: *const u8, +} + +extern "C" { + fn access_struct_ptr(s: HasPointer) -> u8; +} + +fn main() { + let structs = vec![HasPointer { ptr: &0 }, HasPointer { ptr: &1 }]; + unsafe { + let r = access_struct_ptr(structs[1]); + assert_eq!(r, 1); + // There are two pointers stored in the allocation backing `structs`; ensure + // we only exposed the one that was actually passed to C. + let _val = *std::ptr::with_exposed_provenance::<u8>(structs[1].ptr.addr()); // fine, ptr got sent to C + let _val = *std::ptr::with_exposed_provenance::<u8>(structs[0].ptr.addr()); //~ ERROR: memory access failed + }; +} diff --git a/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.stderr b/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.stderr new file mode 100644 index 00000000000..a8f85001c23 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/pass_struct_expose_only_range.stderr @@ -0,0 +1,28 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/fail/pass_struct_expose_only_range.rs:LL:CC + | +LL | let r = access_struct_ptr(structs[1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory + = help: in particular, Miri assumes that the native call initializes all memory it has access to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = note: BACKTRACE: + = note: inside `main` at tests/native-lib/fail/pass_struct_expose_only_range.rs:LL:CC + +error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + --> tests/native-lib/fail/pass_struct_expose_only_range.rs:LL:CC + | +LL | let _val = *std::ptr::with_exposed_provenance::<u8>(structs[0].ptr.addr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/native-lib/fail/pass_struct_expose_only_range.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.rs b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.rs new file mode 100644 index 00000000000..cf8315e0fd9 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.rs @@ -0,0 +1,19 @@ +// Only works on Unix targets +//@ignore-target: windows wasm +//@only-on-host + +#![allow(improper_ctypes)] + +pub struct PassMe { + pub value: i32, + pub other_value: i64, +} + +extern "C" { + fn pass_struct(s: PassMe) -> i64; +} + +fn main() { + let pass_me = PassMe { value: 42, other_value: 1337 }; + unsafe { pass_struct(pass_me) }; //~ ERROR: unsupported operation: passing a non-#[repr(C)] struct over FFI +} diff --git a/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.stderr b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.stderr new file mode 100644 index 00000000000..90e59a31da4 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/struct_not_extern_c.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: passing a non-#[repr(C)] struct over FFI: PassMe + --> tests/native-lib/fail/struct_not_extern_c.rs:LL:CC + | +LL | unsafe { pass_struct(pass_me) }; + | ^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: BACKTRACE: + = note: inside `main` at tests/native-lib/fail/struct_not_extern_c.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/native-lib/fail/uninit_struct.rs b/src/tools/miri/tests/native-lib/fail/uninit_struct.rs new file mode 100644 index 00000000000..cf61c7f3915 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/uninit_struct.rs @@ -0,0 +1,27 @@ +#[repr(C)] +#[derive(Copy, Clone)] +struct ComplexStruct { + part_1: Part1, + part_2: Part2, + part_3: u32, +} +#[repr(C)] +#[derive(Copy, Clone)] +struct Part1 { + high: u16, + low: u16, +} +#[repr(C)] +#[derive(Copy, Clone)] +struct Part2 { + bits: u32, +} + +extern "C" { + fn pass_struct_complex(s: ComplexStruct, high: u16, low: u16, bits: u32) -> i32; +} + +fn main() { + let arg = std::mem::MaybeUninit::<ComplexStruct>::uninit(); + unsafe { pass_struct_complex(*arg.as_ptr(), 0, 0, 0) }; //~ ERROR: Undefined Behavior: constructing invalid value +} diff --git a/src/tools/miri/tests/native-lib/fail/uninit_struct.stderr b/src/tools/miri/tests/native-lib/fail/uninit_struct.stderr new file mode 100644 index 00000000000..0fe6ad9c77b --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/uninit_struct.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value at .part_1.high: encountered uninitialized memory, but expected an integer + --> tests/native-lib/fail/uninit_struct.rs:LL:CC + | +LL | unsafe { pass_struct_complex(*arg.as_ptr(), 0, 0, 0) }; + | ^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/native-lib/fail/uninit_struct.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/native-lib/pass/aggregate_arguments.rs b/src/tools/miri/tests/native-lib/pass/aggregate_arguments.rs new file mode 100644 index 00000000000..55acb240612 --- /dev/null +++ b/src/tools/miri/tests/native-lib/pass/aggregate_arguments.rs @@ -0,0 +1,52 @@ +fn main() { + test_pass_struct(); + test_pass_struct_complex(); +} + +/// Test passing a basic struct as an argument. +fn test_pass_struct() { + // Exactly two fields, so that we hit the ScalarPair case. + #[repr(C)] + struct PassMe { + value: i32, + other_value: i64, + } + + extern "C" { + fn pass_struct(s: PassMe) -> i64; + } + + let pass_me = PassMe { value: 42, other_value: 1337 }; + assert_eq!(unsafe { pass_struct(pass_me) }, 42 + 1337); +} + +/// Test passing a more complex struct as an argument. +fn test_pass_struct_complex() { + #[repr(C)] + struct ComplexStruct { + part_1: Part1, + part_2: Part2, + part_3: u32, + } + #[repr(C)] + struct Part1 { + high: u16, + low: u16, + } + #[repr(C)] + struct Part2 { + bits: u32, + } + + extern "C" { + fn pass_struct_complex(s: ComplexStruct, high: u16, low: u16, bits: u32) -> i32; + } + + let high = 0xabcd; + let low = 0xef01; + let bits = 0xabcdef01; + + let complex = + ComplexStruct { part_1: Part1 { high, low }, part_2: Part2 { bits }, part_3: bits }; + assert_eq!(unsafe { pass_struct_complex(complex, high, low, bits) }, 0); +} diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs index 4f3c37f00c1..bab73f7cf17 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs @@ -1,6 +1,7 @@ //@revisions: trace notrace //@[trace] only-target: x86_64-unknown-linux-gnu i686-unknown-linux-gnu //@[trace] compile-flags: -Zmiri-native-lib-enable-tracing +//@compile-flags: -Zmiri-permissive-provenance fn main() { test_access_pointer(); diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs index 4ca19046b67..7b756603d92 100644 --- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs +++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs @@ -2,20 +2,20 @@ //@compile-flags: -Zmiri-disable-isolation #![allow(nonstandard_style)] -use std::io::{ErrorKind, Read, Write}; +use std::io::{ErrorKind, Read, Seek, SeekFrom, Write}; use std::os::windows::ffi::OsStrExt; -use std::os::windows::io::AsRawHandle; +use std::os::windows::io::{AsRawHandle, FromRawHandle}; use std::path::Path; -use std::{fs, ptr}; +use std::{fs, mem, ptr}; #[path = "../../utils/mod.rs"] mod utils; use windows_sys::Wdk::Storage::FileSystem::{NtReadFile, NtWriteFile}; use windows_sys::Win32::Foundation::{ - CloseHandle, ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS, ERROR_IO_DEVICE, GENERIC_READ, - GENERIC_WRITE, GetLastError, RtlNtStatusToDosError, STATUS_ACCESS_DENIED, - STATUS_IO_DEVICE_ERROR, STATUS_SUCCESS, SetLastError, + CloseHandle, DUPLICATE_SAME_ACCESS, DuplicateHandle, ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS, + ERROR_IO_DEVICE, FALSE, GENERIC_READ, GENERIC_WRITE, GetLastError, RtlNtStatusToDosError, + STATUS_ACCESS_DENIED, STATUS_IO_DEVICE_ERROR, STATUS_SUCCESS, SetLastError, }; use windows_sys::Win32::Storage::FileSystem::{ BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, DeleteFileW, @@ -24,6 +24,7 @@ use windows_sys::Win32::Storage::FileSystem::{ FILE_SHARE_WRITE, GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, SetFilePointerEx, }; use windows_sys::Win32::System::IO::IO_STATUS_BLOCK; +use windows_sys::Win32::System::Threading::GetCurrentProcess; fn main() { unsafe { @@ -36,6 +37,7 @@ fn main() { test_ntstatus_to_dos(); test_file_read_write(); test_file_seek(); + test_dup_handle(); } } @@ -273,6 +275,39 @@ unsafe fn test_file_read_write() { assert_eq!(GetLastError(), 1234); } +unsafe fn test_dup_handle() { + let temp = utils::tmp().join("test_dup.txt"); + + let mut file1 = fs::File::options().read(true).write(true).create(true).open(&temp).unwrap(); + + file1.write_all(b"Hello, World!\n").unwrap(); + file1.seek(SeekFrom::Start(0)).unwrap(); + + let first_handle = file1.as_raw_handle(); + + let cur_proc = GetCurrentProcess(); + let mut second_handle = mem::zeroed(); + let res = DuplicateHandle( + cur_proc, + first_handle, + cur_proc, + &mut second_handle, + 0, + FALSE, + DUPLICATE_SAME_ACCESS, + ); + assert!(res != 0); + + let mut buf1 = [0; 5]; + file1.read(&mut buf1).unwrap(); + assert_eq!(&buf1, b"Hello"); + + let mut file2 = fs::File::from_raw_handle(second_handle); + let mut buf2 = [0; 5]; + file2.read(&mut buf2).unwrap(); + assert_eq!(&buf2, b", Wor"); +} + unsafe fn test_file_seek() { let temp = utils::tmp().join("test_file_seek.txt"); let mut file = fs::File::options().create(true).write(true).read(true).open(&temp).unwrap(); diff --git a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs index 6a625e597df..82976326a8d 100644 --- a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs +++ b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs @@ -23,7 +23,8 @@ fn main() { not_unpin_not_protected(); write_does_not_invalidate_all_aliases(); box_into_raw_allows_interior_mutable_alias(); - cell_inside_struct() + cell_inside_struct(); + zst(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -287,3 +288,22 @@ fn cell_inside_struct() { // Writing to `field1`, which is reserved, should also be allowed. (*a).field1 = 88; } + +/// ZST reborrows on various kinds of dangling pointers are valid. +fn zst() { + unsafe { + // Integer pointer. + let ptr = ptr::without_provenance_mut::<()>(15); + let _ref = &mut *ptr; + + // Out-of-bounds pointer. + let mut b = Box::new(0u8); + let ptr = (&raw mut *b).wrapping_add(15) as *mut (); + let _ref = &mut *ptr; + + // Deallocated pointer. + let ptr = &raw mut *b as *mut (); + drop(b); + let _ref = &mut *ptr; + } +} diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs index a92359758da..142ac9cc8ca 100644 --- a/src/tools/miri/tests/pass/concurrency/sync.rs +++ b/src/tools/miri/tests/pass/concurrency/sync.rs @@ -9,7 +9,8 @@ use std::time::{Duration, Instant}; // We are expecting to sleep for 10ms. How long of a sleep we are accepting? // Even with 1000ms we still see this test fail on macOS runners. -const MAX_SLEEP_TIME_MS: u64 = 2000; +// On a aarch64-pc-windows-msvc runner, we saw 2.7s! +const MAX_SLEEP_TIME_MS: u64 = 4000; // Check if Rust barriers are working. diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index fe7316c6680..1b1163c7797 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -39,9 +39,8 @@ macro_rules! assert_approx_eq { }}; ($a:expr, $b: expr) => { - // accept up to 12ULP (4ULP for host floats and 4ULP for miri artificial error and 4 for any additional effects - // due to having multiple error sources. - assert_approx_eq!($a, $b, 12); + // accept up to 8ULP (4ULP for host floats and 4ULP for miri artificial error). + assert_approx_eq!($a, $b, 8); }; } @@ -176,6 +175,7 @@ fn assert_eq_msg<T: PartialEq + Debug>(x: T, y: T, msg: impl Display) { } /// Check that floats have bitwise equality +#[track_caller] fn assert_biteq<F: Float>(a: F, b: F, msg: impl Display) { let ab = a.to_bits(); let bb = b.to_bits(); @@ -189,6 +189,7 @@ fn assert_biteq<F: Float>(a: F, b: F, msg: impl Display) { } /// Check that two floats have equality +#[track_caller] fn assert_feq<F: Float>(a: F, b: F, msg: impl Display) { let ab = a.to_bits(); let bb = b.to_bits(); @@ -1051,6 +1052,10 @@ pub fn libm() { assert_eq!(42f64.powf(0.0), 1.0); assert_eq!(f32::INFINITY.powf(0.0), 1.0); assert_eq!(f64::INFINITY.powf(0.0), 1.0); + assert_eq!(f32::NEG_INFINITY.powi(3), f32::NEG_INFINITY); + assert_eq!(f32::NEG_INFINITY.powi(2), f32::INFINITY); + assert_eq!(f64::INFINITY.powi(3), f64::INFINITY); + assert_eq!(f64::INFINITY.powi(2), f64::INFINITY); // f*::NAN is a quiet NAN and should return 1 as well. assert_eq!(f32::NAN.powi(0), 1.0); diff --git a/src/tools/miri/tests/pass/float_extra_rounding_error.rs b/src/tools/miri/tests/pass/float_extra_rounding_error.rs new file mode 100644 index 00000000000..24d7cf2ccee --- /dev/null +++ b/src/tools/miri/tests/pass/float_extra_rounding_error.rs @@ -0,0 +1,31 @@ +//! Check that the flags to control the extra rounding error work. +//@revisions: random max none +//@[max]compile-flags: -Zmiri-max-extra-rounding-error +//@[none]compile-flags: -Zmiri-no-extra-rounding-error +#![feature(cfg_select)] + +use std::collections::HashSet; +use std::hint::black_box; + +fn main() { + let expected = cfg_select! { + random => 9, // -4 ..= +4 ULP error + max => 2, + none => 1, + }; + // Call `sin(0.5)` a bunch of times and see how many different values we get. + let mut values = HashSet::new(); + for _ in 0..(expected * 16) { + let val = black_box(0.5f64).sin(); + values.insert(val.to_bits()); + } + assert_eq!(values.len(), expected); + + if !cfg!(none) { + // Ensure the smallest and biggest value are 8 ULP apart. + // We can just subtract the raw bit representations for this. + let min = *values.iter().min().unwrap(); + let max = *values.iter().max().unwrap(); + assert_eq!(min.abs_diff(max), 8); + } +} diff --git a/src/tools/miri/tests/pass/intrinsics/integer.rs b/src/tools/miri/tests/pass/intrinsics/integer.rs index 13e7bd8e1b9..8727b6d3c87 100644 --- a/src/tools/miri/tests/pass/intrinsics/integer.rs +++ b/src/tools/miri/tests/pass/intrinsics/integer.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org) -#![feature(core_intrinsics)] +#![feature(core_intrinsics, funnel_shifts)] use std::intrinsics::*; pub fn main() { @@ -143,5 +143,11 @@ pub fn main() { assert_eq!(unchecked_mul(6u8, 7), 42); assert_eq!(unchecked_mul(13, -5), -65); + + assert_eq!(unchecked_funnel_shl(1_u32, 2, 5), 32); + assert_eq!(unchecked_funnel_shl(1_u32, 2, 31), 0x80000001); + + assert_eq!(unchecked_funnel_shr(1_u32, 2, 5), 0x08000000); + assert_eq!(unchecked_funnel_shr(1_u32, 2, 31), 2); } } diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index e7f11c54704..022dcc5dcba 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -72,7 +72,9 @@ fn test_file() { // Writing to a file opened for reading should error (and not stop interpretation). std does not // categorize the error so we don't check for details. - file.write(&[]).unwrap_err(); + file.write(&[0]).unwrap_err(); + // However, writing 0 bytes can succeed or fail. + let _ignore = file.write(&[]); // Removing file should succeed. remove_file(&path).unwrap(); diff --git a/src/tools/miri/tests/pass/shims/x86/rounding-error.rs b/src/tools/miri/tests/pass/shims/x86/rounding-error.rs new file mode 100644 index 00000000000..bf56111b2e4 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/x86/rounding-error.rs @@ -0,0 +1,37 @@ +// We're testing x86 target specific features +//@only-target: x86_64 i686 + +//! rsqrt and rcp SSE/AVX operations are approximate. We use that as license to treat them as +//! non-deterministic. Ensure that we do indeed see random results within the expected error bounds. + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; +use std::collections::HashSet; + +fn main() { + let mut vals = HashSet::new(); + for _ in 0..50 { + unsafe { + // Compute the inverse square root of 4.0, four times. + let a = _mm_setr_ps(4.0, 4.0, 4.0, 4.0); + let exact = 0.5; + let r = _mm_rsqrt_ps(a); + let r: [f32; 4] = std::mem::transmute(r); + // Check the results. + for r in r { + vals.insert(r.to_bits()); + // Ensure the relative error is less than 2^-12. + let rel_error = (r - exact) / exact; + let log_error = rel_error.abs().log2(); + assert!( + rel_error == 0.0 || log_error < -12.0, + "got an error of {rel_error} = 2^{log_error}" + ); + } + } + } + // Ensure we saw a bunch of different results. + assert!(vals.len() >= 50); +} diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs b/src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs index abe08f2cd22..7352784ac7a 100644 --- a/src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs +++ b/src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs @@ -14,9 +14,11 @@ fn main() { foo(&arr[0]); let pair = (Cell::new(1), 1); - // TODO: Ideally, this would result in UB since the second element - // in `pair` is Frozen. We would need some way to express a - // "shared reference with permission to access surrounding - // interior mutable data". foo(&pair.0); + + // As long as the "inside" part is `!Freeze`, the permission to mutate the "outside" is preserved. + let pair = (Cell::new(()), 1); + let x = &pair.0; + let ptr = (&raw const *x).cast::<i32>().cast_mut(); + unsafe { ptr.write(0) }; } diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index f021d5194cd..b7286d9a367 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -60,6 +60,7 @@ fn build_native_lib(target: &str) -> PathBuf { native_lib_path.to_str().unwrap(), // FIXME: Automate gathering of all relevant C source files in the directory. "tests/native-lib/scalar_arguments.c", + "tests/native-lib/aggregate_arguments.c", "tests/native-lib/ptr_read_access.c", "tests/native-lib/ptr_write_access.c", // Ensure we notice serious problems in the C code. diff --git a/src/tools/miri/tests/utils/libc.rs b/src/tools/miri/tests/utils/libc.rs index 1a3cd067c04..4757a5a268c 100644 --- a/src/tools/miri/tests/utils/libc.rs +++ b/src/tools/miri/tests/utils/libc.rs @@ -34,10 +34,7 @@ pub unsafe fn write_all( if res < 0 { return res; } - if res == 0 { - // EOF? - break; - } + // Apparently a return value of 0 is just a short write, nothing special (unlike reads). written_so_far += res as libc::size_t; } return written_so_far as libc::ssize_t; diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 6974ede624a..560f11ecf50 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -490,6 +490,7 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", + "wit-bindgen", // tidy-alphabetical-end ]; @@ -798,7 +799,10 @@ fn check_runtime_no_duplicate_dependencies(metadata: &Metadata, bad: &mut bool) continue; } - if !seen_pkgs.insert(&*pkg.name) { + // Skip the `wasi` crate here which the standard library explicitly + // depends on two version of (one for the `wasm32-wasip1` target and + // another for the `wasm32-wasip2` target). + if pkg.name.to_string() != "wasi" && !seen_pkgs.insert(&*pkg.name) { tidy_error!( bad, "duplicate package `{}` is not allowed for the standard library", diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs index 305a0b4d264..6f25ed616fa 100644 --- a/src/tools/tidy/src/triagebot.rs +++ b/src/tools/tidy/src/triagebot.rs @@ -19,7 +19,12 @@ pub fn check(path: &Path, bad: &mut bool) { // Check [mentions."*"] sections, i.e. [mentions."compiler/rustc_const_eval/src/"] if let Some(Value::Table(mentions)) = config.get("mentions") { - for path_str in mentions.keys() { + for (entry_key, entry_val) in mentions.iter() { + // If the type is set to something other than "filename", then this is not a path. + if entry_val.get("type").is_some_and(|t| t.as_str().unwrap_or_default() != "filename") { + continue; + } + let path_str = entry_key; // Remove quotes from the path let clean_path = path_str.trim_matches('"'); let full_path = path.join(clean_path); diff --git a/src/tools/unicode-table-generator/src/case_mapping.rs b/src/tools/unicode-table-generator/src/case_mapping.rs index 9c6454492e7..49aef3ec33e 100644 --- a/src/tools/unicode-table-generator/src/case_mapping.rs +++ b/src/tools/unicode-table-generator/src/case_mapping.rs @@ -6,24 +6,26 @@ use crate::{UnicodeData, fmt_list}; const INDEX_MASK: u32 = 1 << 22; -pub(crate) fn generate_case_mapping(data: &UnicodeData) -> String { +pub(crate) fn generate_case_mapping(data: &UnicodeData) -> (String, [usize; 2]) { let mut file = String::new(); write!(file, "const INDEX_MASK: u32 = 0x{INDEX_MASK:x};").unwrap(); file.push_str("\n\n"); file.push_str(HEADER.trim_start()); file.push('\n'); - file.push_str(&generate_tables("LOWER", &data.to_lower)); + let (lower_tables, lower_size) = generate_tables("LOWER", &data.to_lower); + file.push_str(&lower_tables); file.push_str("\n\n"); - file.push_str(&generate_tables("UPPER", &data.to_upper)); - file + let (upper_tables, upper_size) = generate_tables("UPPER", &data.to_upper); + file.push_str(&upper_tables); + (file, [lower_size, upper_size]) } -fn generate_tables(case: &str, data: &BTreeMap<u32, (u32, u32, u32)>) -> String { +fn generate_tables(case: &str, data: &BTreeMap<u32, [u32; 3]>) -> (String, usize) { let mut mappings = Vec::with_capacity(data.len()); let mut multis = Vec::new(); - for (&key, &(a, b, c)) in data.iter() { + for (&key, &[a, b, c]) in data.iter() { let key = char::from_u32(key).unwrap(); if key.is_ascii() { @@ -46,16 +48,31 @@ fn generate_tables(case: &str, data: &BTreeMap<u32, (u32, u32, u32)>) -> String } let mut tables = String::new(); - - write!(tables, "static {}CASE_TABLE: &[(char, u32)] = &[{}];", case, fmt_list(mappings)) - .unwrap(); + let mut size = 0; + + size += size_of_val(mappings.as_slice()); + write!( + tables, + "static {}CASE_TABLE: &[(char, u32); {}] = &[{}];", + case, + mappings.len(), + fmt_list(mappings), + ) + .unwrap(); tables.push_str("\n\n"); - write!(tables, "static {}CASE_TABLE_MULTI: &[[char; 3]] = &[{}];", case, fmt_list(multis)) - .unwrap(); - - tables + size += size_of_val(multis.as_slice()); + write!( + tables, + "static {}CASE_TABLE_MULTI: &[[char; 3]; {}] = &[{}];", + case, + multis.len(), + fmt_list(multis), + ) + .unwrap(); + + (tables, size) } struct CharEscape(char); diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs index 38e5e8bbdb9..9399021df76 100644 --- a/src/tools/unicode-table-generator/src/main.rs +++ b/src/tools/unicode-table-generator/src/main.rs @@ -72,6 +72,8 @@ //! or not. use std::collections::{BTreeMap, HashMap}; +use std::fmt; +use std::fmt::Write; use std::ops::Range; use ucd_parse::Codepoints; @@ -97,11 +99,11 @@ static PROPERTIES: &[&str] = &[ struct UnicodeData { ranges: Vec<(&'static str, Vec<Range<u32>>)>, - to_upper: BTreeMap<u32, (u32, u32, u32)>, - to_lower: BTreeMap<u32, (u32, u32, u32)>, + to_upper: BTreeMap<u32, [u32; 3]>, + to_lower: BTreeMap<u32, [u32; 3]>, } -fn to_mapping(origin: u32, codepoints: Vec<ucd_parse::Codepoint>) -> Option<(u32, u32, u32)> { +fn to_mapping(origin: u32, codepoints: Vec<ucd_parse::Codepoint>) -> Option<[u32; 3]> { let mut a = None; let mut b = None; let mut c = None; @@ -122,7 +124,7 @@ fn to_mapping(origin: u32, codepoints: Vec<ucd_parse::Codepoint>) -> Option<(u32 } } - Some((a.unwrap(), b.unwrap_or(0), c.unwrap_or(0))) + Some([a.unwrap(), b.unwrap_or(0), c.unwrap_or(0)]) } static UNICODE_DIRECTORY: &str = "unicode-downloads"; @@ -162,12 +164,12 @@ fn load_data() -> UnicodeData { if let Some(mapped) = row.simple_lowercase_mapping && mapped != row.codepoint { - to_lower.insert(row.codepoint.value(), (mapped.value(), 0, 0)); + to_lower.insert(row.codepoint.value(), [mapped.value(), 0, 0]); } if let Some(mapped) = row.simple_uppercase_mapping && mapped != row.codepoint { - to_upper.insert(row.codepoint.value(), (mapped.value(), 0, 0)); + to_upper.insert(row.codepoint.value(), [mapped.value(), 0, 0]); } } @@ -186,33 +188,19 @@ fn load_data() -> UnicodeData { } } - let mut properties: HashMap<&'static str, Vec<Range<u32>>> = properties + let mut properties: Vec<(&'static str, Vec<Range<u32>>)> = properties .into_iter() - .map(|(k, v)| { - ( - k, - v.into_iter() - .flat_map(|codepoints| match codepoints { - Codepoints::Single(c) => c - .scalar() - .map(|ch| ch as u32..ch as u32 + 1) - .into_iter() - .collect::<Vec<_>>(), - Codepoints::Range(c) => c - .into_iter() - .flat_map(|c| c.scalar().map(|ch| ch as u32..ch as u32 + 1)) - .collect::<Vec<_>>(), - }) - .collect::<Vec<Range<u32>>>(), - ) + .map(|(prop, codepoints)| { + let codepoints = codepoints + .into_iter() + .flatten() + .flat_map(|cp| cp.scalar()) + .map(u32::from) + .collect::<Vec<_>>(); + (prop, ranges_from_set(&codepoints)) }) .collect(); - for ranges in properties.values_mut() { - merge_ranges(ranges); - } - - let mut properties = properties.into_iter().collect::<Vec<_>>(); properties.sort_by_key(|p| p.0); UnicodeData { ranges: properties, to_lower, to_upper } } @@ -235,9 +223,14 @@ fn main() { let ranges_by_property = &unicode_data.ranges; if let Some(path) = test_path { - std::fs::write(&path, generate_tests(&write_location, ranges_by_property)).unwrap(); + std::fs::write(&path, generate_tests(&unicode_data).unwrap()).unwrap(); } + let mut table_file = String::new(); + table_file.push_str( + "///! This file is generated by `./x run src/tools/unicode-table-generator`; do not edit manually!\n", + ); + let mut total_bytes = 0; let mut modules = Vec::new(); for (property, ranges) in ranges_by_property { @@ -251,8 +244,8 @@ fn main() { } modules.push((property.to_lowercase().to_string(), emitter.file)); - println!( - "{:15}: {} bytes, {} codepoints in {} ranges ({} - {}) using {}", + table_file.push_str(&format!( + "// {:16}: {:5} bytes, {:6} codepoints in {:3} ranges (U+{:06X} - U+{:06X}) using {}\n", property, emitter.bytes_used, datapoints, @@ -260,15 +253,15 @@ fn main() { ranges.first().unwrap().start, ranges.last().unwrap().end, emitter.desc, - ); + )); total_bytes += emitter.bytes_used; } - - let mut table_file = String::new(); - - table_file.push_str( - "///! This file is generated by `./x run src/tools/unicode-table-generator`; do not edit manually!\n", - ); + let (conversions, sizes) = case_mapping::generate_case_mapping(&unicode_data); + for (name, size) in ["to_lower", "to_upper"].iter().zip(sizes) { + table_file.push_str(&format!("// {:16}: {:5} bytes\n", name, size)); + total_bytes += size; + } + table_file.push_str(&format!("// {:16}: {:5} bytes\n", "Total", total_bytes)); // Include the range search function table_file.push('\n'); @@ -279,7 +272,7 @@ fn main() { table_file.push('\n'); - modules.push((String::from("conversions"), case_mapping::generate_case_mapping(&unicode_data))); + modules.push((String::from("conversions"), conversions)); for (name, contents) in modules { table_file.push_str("#[rustfmt::skip]\n"); @@ -295,8 +288,6 @@ fn main() { } std::fs::write(&write_location, format!("{}\n", table_file.trim_end())).unwrap(); - - println!("Total table sizes: {total_bytes} bytes"); } fn version() -> String { @@ -336,110 +327,96 @@ fn fmt_list<V: std::fmt::Debug>(values: impl IntoIterator<Item = V>) -> String { out } -fn generate_tests(data_path: &str, ranges: &[(&str, Vec<Range<u32>>)]) -> String { +fn generate_tests(data: &UnicodeData) -> Result<String, fmt::Error> { let mut s = String::new(); - s.push_str("#![allow(incomplete_features, unused)]\n"); - s.push_str("#![feature(const_generics)]\n\n"); - s.push_str("\n#[allow(unused)]\nuse std::hint;\n"); - s.push_str(&format!("#[path = \"{data_path}\"]\n")); - s.push_str("mod unicode_data;\n\n"); - - s.push_str("\nfn main() {\n"); - - for (property, ranges) in ranges { - s.push_str(&format!(r#" println!("Testing {property}");"#)); - s.push('\n'); - s.push_str(&format!(" {}_true();\n", property.to_lowercase())); - s.push_str(&format!(" {}_false();\n", property.to_lowercase())); - let mut is_true = Vec::new(); - let mut is_false = Vec::new(); - for ch_num in 0..(std::char::MAX as u32) { - if std::char::from_u32(ch_num).is_none() { - continue; - } - if ranges.iter().any(|r| r.contains(&ch_num)) { - is_true.push(ch_num); - } else { - is_false.push(ch_num); - } - } - - s.push_str(&format!(" fn {}_true() {{\n", property.to_lowercase())); - generate_asserts(&mut s, property, &is_true, true); - s.push_str(" }\n\n"); - s.push_str(&format!(" fn {}_false() {{\n", property.to_lowercase())); - generate_asserts(&mut s, property, &is_false, false); - s.push_str(" }\n\n"); + writeln!(s, "#![feature(core_intrinsics)]")?; + writeln!(s, "#![allow(internal_features, dead_code)]")?; + writeln!(s, "// ignore-tidy-filelength")?; + writeln!(s, "use std::intrinsics;")?; + writeln!(s, "mod unicode_data;")?; + writeln!(s, "fn main() {{")?; + for (property, ranges) in &data.ranges { + let prop = property.to_lowercase(); + writeln!(s, r#" println!("Testing {prop}");"#)?; + writeln!(s, " {prop}_true();")?; + writeln!(s, " {prop}_false();")?; + let (is_true, is_false): (Vec<_>, Vec<_>) = (char::MIN..=char::MAX) + .filter(|c| !c.is_ascii()) + .map(u32::from) + .partition(|c| ranges.iter().any(|r| r.contains(c))); + + writeln!(s, " fn {prop}_true() {{")?; + generate_asserts(&mut s, &prop, &is_true, true)?; + writeln!(s, " }}")?; + + writeln!(s, " fn {prop}_false() {{")?; + generate_asserts(&mut s, &prop, &is_false, false)?; + writeln!(s, " }}")?; } - s.push('}'); - s -} - -fn generate_asserts(s: &mut String, property: &str, points: &[u32], truthy: bool) { - for range in ranges_from_set(points) { - if range.end == range.start + 1 { - s.push_str(&format!( - " assert!({}unicode_data::{}::lookup({:?}), \"{}\");\n", - if truthy { "" } else { "!" }, - property.to_lowercase(), - std::char::from_u32(range.start).unwrap(), - range.start, - )); - } else { - s.push_str(&format!(" for chn in {range:?}u32 {{\n")); - s.push_str(&format!( - " assert!({}unicode_data::{}::lookup(std::char::from_u32(chn).unwrap()), \"{{:?}}\", chn);\n", - if truthy { "" } else { "!" }, - property.to_lowercase(), - )); - s.push_str(" }\n"); + for (name, conversion) in ["to_lower", "to_upper"].iter().zip([&data.to_lower, &data.to_upper]) + { + writeln!(s, r#" println!("Testing {name}");"#)?; + for (c, mapping) in conversion { + let c = char::from_u32(*c).unwrap(); + let mapping = mapping.map(|c| char::from_u32(c).unwrap()); + writeln!( + s, + r#" assert_eq!(unicode_data::conversions::{name}({c:?}), {mapping:?});"# + )?; + } + let unmapped: Vec<_> = (char::MIN..=char::MAX) + .filter(|c| !c.is_ascii()) + .map(u32::from) + .filter(|c| !conversion.contains_key(c)) + .collect(); + let unmapped_ranges = ranges_from_set(&unmapped); + for range in unmapped_ranges { + let start = char::from_u32(range.start).unwrap(); + let end = char::from_u32(range.end - 1).unwrap(); + writeln!(s, " for c in {start:?}..={end:?} {{")?; + writeln!( + s, + r#" assert_eq!(unicode_data::conversions::{name}(c), [c, '\0', '\0']);"# + )?; + + writeln!(s, " }}")?; } } -} -fn ranges_from_set(set: &[u32]) -> Vec<Range<u32>> { - let mut ranges = set.iter().map(|e| (*e)..(*e + 1)).collect::<Vec<Range<u32>>>(); - merge_ranges(&mut ranges); - ranges + writeln!(s, "}}")?; + Ok(s) } -fn merge_ranges(ranges: &mut Vec<Range<u32>>) { - loop { - let mut new_ranges = Vec::new(); - let mut idx_iter = 0..(ranges.len() - 1); - let mut should_insert_last = true; - while let Some(idx) = idx_iter.next() { - let cur = ranges[idx].clone(); - let next = ranges[idx + 1].clone(); - if cur.end == next.start { - if idx_iter.next().is_none() { - // We're merging the last element - should_insert_last = false; - } - new_ranges.push(cur.start..next.end); - } else { - // We're *not* merging the last element - should_insert_last = true; - new_ranges.push(cur); +fn generate_asserts( + s: &mut String, + prop: &str, + points: &[u32], + truthy: bool, +) -> Result<(), fmt::Error> { + let truthy = if truthy { "" } else { "!" }; + for range in ranges_from_set(points) { + let start = char::from_u32(range.start).unwrap(); + let end = char::from_u32(range.end - 1).unwrap(); + match range.len() { + 1 => writeln!(s, " assert!({truthy}unicode_data::{prop}::lookup({start:?}));")?, + _ => { + writeln!(s, " for c in {start:?}..={end:?} {{")?; + writeln!(s, " assert!({truthy}unicode_data::{prop}::lookup(c));")?; + writeln!(s, " }}")?; } } - if should_insert_last { - new_ranges.push(ranges.last().unwrap().clone()); - } - if new_ranges.len() == ranges.len() { - *ranges = new_ranges; - break; - } else { - *ranges = new_ranges; - } } + Ok(()) +} - let mut last_end = None; - for range in ranges { - if let Some(last) = last_end { - assert!(range.start > last, "{range:?}"); - } - last_end = Some(range.end); - } +/// Group the elements of `set` into contigous ranges +fn ranges_from_set(set: &[u32]) -> Vec<Range<u32>> { + set.chunk_by(|a, b| a + 1 == *b) + .map(|chunk| { + let start = *chunk.first().unwrap(); + let end = *chunk.last().unwrap(); + start..(end + 1) + }) + .collect() } diff --git a/tests/run-make/multiline-args-value/cfg.stderr b/tests/run-make/multiline-args-value/cfg.stderr new file mode 100644 index 00000000000..9b06f84be48 --- /dev/null +++ b/tests/run-make/multiline-args-value/cfg.stderr @@ -0,0 +1,4 @@ +error: invalid `--cfg` argument: `--- + --- + key` (expected `key` or `key="value"`) + diff --git a/tests/run-make/multiline-args-value/check-cfg.stderr b/tests/run-make/multiline-args-value/check-cfg.stderr new file mode 100644 index 00000000000..4a499cc0a1e --- /dev/null +++ b/tests/run-make/multiline-args-value/check-cfg.stderr @@ -0,0 +1,7 @@ +error: invalid `--check-cfg` argument: `--- + --- + cfg(key)` + | + = note: expected `cfg(name, values("value1", "value2", ... "valueN"))` + = note: visit <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more details + diff --git a/tests/run-make/multiline-args-value/rmake.rs b/tests/run-make/multiline-args-value/rmake.rs new file mode 100644 index 00000000000..825cbd158c0 --- /dev/null +++ b/tests/run-make/multiline-args-value/rmake.rs @@ -0,0 +1,34 @@ +use run_make_support::{cwd, diff, rustc}; + +fn test_and_compare(flag: &str, val: &str) { + let mut cmd = rustc(); + + let output = + cmd.input("").arg("--crate-type=lib").arg(&format!("--{flag}")).arg(val).run_fail(); + + assert_eq!(output.stdout_utf8(), ""); + diff() + .expected_file(format!("{flag}.stderr")) + .actual_text("output", output.stderr_utf8()) + .run(); +} + +fn main() { + // Verify that frontmatter isn't allowed in `--cfg` arguments. + // https://github.com/rust-lang/rust/issues/146130 + test_and_compare( + "cfg", + r#"--- +--- +key"#, + ); + + // Verify that frontmatter isn't allowed in `--check-cfg` arguments. + // https://github.com/rust-lang/rust/issues/146130 + test_and_compare( + "check-cfg", + r#"--- +--- +cfg(key)"#, + ); +} diff --git a/tests/run-make/rustdoc-dep-info/rmake.rs b/tests/run-make/rustdoc-dep-info/rmake.rs index 625f81fd428..166e8d5702f 100644 --- a/tests/run-make/rustdoc-dep-info/rmake.rs +++ b/tests/run-make/rustdoc-dep-info/rmake.rs @@ -33,4 +33,16 @@ fn main() { // Now we check that we can provide a file name to the `dep-info` argument. rustdoc().input("lib.rs").arg("-Zunstable-options").emit("dep-info=bla.d").run(); assert!(path("bla.d").exists()); + + // The last emit-type wins. The same behavior as rustc. + rustdoc() + .input("lib.rs") + .arg("-Zunstable-options") + .emit("dep-info=precedence1.d") + .emit("dep-info=precedence2.d") + .emit("dep-info=precedence3.d") + .run(); + assert!(!path("precedence1.d").exists()); + assert!(!path("precedence2.d").exists()); + assert!(path("precedence3.d").exists()); } diff --git a/tests/run-make/rustdoc-search-load-itemtype/bar.rs b/tests/run-make/rustdoc-search-load-itemtype/bar.rs new file mode 100644 index 00000000000..0416b1b75b5 --- /dev/null +++ b/tests/run-make/rustdoc-search-load-itemtype/bar.rs @@ -0,0 +1,27 @@ +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +//@ has bar/macro.a_procmacro.html +//@ hasraw search.index/name/*.js a_procmacro +#[proc_macro] +pub fn a_procmacro(_: TokenStream) -> TokenStream { + unimplemented!() +} + +//@ has bar/attr.a_procattribute.html +//@ hasraw search.index/name/*.js a_procattribute +#[proc_macro_attribute] +pub fn a_procattribute(_: TokenStream, _: TokenStream) -> TokenStream { + unimplemented!() +} + +//@ has bar/derive.AProcDerive.html +//@ !has bar/derive.a_procderive.html +//@ hasraw search.index/name/*.js AProcDerive +//@ !hasraw search.index/name/*.js a_procderive +#[proc_macro_derive(AProcDerive)] +pub fn a_procderive(_: TokenStream) -> TokenStream { + unimplemented!() +} diff --git a/tests/run-make/rustdoc-search-load-itemtype/baz.rs b/tests/run-make/rustdoc-search-load-itemtype/baz.rs new file mode 100644 index 00000000000..4d1f5430fc6 --- /dev/null +++ b/tests/run-make/rustdoc-search-load-itemtype/baz.rs @@ -0,0 +1,3 @@ +//@ has baz/struct.Baz.html +//@ hasraw search.index/name/*.js Baz +pub struct Baz; diff --git a/tests/run-make/rustdoc-search-load-itemtype/foo.rs b/tests/run-make/rustdoc-search-load-itemtype/foo.rs new file mode 100644 index 00000000000..93b372d10cb --- /dev/null +++ b/tests/run-make/rustdoc-search-load-itemtype/foo.rs @@ -0,0 +1,119 @@ +#![feature(extern_types, rustc_attrs, rustdoc_internals, trait_alias)] +#![allow(internal_features)] +#![no_std] + +//@ has foo/keyword.while.html +//@ hasraw search.index/name/*.js while +//@ !hasraw search.index/name/*.js w_keyword +#[doc(keyword = "while")] +mod w_keyword {} + +//@ has foo/primitive.u32.html +//@ hasraw search.index/name/*.js u32 +//@ !hasraw search.index/name/*.js u_primitive +#[rustc_doc_primitive = "u32"] +mod u_primitive {} + +//@ has foo/x_mod/index.html +//@ hasraw search.index/name/*.js x_mod +pub mod x_mod {} + +//@ hasraw foo/index.html y_crate +//@ hasraw search.index/name/*.js y_crate +#[doc(no_inline)] +pub extern crate core as y_crate; + +//@ hasraw foo/index.html z_import +//@ hasraw search.index/name/*.js z_import +#[doc(no_inline)] +pub use core::option as z_import; + +//@ has foo/struct.AStruct.html +//@ hasraw search.index/name/*.js AStruct +pub struct AStruct { + //@ hasraw foo/struct.AStruct.html a_structfield + //@ hasraw search.index/name/*.js a_structfield + pub a_structfield: i32, +} + +//@ has foo/enum.AEnum.html +//@ hasraw search.index/name/*.js AEnum +pub enum AEnum { + //@ hasraw foo/enum.AEnum.html AVariant + //@ hasraw search.index/name/*.js AVariant + AVariant, +} + +//@ has foo/fn.a_fn.html +//@ hasraw search.index/name/*.js a_fn +pub fn a_fn() {} + +//@ has foo/type.AType.html +//@ hasraw search.index/name/*.js AType +pub type AType = AStruct; + +//@ has foo/static.a_static.html +//@ hasraw search.index/name/*.js a_static +pub static a_static: i32 = 1; + +//@ has foo/trait.ATrait.html +//@ hasraw search.index/name/*.js ATrait +pub trait ATrait { + //@ hasraw foo/trait.ATrait.html a_tymethod + //@ hasraw search.index/name/*.js a_tymethod + fn a_tymethod(); + //@ hasraw foo/trait.ATrait.html AAssocType + //@ hasraw search.index/name/*.js AAssocType + type AAssocType; + //@ hasraw foo/trait.ATrait.html AAssocConst + //@ hasraw search.index/name/*.js AAssocConst + const AAssocConst: bool; +} + +// skip ItemType::Impl, since impls are anonymous +// and have no search entry + +impl AStruct { + //@ hasraw foo/struct.AStruct.html a_method + //@ hasraw search.index/name/*.js a_method + pub fn a_method() {} +} + +//@ has foo/macro.a_macro.html +//@ hasraw search.index/name/*.js a_macro +#[macro_export] +macro_rules! a_macro { + () => {}; +} + +//@ has foo/constant.A_CONSTANT.html +//@ hasraw search.index/name/*.js A_CONSTANT +pub const A_CONSTANT: i32 = 1; + +//@ has foo/union.AUnion.html +//@ hasraw search.index/name/*.js AUnion +pub union AUnion { + //@ hasraw foo/union.AUnion.html a_unionfield + //@ hasraw search.index/name/*.js a_unionfield + pub a_unionfield: i32, +} + +extern "C" { + //@ has foo/foreigntype.AForeignType.html + //@ hasraw search.index/name/*.js AForeignType + pub type AForeignType; +} + +// procattribute and procderive are defined in +// bar.rs, because they only work with proc_macro +// crate type. + +//@ has foo/traitalias.ATraitAlias.html +//@ hasraw search.index/name/*.js ATraitAlias +pub trait ATraitAlias = ATrait; + +//@ has foo/attribute.doc.html +//@ hasraw search.index/name/*.js doc +//@ !hasraw search.index/name/*.js aa_mod +#[doc(attribute = "doc")] +mod aa_mod {} diff --git a/tests/run-make/rustdoc-search-load-itemtype/rmake.rs b/tests/run-make/rustdoc-search-load-itemtype/rmake.rs new file mode 100644 index 00000000000..803eb8a61da --- /dev/null +++ b/tests/run-make/rustdoc-search-load-itemtype/rmake.rs @@ -0,0 +1,21 @@ +//@ ignore-cross-compile +//@ needs-crate-type: proc-macro + +// Test that rustdoc can deserialize a search index with every itemtype. +// https://github.com/rust-lang/rust/pull/146117 + +use std::path::Path; + +use run_make_support::{htmldocck, rfs, rustdoc, source_root}; + +fn main() { + let out_dir = Path::new("rustdoc-search-load-itemtype"); + + rfs::create_dir_all(&out_dir); + rustdoc().out_dir(&out_dir).input("foo.rs").run(); + rustdoc().out_dir(&out_dir).input("bar.rs").arg("--crate-type=proc-macro").run(); + rustdoc().out_dir(&out_dir).input("baz.rs").run(); + htmldocck().arg(out_dir).arg("foo.rs").run(); + htmldocck().arg(out_dir).arg("bar.rs").run(); + htmldocck().arg(out_dir).arg("baz.rs").run(); +} diff --git a/tests/run-make/separate-link-fail/rmake.rs b/tests/run-make/separate-link-fail/rmake.rs index b5d5300de68..ba24f777395 100644 --- a/tests/run-make/separate-link-fail/rmake.rs +++ b/tests/run-make/separate-link-fail/rmake.rs @@ -11,5 +11,5 @@ fn main() { .arg("-Zlink-only") .input("foo.rs") .run_fail() - .assert_stderr_contains("The input does not look like a .rlink file"); + .assert_stderr_contains("the input does not look like a .rlink file"); } diff --git a/tests/ui/.gitattributes b/tests/ui/.gitattributes index 9ea3d3fb0e1..4923ac100e1 100644 --- a/tests/ui/.gitattributes +++ b/tests/ui/.gitattributes @@ -3,4 +3,5 @@ json-bom-plus-crlf.rs -text json-bom-plus-crlf-multifile.rs -text json-bom-plus-crlf-multifile-aux.rs -text trailing-carriage-return-in-string.rs -text +frontmatter-crlf.rs -text *.bin -text diff --git a/tests/ui/codegen/empty-static-libs-issue-108825.rs b/tests/ui/codegen/empty-static-libs-issue-108825.rs index 4c644be0954..4f8e4420f72 100644 --- a/tests/ui/codegen/empty-static-libs-issue-108825.rs +++ b/tests/ui/codegen/empty-static-libs-issue-108825.rs @@ -15,4 +15,4 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { } //~? NOTE native-static-libs: -//~? NOTE Link against the following native artifacts when linking against this static library +//~? NOTE link against the following native artifacts when linking against this static library diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index 0c57eddbe93..cc6a813b747 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -14,7 +14,7 @@ error[E0080]: constructing invalid value: encountered 0x42, but expected a boole LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 42 │ B } @@ -25,7 +25,7 @@ error[E0080]: constructing invalid value: encountered 0x42, but expected a boole LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 42 │ B } diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index 0c57eddbe93..cc6a813b747 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -14,7 +14,7 @@ error[E0080]: constructing invalid value: encountered 0x42, but expected a boole LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 42 │ B } @@ -25,7 +25,7 @@ error[E0080]: constructing invalid value: encountered 0x42, but expected a boole LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 42 │ B } diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index 25d6f0461a9..70ae00af23f 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a null reference LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered a null reference LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -50,7 +50,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -61,7 +61,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -72,7 +72,7 @@ error[E0080]: constructing invalid value at .<deref>[1]: encountered uninitializ LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -83,7 +83,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin LL | pub static S8: &[u64] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -94,7 +94,7 @@ error[E0080]: constructing invalid value: encountered a null reference LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -117,7 +117,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -130,7 +130,7 @@ LL | pub static R5: &[u8] = unsafe { | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -141,7 +141,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -152,7 +152,7 @@ error[E0080]: constructing invalid value: encountered an unaligned reference (re LL | pub static R7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr index a8c7ee93971..239bca51fc9 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized LL | const BAR: &i32 = unsafe { | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC0<imm>╼ │ ╾──╼ } diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr index 47e1c22cc2c..3c6d66ac5b6 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized LL | const BAR: &i32 = unsafe { | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC0<imm>╼ │ ╾──────╼ } diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr index d4039e1952c..152eeababc5 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (use- LL | const _X: &'static u8 = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index 36183e28921..2861f82ec53 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x00000001, LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 01 00 00 00 │ .... } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x00000000, LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 01 │ . } @@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 03 │ . } @@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0.1: encounter LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { 78 00 00 00 ff ff ff ff │ x....... } @@ -59,7 +59,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } @@ -70,7 +70,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some LL | const NULL_U8: NonZero<u8> = unsafe { mem::transmute(0u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 00 │ . } @@ -81,7 +81,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } @@ -92,7 +92,7 @@ error[E0080]: constructing invalid value: encountered 42, but expected something LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 2a 00 00 00 │ *... } @@ -103,7 +103,7 @@ error[E0080]: constructing invalid value: encountered 20, but expected something LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 14 00 00 00 │ .... } @@ -114,7 +114,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { 00 00 00 00 ╾ALLOC_ID╼ │ ....╾──╼ } @@ -125,7 +125,7 @@ error[E0080]: constructing invalid value: encountered an unaligned reference (re LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC_ID╼ │ ╾──╼ } @@ -136,7 +136,7 @@ error[E0080]: constructing invalid value: encountered an unaligned box (required LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC_ID╼ │ ╾──╼ } @@ -147,7 +147,7 @@ error[E0080]: constructing invalid value: encountered a null reference LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } @@ -158,7 +158,7 @@ error[E0080]: constructing invalid value: encountered a null box LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } @@ -169,7 +169,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (0x53 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 39 05 00 00 │ 9... } @@ -180,7 +180,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (0x539[noal LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 39 05 00 00 │ 9... } @@ -191,7 +191,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 00 00 00 00 │ .... } @@ -202,7 +202,7 @@ error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 0d 00 00 00 │ .... } @@ -213,7 +213,7 @@ error[E0080]: constructing invalid value: encountered ALLOC3<imm>, but expected LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC_ID╼ │ ╾──╼ } @@ -224,7 +224,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 01 00 00 00 │ .... } @@ -235,7 +235,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... } @@ -246,7 +246,7 @@ error[E0080]: constructing invalid value at .0: encountered invalid reference me LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼.... } @@ -257,7 +257,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ff ff ff ff │ ╾──╼.... } @@ -268,7 +268,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } @@ -279,7 +279,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered uninitialize LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } @@ -292,7 +292,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _> | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } @@ -303,7 +303,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... } @@ -314,7 +314,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ff ff ff 7f │ ╾──╼.... } @@ -325,7 +325,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (going beyo LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ e7 03 00 00 │ ╾──╼.... } @@ -336,7 +336,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x03, but e LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC_ID╼ │ ╾──╼ } @@ -353,7 +353,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered 0x03, but ex LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC_ID╼ │ ╾──╼ } @@ -370,7 +370,7 @@ error[E0080]: constructing invalid value at .<deref>.1[0]: encountered 0x03, but LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC_ID╼ │ ╾──╼ } @@ -387,7 +387,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC17<imm>, but ex LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } @@ -398,7 +398,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC19<imm>, but ex LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } @@ -409,7 +409,7 @@ error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but ex LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } @@ -420,7 +420,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC22<imm>, but ex LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } @@ -431,7 +431,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>: encountered LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } @@ -442,7 +442,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 00 00 00 00 │ ╾──╼.... } @@ -453,7 +453,7 @@ error[E0080]: constructing invalid value: encountered ALLOC27<imm>, but expected LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } @@ -464,7 +464,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 01 00 00 00 │ .... } @@ -475,7 +475,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { 01 00 00 00 01 00 00 00 │ ........ } @@ -486,7 +486,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; | ^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { 01 00 00 00 2a 00 00 00 │ ....*... } @@ -497,7 +497,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } @@ -510,7 +510,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } @@ -521,7 +521,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } @@ -532,7 +532,7 @@ error[E0080]: constructing invalid value at .<deref>[1]: encountered uninitializ LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID+0x2╼ 04 00 00 00 │ ╾──╼.... } @@ -543,7 +543,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 01 00 00 00 │ ╾──╼.... } @@ -556,7 +556,7 @@ LL | pub static R5: &[u8] = unsafe { | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } @@ -567,7 +567,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index c53326534fd..8e6dc66a40e 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x000000000 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 01 00 00 00 00 00 00 00 │ ........ } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x000000000 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 01 │ . } @@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 03 │ . } @@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0.1: encounter LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { 78 00 00 00 ff ff ff ff │ x....... } @@ -59,7 +59,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } @@ -70,7 +70,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some LL | const NULL_U8: NonZero<u8> = unsafe { mem::transmute(0u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 00 │ . } @@ -81,7 +81,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } @@ -92,7 +92,7 @@ error[E0080]: constructing invalid value: encountered 42, but expected something LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 2a 00 00 00 │ *... } @@ -103,7 +103,7 @@ error[E0080]: constructing invalid value: encountered 20, but expected something LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { 14 00 00 00 │ .... } @@ -114,7 +114,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { 00 00 00 00 00 00 00 00 ╾ALLOC_ID╼ │ ........╾──────╼ } @@ -125,7 +125,7 @@ error[E0080]: constructing invalid value: encountered an unaligned reference (re LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC_ID╼ │ ╾──────╼ } @@ -136,7 +136,7 @@ error[E0080]: constructing invalid value: encountered an unaligned box (required LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC_ID╼ │ ╾──────╼ } @@ -147,7 +147,7 @@ error[E0080]: constructing invalid value: encountered a null reference LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } @@ -158,7 +158,7 @@ error[E0080]: constructing invalid value: encountered a null box LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } @@ -169,7 +169,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (0x53 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 39 05 00 00 00 00 00 00 │ 9....... } @@ -180,7 +180,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (0x539[noal LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 39 05 00 00 00 00 00 00 │ 9....... } @@ -191,7 +191,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 00 00 00 00 00 00 00 00 │ ........ } @@ -202,7 +202,7 @@ error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 0d 00 00 00 00 00 00 00 │ ........ } @@ -213,7 +213,7 @@ error[E0080]: constructing invalid value: encountered ALLOC3<imm>, but expected LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC_ID╼ │ ╾──────╼ } @@ -224,7 +224,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 01 00 00 00 00 00 00 00 │ ........ } @@ -235,7 +235,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ } @@ -246,7 +246,7 @@ error[E0080]: constructing invalid value at .0: encountered invalid reference me LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ } @@ -257,7 +257,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ } @@ -268,7 +268,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -279,7 +279,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered uninitialize LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -292,7 +292,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _> | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -303,7 +303,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ } @@ -314,7 +314,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ff ff ff ff ff ff ff 7f │ ╾──────╼........ } @@ -325,7 +325,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (going beyo LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ e7 03 00 00 00 00 00 00 │ ╾──────╼........ } @@ -336,7 +336,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x03, but e LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC_ID╼ │ ╾──────╼ } @@ -353,7 +353,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered 0x03, but ex LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC_ID╼ │ ╾──────╼ } @@ -370,7 +370,7 @@ error[E0080]: constructing invalid value at .<deref>.1[0]: encountered 0x03, but LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC_ID╼ │ ╾──────╼ } @@ -387,7 +387,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC17<imm>, but ex LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } @@ -398,7 +398,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC19<imm>, but ex LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } @@ -409,7 +409,7 @@ error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but ex LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -420,7 +420,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC22<imm>, but ex LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } @@ -431,7 +431,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>: encountered LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } @@ -442,7 +442,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -453,7 +453,7 @@ error[E0080]: constructing invalid value: encountered ALLOC27<imm>, but expected LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } @@ -464,7 +464,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { 01 00 00 00 00 00 00 00 │ ........ } @@ -475,7 +475,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ } @@ -486,7 +486,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; | ^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { 01 00 00 00 00 00 00 00 2a 00 00 00 00 00 00 00 │ ........*....... } @@ -497,7 +497,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -510,7 +510,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -521,7 +521,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -532,7 +532,7 @@ error[E0080]: constructing invalid value at .<deref>[1]: encountered uninitializ LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID+0x2╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -543,7 +543,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered uninitializ LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -556,7 +556,7 @@ LL | pub static R5: &[u8] = unsafe { | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........ } @@ -567,7 +567,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x11, but e LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } diff --git a/tests/ui/consts/const-eval/transmute-const.stderr b/tests/ui/consts/const-eval/transmute-const.stderr index ed3b3df70dd..53665c176a7 100644 --- a/tests/ui/consts/const-eval/transmute-const.stderr +++ b/tests/ui/consts/const-eval/transmute-const.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered 0x03, but expected a boole LL | static FOO: bool = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 03 │ . } diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr index 5cbd6176c92..1efd9383229 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x01, but e LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -33,7 +33,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered 0x0, but ex LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -81,7 +81,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -92,7 +92,7 @@ error[E0080]: constructing invalid value at .<enum-tag>: encountered an uninhabi LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -103,7 +103,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0.1: encounter LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr index 86d6f8c52bc..1e4d425d78e 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered ALLOC1<imm>, but expected LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──╼╾──╼ } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered ALLOC3<imm>, but expected LL | const INVALID_VTABLE_SIZE: &dyn Trait = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──╼╾──╼ } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC5<imm>, but exp LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──╼╾──╼ } @@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC7<imm>, but exp LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼ │ ╾──╼╾──╼ } @@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC9<imm>, but exp LL | const INVALID_VTABLE_UB: W<&dyn Trait> = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼ │ ╾──╼╾──╼ } @@ -59,7 +59,7 @@ error[E0080]: constructing invalid value at .1: encountered a dangling reference LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; | ^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC10<imm>╼ ╾ALLOC11╼ │ ╾──╼╾──╼ } diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr index a9518216dbd..a068991f324 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered ALLOC1<imm>, but expected LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──────╼╾──────╼ } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered ALLOC3<imm>, but expected LL | const INVALID_VTABLE_SIZE: &dyn Trait = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──────╼╾──────╼ } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC5<imm>, but exp LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──────╼╾──────╼ } @@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC7<imm>, but exp LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼ │ ╾──────╼╾──────╼ } @@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC9<imm>, but exp LL | const INVALID_VTABLE_UB: W<&dyn Trait> = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼ │ ╾──────╼╾──────╼ } @@ -59,7 +59,7 @@ error[E0080]: constructing invalid value at .1: encountered a dangling reference LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; | ^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC10<imm>╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼ } diff --git a/tests/ui/consts/const-eval/ub-int-array.stderr b/tests/ui/consts/const-eval/ub-int-array.stderr index 10eb7c46c92..065bfd2c304 100644 --- a/tests/ui/consts/const-eval/ub-int-array.stderr +++ b/tests/ui/consts/const-eval/ub-int-array.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at [0]: encountered uninitialized memor LL | const UNINIT_INT_0: [u32; 3] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { __ __ __ __ 11 11 11 11 22 22 22 22 │ ░░░░...."""" } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at [1]: encountered uninitialized memor LL | const UNINIT_INT_1: [u32; 3] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { 00 00 00 00 01 __ 01 01 02 02 __ 02 │ .....░....░. } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at [2]: encountered uninitialized memor LL | const UNINIT_INT_2: [u32; 3] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { 00 00 00 00 01 01 01 01 02 02 02 __ │ ...........░ } diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 19ae66cf3c6..91c82efbc5e 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -21,7 +21,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some LL | const NULL_U8: NonZero<u8> = unsafe { mem::transmute(0u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -32,7 +32,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some LL | const NULL_USIZE: NonZero<usize> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -53,7 +53,7 @@ error[E0080]: constructing invalid value: encountered 42, but expected something LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -64,7 +64,7 @@ error[E0080]: constructing invalid value: encountered 20, but expected something LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -75,7 +75,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index 451ebb6eba1..c45f66c2925 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered an unaligned reference (re LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered an unaligned box (required LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value: encountered a null reference LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -37,7 +37,7 @@ error[E0080]: constructing invalid value: encountered a null box LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -87,7 +87,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (0x53 LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -98,7 +98,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (0x539[noal LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -119,7 +119,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -140,7 +140,7 @@ error[E0080]: constructing invalid value: encountered 0xd[noalloc], but expected LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -151,7 +151,7 @@ error[E0080]: constructing invalid value: encountered ALLOC2<imm>, but expected LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/const-eval/ub-uninhabit.stderr b/tests/ui/consts/const-eval/ub-uninhabit.stderr index b0f475fe938..aca0b13bb90 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.stderr +++ b/tests/ui/consts/const-eval/ub-uninhabit.stderr @@ -10,7 +10,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr index ecd1c768c28..b434970b677 100644 --- a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>.<captured-va LL | const BAD_UPVAR: &dyn FnOnce() = &{ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──╼╾──╼ } diff --git a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr index 108dfe6b27b..de1e1f8a2be 100644 --- a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>.<captured-va LL | const BAD_UPVAR: &dyn FnOnce() = &{ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ } diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index ab15ba826a5..c505e5cc8a2 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at .0: encountered invalid reference me LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -44,7 +44,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -55,7 +55,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -66,7 +66,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered uninitialize LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -87,7 +87,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (goin LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -98,7 +98,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -118,7 +118,7 @@ error[E0080]: constructing invalid value: encountered a dangling box (going beyo LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -138,7 +138,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered 0x03, but e LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -155,7 +155,7 @@ error[E0080]: constructing invalid value at .<deref>.0: encountered 0x03, but ex LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -172,7 +172,7 @@ error[E0080]: constructing invalid value at .<deref>.1[0]: encountered 0x03, but LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -199,7 +199,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC12<imm>, but ex LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -210,7 +210,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC14<imm>, but ex LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -221,7 +221,7 @@ error[E0080]: constructing invalid value at .0: encountered 0x4[noalloc], but ex LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -232,7 +232,7 @@ error[E0080]: constructing invalid value: encountered ALLOC17<imm>, but expected LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -243,7 +243,7 @@ error[E0080]: constructing invalid value: encountered ALLOC19<imm>, but expected LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -254,7 +254,7 @@ error[E0080]: constructing invalid value: encountered ALLOC21<imm>, but expected LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -265,7 +265,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC23<imm>, but ex LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -276,7 +276,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>: encountered LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -287,7 +287,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -298,7 +298,7 @@ error[E0080]: constructing invalid value: encountered ALLOC28<imm>, but expected LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -309,7 +309,7 @@ error[E0080]: constructing invalid value: encountered null pointer, but expected LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -320,7 +320,7 @@ error[E0080]: constructing invalid value: encountered ALLOC31<imm>, but expected LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/const-eval/union-ub.32bit.stderr b/tests/ui/consts/const-eval/union-ub.32bit.stderr index 757bcea91c3..fb2311b9921 100644 --- a/tests/ui/consts/const-eval/union-ub.32bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.32bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered 0x2a, but expected a boole LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool }; | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 2a │ * } diff --git a/tests/ui/consts/const-eval/union-ub.64bit.stderr b/tests/ui/consts/const-eval/union-ub.64bit.stderr index 757bcea91c3..fb2311b9921 100644 --- a/tests/ui/consts/const-eval/union-ub.64bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.64bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered 0x2a, but expected a boole LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool }; | ^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { 2a │ * } diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr index 16dee44d800..08656776468 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final.stderr @@ -34,7 +34,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p LL | const IMMUT_MUT_REF: &mut u16 = unsafe { mem::transmute(&13) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -45,7 +45,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p LL | static IMMUT_MUT_REF_STATIC: &mut u16 = unsafe { mem::transmute(&13) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr index 302e342bce6..96263998ad4 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered LL | const MUT: Option<&mut i32> = helper(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered LL | const INT2PTR: Option<&mut i32> = helper_int2ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered LL | static INT2PTR_STATIC: Option<&mut i32> = helper_int2ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered LL | const DANGLING: Option<&mut i32> = helper_dangling(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered LL | static DANGLING_STATIC: Option<&mut i32> = helper_dangling(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr index 8be8b4bc50f..f9088c318a6 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered 0x0a, but expe LL | const C: &bool = unsafe { std::mem::transmute(&S) }; | ^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/dangling-alloc-id-ice.stderr b/tests/ui/consts/dangling-alloc-id-ice.stderr index 65a46b62dae..4b034c81a61 100644 --- a/tests/ui/consts/dangling-alloc-id-ice.stderr +++ b/tests/ui/consts/dangling-alloc-id-ice.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (use- LL | const FOO: &() = { | ^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/dangling-zst-ice-issue-126393.stderr b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr index 2f600e494c4..248db694d52 100644 --- a/tests/ui/consts/dangling-zst-ice-issue-126393.stderr +++ b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a dangling reference (use- LL | pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/interior-mut-const-via-union.32bit.stderr b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr index 47bb2e5e879..17b32383912 100644 --- a/tests/ui/consts/interior-mut-const-via-union.32bit.stderr +++ b/tests/ui/consts/interior-mut-const-via-union.32bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.y.<enum-variant(B)>.0: enco LL | fn main() { | ^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC0╼ │ ╾──╼ } diff --git a/tests/ui/consts/interior-mut-const-via-union.64bit.stderr b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr index b4c9a4bd47e..c4f78e7bf9e 100644 --- a/tests/ui/consts/interior-mut-const-via-union.64bit.stderr +++ b/tests/ui/consts/interior-mut-const-via-union.64bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.y.<enum-variant(B)>.0: enco LL | fn main() { | ^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC0╼ │ ╾──────╼ } diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index 68d1a72b71e..2c54200c8a2 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -14,7 +14,7 @@ error[E0080]: constructing invalid value: encountered mutable reference in `cons LL | const C2: &'static mut i32 = unsafe { &mut S }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $PTR, align: $PTR) { HEX_DUMP } diff --git a/tests/ui/consts/issue-63952.32bit.stderr b/tests/ui/consts/issue-63952.32bit.stderr index e5340788167..cf97ed6e487 100644 --- a/tests/ui/consts/issue-63952.32bit.stderr +++ b/tests/ui/consts/issue-63952.32bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { ╾ALLOC0<imm>╼ ff ff ff ff │ ╾──╼.... } diff --git a/tests/ui/consts/issue-63952.64bit.stderr b/tests/ui/consts/issue-63952.64bit.stderr index 27e74833fc5..4cea967314c 100644 --- a/tests/ui/consts/issue-63952.64bit.stderr +++ b/tests/ui/consts/issue-63952.64bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered invalid reference metadata LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC0<imm>╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ } diff --git a/tests/ui/consts/issue-79690.64bit.stderr b/tests/ui/consts/issue-79690.64bit.stderr index 7488f7b7752..2653ff22f12 100644 --- a/tests/ui/consts/issue-79690.64bit.stderr +++ b/tests/ui/consts/issue-79690.64bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .1: encountered a dangling reference LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; | ^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { ╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ } diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index 137efde44b3..b35076b669e 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered mutable refere LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p LL | static OH_YES: &mut i32 = &mut 42; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -38,7 +38,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p LL | const BLUNT: &mut i32 = &mut 42; | ^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -49,7 +49,7 @@ error[E0080]: constructing invalid value: encountered mutable reference in `cons LL | const SUBTLE: &mut i32 = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -60,7 +60,7 @@ error[E0080]: constructing invalid value at .x.<deref>: encountered `UnsafeCell` LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -71,7 +71,7 @@ error[E0080]: constructing invalid value at .x.<deref>: encountered `UnsafeCell` LL | const MUH: Meh = Meh { | ^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -82,7 +82,7 @@ error[E0080]: constructing invalid value at .<deref>.<dyn-downcast>.x: encounter LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -93,7 +93,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p LL | static mut MUT_TO_READONLY: &mut i32 = unsafe { &mut *(&READONLY as *const _ as *mut _) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr index 1ef20689985..d7c668a9812 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.32bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.v: encountered `UnsafeCell` LL | static REF: &AtomicI32 = &AtomicI32::new(42); | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC0╼ │ ╾──╼ } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p LL | static REFMUT: &mut i32 = &mut 0; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC1╼ │ ╾──╼ } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<deref>.v: encountered `UnsafeCell` LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC2╼ │ ╾──╼ } @@ -37,7 +37,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { ╾ALLOC3╼ │ ╾──╼ } diff --git a/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr index 06f78e679b1..f3bb49900b5 100644 --- a/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/static-no-inner-mut.64bit.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .<deref>.v: encountered `UnsafeCell` LL | static REF: &AtomicI32 = &AtomicI32::new(42); | ^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC0╼ │ ╾──────╼ } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p LL | static REFMUT: &mut i32 = &mut 0; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC1╼ │ ╾──────╼ } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<deref>.v: encountered `UnsafeCell` LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; | ^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC2╼ │ ╾──────╼ } @@ -37,7 +37,7 @@ error[E0080]: constructing invalid value: encountered mutable reference or box p LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; | ^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { ╾ALLOC3╼ │ ╾──────╼ } diff --git a/tests/ui/consts/validate_never_arrays.stderr b/tests/ui/consts/validate_never_arrays.stderr index 0f503df4060..3c405e8d3cd 100644 --- a/tests/ui/consts/validate_never_arrays.stderr +++ b/tests/ui/consts/validate_never_arrays.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered a reference pointing to un LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .<deref>[0]: encountered a value of LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; | ^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/drop/if-let-super-let.rs b/tests/ui/drop/if-let-super-let.rs new file mode 100644 index 00000000000..c6543e6d3dc --- /dev/null +++ b/tests/ui/drop/if-let-super-let.rs @@ -0,0 +1,112 @@ +//! Test for #145328: ensure the lifetime of a `super let` binding within an `if let` scrutinee is +//! at most the scope of the `if` condition's temporaries. Additionally, test `pin!` since it's +//! implemented in terms of `super let` and exposes this behavior. +//@ run-pass +//@ revisions: e2021 e2024 +//@ [e2021] edition: 2021 +//@ [e2024] edition: 2024 + +#![feature(if_let_guard)] +#![feature(super_let)] +#![expect(irrefutable_let_patterns)] + +use std::cell::RefCell; +use std::pin::pin; + +fn main() { + // The `super let` bindings here should have the same scope as `if let` temporaries. + // In Rust 2021, this means it lives past the end of the `if` expression. + // In Rust 2024, this means it lives to the end of the `if`'s success block. + assert_drop_order(0..=2, |o| { + #[cfg(e2021)] + ( + if let _ = { super let _x = o.log(2); } { o.push(0) }, + o.push(1), + ); + #[cfg(e2024)] + ( + if let _ = { super let _x = o.log(1); } { o.push(0) }, + o.push(2), + ); + }); + assert_drop_order(0..=2, |o| { + #[cfg(e2021)] + ( + if let true = { super let _x = o.log(2); false } {} else { o.push(0) }, + o.push(1), + ); + #[cfg(e2024)] + ( + if let true = { super let _x = o.log(0); false } {} else { o.push(1) }, + o.push(2), + ); + }); + + // `pin!` should behave likewise. + assert_drop_order(0..=2, |o| { + #[cfg(e2021)] (if let _ = pin!(o.log(2)) { o.push(0) }, o.push(1)); + #[cfg(e2024)] (if let _ = pin!(o.log(1)) { o.push(0) }, o.push(2)); + }); + assert_drop_order(0..=2, |o| { + #[cfg(e2021)] + ( + if let None = Some(pin!(o.log(2))) {} else { o.push(0) }, + o.push(1), + ); + #[cfg(e2024)] + ( + if let None = Some(pin!(o.log(0))) {} else { o.push(1) }, + o.push(2), + ); + }); + + // `super let` bindings' scope should also be consistent with `if let` temporaries in guards. + // Here, that means the `super let` binding in the second guard condition operand should be + // dropped before the first operand's temporary. This is consistent across Editions. + assert_drop_order(0..=1, |o| { + match () { + _ if let _ = o.log(1) + && let _ = { super let _x = o.log(0); } => {} + _ => unreachable!(), + } + }); + assert_drop_order(0..=1, |o| { + match () { + _ if let _ = o.log(1) + && let _ = pin!(o.log(0)) => {} + _ => unreachable!(), + } + }); +} + +// # Test scaffolding... + +struct DropOrder(RefCell<Vec<u64>>); +struct LogDrop<'o>(&'o DropOrder, u64); + +impl DropOrder { + fn log(&self, n: u64) -> LogDrop<'_> { + LogDrop(self, n) + } + fn push(&self, n: u64) { + self.0.borrow_mut().push(n); + } +} + +impl<'o> Drop for LogDrop<'o> { + fn drop(&mut self) { + self.0.push(self.1); + } +} + +#[track_caller] +fn assert_drop_order( + ex: impl IntoIterator<Item = u64>, + f: impl Fn(&DropOrder), +) { + let order = DropOrder(RefCell::new(Vec::new())); + f(&order); + let order = order.0.into_inner(); + let expected: Vec<u64> = ex.into_iter().collect(); + assert_eq!(order, expected); +} diff --git a/tests/ui/feature-gates/feature-gate-target-feature-inline-always.rs b/tests/ui/feature-gates/feature-gate-target-feature-inline-always.rs new file mode 100644 index 00000000000..181f9a21000 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-target-feature-inline-always.rs @@ -0,0 +1,9 @@ +//@ only-aarch64 +#[inline(always)] +//~^ ERROR cannot use `#[inline(always)]` with `#[target_feature]` +#[target_feature(enable="fp16")] +fn test() { + +} + +fn main() { } diff --git a/tests/ui/feature-gates/feature-gate-target-feature-inline-always.stderr b/tests/ui/feature-gates/feature-gate-target-feature-inline-always.stderr new file mode 100644 index 00000000000..de54844bc29 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-target-feature-inline-always.stderr @@ -0,0 +1,13 @@ +error[E0658]: cannot use `#[inline(always)]` with `#[target_feature]` + --> $DIR/feature-gate-target-feature-inline-always.rs:2:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #145574 <https://github.com/rust-lang/rust/issues/145574> for more information + = help: add `#![feature(target_feature_inline_always)]` 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: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed index b58c3a6720d..14d5de0261d 100644 --- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed +++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.fixed @@ -1,5 +1,5 @@ //@ run-rustfix -#![deny(unused_assignments, unused_variables)] +#![deny(unused_assignments)] #![allow(unused_mut)] struct Object; @@ -8,15 +8,15 @@ fn change_object(object: &mut Object) { //~ HELP you might have meant to mutate *object = object2; //~ ERROR mismatched types } -fn change_object2(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used - //~^ HELP you might have meant to mutate +fn change_object2(object: &mut Object) { + //~^ HELP you might have meant to mutate let object2 = Object; *object = object2; //~^ ERROR `object2` does not live long enough //~| ERROR value assigned to `object` is never read } -fn change_object3(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used +fn change_object3(object: &mut Object) { //~^ HELP you might have meant to mutate let mut object2 = Object; //~ HELP consider changing this to be mutable *object = object2; diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs index 1fd222e0db1..5805afb3369 100644 --- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs +++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs @@ -1,5 +1,5 @@ //@ run-rustfix -#![deny(unused_assignments, unused_variables)] +#![deny(unused_assignments)] #![allow(unused_mut)] struct Object; @@ -8,15 +8,15 @@ fn change_object(mut object: &Object) { //~ HELP you might have meant to mutate object = object2; //~ ERROR mismatched types } -fn change_object2(mut object: &Object) { //~ ERROR variable `object` is assigned to, but never used - //~^ HELP you might have meant to mutate +fn change_object2(mut object: &Object) { + //~^ HELP you might have meant to mutate let object2 = Object; object = &object2; //~^ ERROR `object2` does not live long enough //~| ERROR value assigned to `object` is never read } -fn change_object3(mut object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used +fn change_object3(mut object: &mut Object) { //~^ HELP you might have meant to mutate let object2 = Object; //~ HELP consider changing this to be mutable object = &mut object2; diff --git a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr index 0330853d922..c2c7378f07a 100644 --- a/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr +++ b/tests/ui/fn/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.stderr @@ -23,7 +23,7 @@ LL | object = &object2; note: the lint level is defined here --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:9 | -LL | #![deny(unused_assignments, unused_variables)] +LL | #![deny(unused_assignments)] | ^^^^^^^^^^^^^^^^^^ help: you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding | @@ -33,19 +33,6 @@ LL | let object2 = Object; LL ~ *object = object2; | -error: variable `object` is assigned to, but never used - --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:11:23 - | -LL | fn change_object2(mut object: &Object) { - | ^^^^^^ - | - = note: consider using `_object` instead -note: the lint level is defined here - --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:29 - | -LL | #![deny(unused_assignments, unused_variables)] - | ^^^^^^^^^^^^^^^^ - error[E0597]: `object2` does not live long enough --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:14:13 | @@ -77,14 +64,6 @@ LL | let object2 = Object; LL ~ *object = object2; | -error: variable `object` is assigned to, but never used - --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:19:23 - | -LL | fn change_object3(mut object: &mut Object) { - | ^^^^^^ - | - = note: consider using `_object` instead - error[E0596]: cannot borrow `object2` as mutable, as it is not declared as mutable --> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:22:14 | @@ -96,7 +75,7 @@ help: consider changing this to be mutable LL | let mut object2 = Object; | +++ -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0308, E0596, E0597. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/frontmatter/frontmatter-contains-whitespace.rs b/tests/ui/frontmatter/frontmatter-contains-whitespace.rs new file mode 100644 index 00000000000..11df822f793 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-contains-whitespace.rs @@ -0,0 +1,22 @@ +#!/usr/bin/env -S cargo -Zscript +---cargo +# Beware editing: it has numerous whitespace characters which are important. +# It contains one ranges from the 'PATTERN_WHITE_SPACE' property outlined in +# https://unicode.org/Public/UNIDATA/PropList.txt +# +# The characters in the first expression of the assertion can be generated +# from: "4\u{0C}+\n\t\r7\t*\u{20}2\u{85}/\u{200E}3\u{200F}*\u{2028}2\u{2029}" +package.description = """ +4+ + +7 * 2 /3* 2 +""" +--- + +//@ check-pass + +// Ensure the frontmatter can contain any whitespace + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-crlf.rs b/tests/ui/frontmatter/frontmatter-crlf.rs new file mode 100644 index 00000000000..b46cc9ddbb0 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-crlf.rs @@ -0,0 +1,14 @@ +#!/usr/bin/env -S cargo -Zscript +--- +[dependencies] +clap = "4" +--- + +//@ check-pass +// ignore-tidy-cr + +// crlf line endings should be accepted + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-whitespace-3.rs b/tests/ui/frontmatter/frontmatter-whitespace-3.rs index 95e0981e2ae..6580514fba2 100644 --- a/tests/ui/frontmatter/frontmatter-whitespace-3.rs +++ b/tests/ui/frontmatter/frontmatter-whitespace-3.rs @@ -1,7 +1,7 @@ ----cargo ---- +---cargo +--- // please note the whitespace characters after the first four lines. // This ensures that we accept whitespaces before the frontmatter, after @@ -10,6 +10,7 @@ //@ check-pass // ignore-tidy-end-whitespace // ignore-tidy-leading-newlines +// ignore-tidy-tab #![feature(frontmatter)] diff --git a/tests/ui/frontmatter/frontmatter-whitespace-4.rs b/tests/ui/frontmatter/frontmatter-whitespace-4.rs index 3bda3227838..1e7c5556647 100644 --- a/tests/ui/frontmatter/frontmatter-whitespace-4.rs +++ b/tests/ui/frontmatter/frontmatter-whitespace-4.rs @@ -1,7 +1,8 @@ ---- cargo +--- cargo --- //@ check-pass +// ignore-tidy-tab // A frontmatter infostring can have leading whitespace. #![feature(frontmatter)] diff --git a/tests/ui/imports/overwritten-extern-flag-ambig.rs b/tests/ui/imports/overwritten-extern-flag-ambig.rs new file mode 100644 index 00000000000..80f394d34de --- /dev/null +++ b/tests/ui/imports/overwritten-extern-flag-ambig.rs @@ -0,0 +1,13 @@ +// Test for issue #145575. + +//@ check-pass +//@ edition: 2018 + +extern crate core as std; + +mod inner { + use crate::*; + use std::str; // OK for now +} + +fn main() {} diff --git a/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs index 0c78d799bad..f5f92db3b50 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs @@ -11,4 +11,4 @@ pub fn lib_main() { unsafe { f(42); } } -//~? ERROR Error calling dlltool 'does_not_exist.exe': program not found +//~? ERROR error calling dlltool 'does_not_exist.exe': program not found diff --git a/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.stderr b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.stderr index 4bbad9b30a7..311d8c61589 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.stderr @@ -1,4 +1,4 @@ -error: Error calling dlltool 'does_not_exist.exe': program not found +error: error calling dlltool 'does_not_exist.exe': program not found error: aborting due to 1 previous error diff --git a/tests/ui/linking/mixed-allocator-shim.rs b/tests/ui/linking/mixed-allocator-shim.rs new file mode 100644 index 00000000000..e4f20a11ebb --- /dev/null +++ b/tests/ui/linking/mixed-allocator-shim.rs @@ -0,0 +1,16 @@ +//@ build-pass +//@ compile-flags: --crate-type staticlib,dylib -Zstaticlib-prefer-dynamic +//@ no-prefer-dynamic +//@ needs-crate-type: dylib + +// Test that compiling for multiple crate types in a single compilation with +// mismatching allocator shim requirements doesn't result in the allocator shim +// missing entirely. +// In this particular test the dylib crate type will statically link libstd and +// thus need an allocator shim, while the staticlib crate type will dynamically +// link libstd and thus not need an allocator shim. +// The -Zstaticlib-prefer-dynamic flag could be avoided by doing it the other +// way around, but testing that the staticlib correctly has the allocator shim +// in that case would require a run-make test instead. + +pub fn foo() {} diff --git a/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr b/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr index b0c56003957..e5f2e65fd91 100644 --- a/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr +++ b/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr @@ -16,7 +16,7 @@ warning: unused variable: `Foo` --> $DIR/lint-uppercase-variables.rs:22:9 | LL | Foo => {} - | ^^^ help: if this is intentional, prefix it with an underscore: `_Foo` + | ^^^ | note: the lint level is defined here --> $DIR/lint-uppercase-variables.rs:1:9 @@ -24,12 +24,29 @@ note: the lint level is defined here LL | #![warn(unused)] | ^^^^^^ = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` +help: if this is intentional, prefix it with an underscore + | +LL | _Foo => {} + | + +help: you might have meant to pattern match on the similarly named variant `Foo` + | +LL | foo::Foo::Foo => {} + | ++++++++++ warning: unused variable: `Foo` --> $DIR/lint-uppercase-variables.rs:28:9 | LL | let Foo = foo::Foo::Foo; - | ^^^ help: if this is intentional, prefix it with an underscore: `_Foo` + | ^^^ + | +help: if this is intentional, prefix it with an underscore + | +LL | let _Foo = foo::Foo::Foo; + | + +help: you might have meant to pattern match on the similarly named variant `Foo` + | +LL | let foo::Foo::Foo = foo::Foo::Foo; + | ++++++++++ error[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` --> $DIR/lint-uppercase-variables.rs:33:17 @@ -41,7 +58,16 @@ warning: unused variable: `Foo` --> $DIR/lint-uppercase-variables.rs:33:17 | LL | fn in_param(Foo: foo::Foo) {} - | ^^^ help: if this is intentional, prefix it with an underscore: `_Foo` + | ^^^ + | +help: if this is intentional, prefix it with an underscore + | +LL | fn in_param(_Foo: foo::Foo) {} + | + +help: you might have meant to pattern match on the similarly named variant `Foo` + | +LL | fn in_param(foo::Foo::Foo: foo::Foo) {} + | ++++++++++ error: structure field `X` should have a snake case name --> $DIR/lint-uppercase-variables.rs:10:5 diff --git a/tests/ui/or-patterns/binding-typo-2.rs b/tests/ui/or-patterns/binding-typo-2.rs new file mode 100644 index 00000000000..275b68a22e2 --- /dev/null +++ b/tests/ui/or-patterns/binding-typo-2.rs @@ -0,0 +1,122 @@ +// Issue #51976 +#![deny(unused_variables)] //~ NOTE: the lint level is defined here +enum Lol { + Foo, + Bar, +} +const Bat: () = (); +const Battery: () = (); +struct Bay; + +fn foo(x: (Lol, Lol)) { + use Lol::*; + match &x { + (Foo, Bar) | (Ban, Foo) => {} + //~^ ERROR: variable `Ban` is not bound in all patterns + //~| HELP: you might have meant to use the similarly named previously used binding `Bar` + //~| NOTE: pattern doesn't bind `Ban` + //~| NOTE: variable not in all patterns + //~| ERROR: variable `Ban` is assigned to, but never used + //~| NOTE: consider using `_Ban` instead + //~| HELP: you might have meant to pattern match on the similarly named + _ => {} + } + match &x { + (Foo, _) | (Ban, Foo) => {} + //~^ ERROR: variable `Ban` is not bound in all patterns + //~| HELP: you might have meant to use the similarly named unit variant `Bar` + //~| NOTE: pattern doesn't bind `Ban` + //~| NOTE: variable not in all patterns + //~| ERROR: variable `Ban` is assigned to, but never used + //~| NOTE: consider using `_Ban` instead + //~| HELP: you might have meant to pattern match on the similarly named + _ => {} + } + match Some(42) { + Some(_) => {} + Non => {} + //~^ ERROR: unused variable: `Non` + //~| HELP: if this is intentional, prefix it with an underscore + //~| HELP: you might have meant to pattern match on the similarly named + } + match Some(42) { + Some(_) => {} + Non | None => {} + //~^ ERROR: unused variable: `Non` + //~| HELP: if this is intentional, prefix it with an underscore + //~| ERROR: variable `Non` is not bound in all patterns [E0408] + //~| NOTE: pattern doesn't bind `Non` + //~| NOTE: variable not in all patterns + //~| HELP: you might have meant to use the similarly named unit variant `None` + //~| HELP: you might have meant to pattern match on the similarly named + } + match Some(42) { + Non | Some(_) => {} + //~^ ERROR: unused variable: `Non` + //~| HELP: if this is intentional, prefix it with an underscore + //~| ERROR: variable `Non` is not bound in all patterns [E0408] + //~| NOTE: pattern doesn't bind `Non` + //~| NOTE: variable not in all patterns + //~| HELP: you might have meant to use the similarly named unit variant `None` + //~| HELP: you might have meant to pattern match on the similarly named + } +} +fn bar(x: (Lol, Lol)) { + use Lol::*; + use ::Bat; + use ::Bay; + match &x { + (Foo, _) | (Ban, Foo) => {} + //~^ ERROR: variable `Ban` is not bound in all patterns + //~| HELP: you might have meant to use the similarly named unit variant `Bar` + //~| HELP: you might have meant to use the similarly named unit struct `Bay` + //~| HELP: you might have meant to use the similarly named constant `Bat` + //~| NOTE: pattern doesn't bind `Ban` + //~| NOTE: variable not in all patterns + //~| ERROR: variable `Ban` is assigned to, but never used + //~| NOTE: consider using `_Ban` instead + //~| HELP: you might have meant to pattern match on the similarly named + _ => {} + } +} +fn baz(x: (Lol, Lol)) { + use Lol::*; + use Bat; + match &x { + (Foo, _) | (Ban, Foo) => {} + //~^ ERROR: variable `Ban` is not bound in all patterns + //~| HELP: you might have meant to use the similarly named unit variant `Bar` + //~| HELP: you might have meant to use the similarly named constant `Bat` + //~| NOTE: pattern doesn't bind `Ban` + //~| NOTE: variable not in all patterns + //~| ERROR: variable `Ban` is assigned to, but never used + //~| NOTE: consider using `_Ban` instead + //~| HELP: you might have meant to pattern match on the similarly named + _ => {} + } + match &x { + (Ban, _) => {} + //~^ ERROR: unused variable: `Ban` + //~| HELP: if this is intentional, prefix it with an underscore + //~| HELP: you might have meant to pattern match on the similarly named + } + match Bay { + Ban => {} + //~^ ERROR: unused variable: `Ban` + //~| HELP: if this is intentional, prefix it with an underscore + //~| HELP: you might have meant to pattern match on the similarly named + } + match () { + Batery => {} + //~^ ERROR: unused variable: `Batery` + //~| HELP: if this is intentional, prefix it with an underscore + //~| HELP: you might have meant to pattern match on the similarly named constant + } +} + +fn main() { + use Lol::*; + foo((Foo, Bar)); + bar((Foo, Bar)); + baz((Foo, Bar)); +} diff --git a/tests/ui/or-patterns/binding-typo-2.stderr b/tests/ui/or-patterns/binding-typo-2.stderr new file mode 100644 index 00000000000..81ea6e6b1bc --- /dev/null +++ b/tests/ui/or-patterns/binding-typo-2.stderr @@ -0,0 +1,254 @@ +error[E0408]: variable `Ban` is not bound in all patterns + --> $DIR/binding-typo-2.rs:14:9 + | +LL | (Foo, Bar) | (Ban, Foo) => {} + | ^^^^^^^^^^ --- variable not in all patterns + | | + | pattern doesn't bind `Ban` + | +help: you might have meant to use the similarly named previously used binding `Bar` + | +LL - (Foo, Bar) | (Ban, Foo) => {} +LL + (Foo, Bar) | (Bar, Foo) => {} + | + +error[E0408]: variable `Ban` is not bound in all patterns + --> $DIR/binding-typo-2.rs:25:9 + | +LL | (Foo, _) | (Ban, Foo) => {} + | ^^^^^^^^ --- variable not in all patterns + | | + | pattern doesn't bind `Ban` + | +help: you might have meant to use the similarly named unit variant `Bar` + | +LL - (Foo, _) | (Ban, Foo) => {} +LL + (Foo, _) | (Bar, Foo) => {} + | + +error[E0408]: variable `Non` is not bound in all patterns + --> $DIR/binding-typo-2.rs:44:15 + | +LL | Non | None => {} + | --- ^^^^ pattern doesn't bind `Non` + | | + | variable not in all patterns + | +help: you might have meant to use the similarly named unit variant `None` + | +LL - Non | None => {} +LL + core::option::Option::None | None => {} + | + +error[E0408]: variable `Non` is not bound in all patterns + --> $DIR/binding-typo-2.rs:54:15 + | +LL | Non | Some(_) => {} + | --- ^^^^^^^ pattern doesn't bind `Non` + | | + | variable not in all patterns + | +help: you might have meant to use the similarly named unit variant `None` + | +LL - Non | Some(_) => {} +LL + core::option::Option::None | Some(_) => {} + | + +error[E0408]: variable `Ban` is not bound in all patterns + --> $DIR/binding-typo-2.rs:69:9 + | +LL | (Foo, _) | (Ban, Foo) => {} + | ^^^^^^^^ --- variable not in all patterns + | | + | pattern doesn't bind `Ban` + | +help: you might have meant to use the similarly named unit variant `Bar` + | +LL - (Foo, _) | (Ban, Foo) => {} +LL + (Foo, _) | (Bar, Foo) => {} + | +help: you might have meant to use the similarly named unit struct `Bay` + | +LL - (Foo, _) | (Ban, Foo) => {} +LL + (Foo, _) | (Bay, Foo) => {} + | +help: you might have meant to use the similarly named constant `Bat` + | +LL - (Foo, _) | (Ban, Foo) => {} +LL + (Foo, _) | (Bat, Foo) => {} + | + +error[E0408]: variable `Ban` is not bound in all patterns + --> $DIR/binding-typo-2.rs:86:9 + | +LL | (Foo, _) | (Ban, Foo) => {} + | ^^^^^^^^ --- variable not in all patterns + | | + | pattern doesn't bind `Ban` + | +help: you might have meant to use the similarly named unit variant `Bar` + | +LL - (Foo, _) | (Ban, Foo) => {} +LL + (Foo, _) | (Bar, Foo) => {} + | +help: you might have meant to use the similarly named constant `Bat` + | +LL - (Foo, _) | (Ban, Foo) => {} +LL + (Foo, _) | (Bat, Foo) => {} + | + +error: variable `Ban` is assigned to, but never used + --> $DIR/binding-typo-2.rs:14:23 + | +LL | (Foo, Bar) | (Ban, Foo) => {} + | ^^^ + | + = note: consider using `_Ban` instead +note: the lint level is defined here + --> $DIR/binding-typo-2.rs:2:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ +help: you might have meant to pattern match on the similarly named variant `Bar` + | +LL - (Foo, Bar) | (Ban, Foo) => {} +LL + (Foo, Bar) | (Lol::Bar, Foo) => {} + | + +error: variable `Ban` is assigned to, but never used + --> $DIR/binding-typo-2.rs:25:21 + | +LL | (Foo, _) | (Ban, Foo) => {} + | ^^^ + | + = note: consider using `_Ban` instead +help: you might have meant to pattern match on the similarly named variant `Bar` + | +LL - (Foo, _) | (Ban, Foo) => {} +LL + (Foo, _) | (Lol::Bar, Foo) => {} + | + +error: unused variable: `Non` + --> $DIR/binding-typo-2.rs:37:9 + | +LL | Non => {} + | ^^^ + | +help: if this is intentional, prefix it with an underscore + | +LL | _Non => {} + | + +help: you might have meant to pattern match on the similarly named variant `None` + | +LL - Non => {} +LL + std::prelude::v1::None => {} + | + +error: unused variable: `Non` + --> $DIR/binding-typo-2.rs:44:9 + | +LL | Non | None => {} + | ^^^ + | +help: if this is intentional, prefix it with an underscore + | +LL | _Non | None => {} + | + +help: you might have meant to pattern match on the similarly named variant `None` + | +LL - Non | None => {} +LL + std::prelude::v1::None | None => {} + | + +error: unused variable: `Non` + --> $DIR/binding-typo-2.rs:54:9 + | +LL | Non | Some(_) => {} + | ^^^ + | +help: if this is intentional, prefix it with an underscore + | +LL | _Non | Some(_) => {} + | + +help: you might have meant to pattern match on the similarly named variant `None` + | +LL - Non | Some(_) => {} +LL + std::prelude::v1::None | Some(_) => {} + | + +error: variable `Ban` is assigned to, but never used + --> $DIR/binding-typo-2.rs:69:21 + | +LL | (Foo, _) | (Ban, Foo) => {} + | ^^^ + | + = note: consider using `_Ban` instead +help: you might have meant to pattern match on the similarly named variant `Bar` + | +LL - (Foo, _) | (Ban, Foo) => {} +LL + (Foo, _) | (Lol::Bar, Foo) => {} + | + +error: variable `Ban` is assigned to, but never used + --> $DIR/binding-typo-2.rs:86:21 + | +LL | (Foo, _) | (Ban, Foo) => {} + | ^^^ + | + = note: consider using `_Ban` instead +help: you might have meant to pattern match on the similarly named variant `Bar` + | +LL - (Foo, _) | (Ban, Foo) => {} +LL + (Foo, _) | (Lol::Bar, Foo) => {} + | + +error: unused variable: `Ban` + --> $DIR/binding-typo-2.rs:98:10 + | +LL | (Ban, _) => {} + | ^^^ + | +help: if this is intentional, prefix it with an underscore + | +LL | (_Ban, _) => {} + | + +help: you might have meant to pattern match on the similarly named variant `Bar` + | +LL - (Ban, _) => {} +LL + (Lol::Bar, _) => {} + | + +error: unused variable: `Ban` + --> $DIR/binding-typo-2.rs:104:9 + | +LL | Ban => {} + | ^^^ + | +help: if this is intentional, prefix it with an underscore + | +LL | _Ban => {} + | + +help: you might have meant to pattern match on the similarly named struct `Bay` + | +LL - Ban => {} +LL + Bay => {} + | + +error: unused variable: `Batery` + --> $DIR/binding-typo-2.rs:110:9 + | +LL | Batery => {} + | ^^^^^^ + | +help: if this is intentional, prefix it with an underscore + | +LL | _Batery => {} + | + +help: you might have meant to pattern match on the similarly named constant `Battery` + | +LL | Battery => {} + | + + +error: aborting due to 16 previous errors + +For more information about this error, try `rustc --explain E0408`. diff --git a/tests/ui/or-patterns/binding-typo.fixed b/tests/ui/or-patterns/binding-typo.fixed new file mode 100644 index 00000000000..f209ad644db --- /dev/null +++ b/tests/ui/or-patterns/binding-typo.fixed @@ -0,0 +1,32 @@ +// Issue #51976 +//@ run-rustfix +#![allow(unused_variables)] // allowed so we don't get overlapping suggestions +enum Lol { + Foo, + Bar, +} + +fn foo(x: (Lol, Lol)) { + use Lol::*; + match &x { + (Foo, Bar) | (Bar, Foo) => {} + //~^ ERROR: variable `Ban` is not bound in all patterns + //~| HELP: you might have meant to use the similarly named previously used binding `Bar` + //~| NOTE: pattern doesn't bind `Ban` + //~| NOTE: variable not in all patterns + _ => {} + } + match &x { + (Foo, _) | (Bar, Foo) => {} + //~^ ERROR: variable `Ban` is not bound in all patterns + //~| HELP: you might have meant to use the similarly named unit variant `Bar` + //~| NOTE: pattern doesn't bind `Ban` + //~| NOTE: variable not in all patterns + _ => {} + } +} + +fn main() { + use Lol::*; + foo((Foo, Bar)); +} diff --git a/tests/ui/or-patterns/binding-typo.rs b/tests/ui/or-patterns/binding-typo.rs new file mode 100644 index 00000000000..6be9b801a0d --- /dev/null +++ b/tests/ui/or-patterns/binding-typo.rs @@ -0,0 +1,32 @@ +// Issue #51976 +//@ run-rustfix +#![allow(unused_variables)] // allowed so we don't get overlapping suggestions +enum Lol { + Foo, + Bar, +} + +fn foo(x: (Lol, Lol)) { + use Lol::*; + match &x { + (Foo, Bar) | (Ban, Foo) => {} + //~^ ERROR: variable `Ban` is not bound in all patterns + //~| HELP: you might have meant to use the similarly named previously used binding `Bar` + //~| NOTE: pattern doesn't bind `Ban` + //~| NOTE: variable not in all patterns + _ => {} + } + match &x { + (Foo, _) | (Ban, Foo) => {} + //~^ ERROR: variable `Ban` is not bound in all patterns + //~| HELP: you might have meant to use the similarly named unit variant `Bar` + //~| NOTE: pattern doesn't bind `Ban` + //~| NOTE: variable not in all patterns + _ => {} + } +} + +fn main() { + use Lol::*; + foo((Foo, Bar)); +} diff --git a/tests/ui/or-patterns/binding-typo.stderr b/tests/ui/or-patterns/binding-typo.stderr new file mode 100644 index 00000000000..fb6d5f71209 --- /dev/null +++ b/tests/ui/or-patterns/binding-typo.stderr @@ -0,0 +1,31 @@ +error[E0408]: variable `Ban` is not bound in all patterns + --> $DIR/binding-typo.rs:12:9 + | +LL | (Foo, Bar) | (Ban, Foo) => {} + | ^^^^^^^^^^ --- variable not in all patterns + | | + | pattern doesn't bind `Ban` + | +help: you might have meant to use the similarly named previously used binding `Bar` + | +LL - (Foo, Bar) | (Ban, Foo) => {} +LL + (Foo, Bar) | (Bar, Foo) => {} + | + +error[E0408]: variable `Ban` is not bound in all patterns + --> $DIR/binding-typo.rs:20:9 + | +LL | (Foo, _) | (Ban, Foo) => {} + | ^^^^^^^^ --- variable not in all patterns + | | + | pattern doesn't bind `Ban` + | +help: you might have meant to use the similarly named unit variant `Bar` + | +LL - (Foo, _) | (Ban, Foo) => {} +LL + (Foo, _) | (Bar, Foo) => {} + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0408`. diff --git a/tests/ui/or-patterns/missing-bindings.stderr b/tests/ui/or-patterns/missing-bindings.stderr index 6288cc58913..636f7016647 100644 --- a/tests/ui/or-patterns/missing-bindings.stderr +++ b/tests/ui/or-patterns/missing-bindings.stderr @@ -86,6 +86,12 @@ LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; | ^^^^^^^ - variable not in all patterns | | | pattern doesn't bind `c` + | +help: you might have meant to use the similarly named previously used binding `a` + | +LL - let (A(A(a, b) | B(c), d) | B(e)) = Y; +LL + let (A(A(a, b) | B(a), d) | B(e)) = Y; + | error[E0408]: variable `a` is not bound in all patterns --> $DIR/missing-bindings.rs:47:22 @@ -94,6 +100,12 @@ LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; | - ^^^^ pattern doesn't bind `a` | | | variable not in all patterns + | +help: you might have meant to use the similarly named previously used binding `c` + | +LL - let (A(A(a, b) | B(c), d) | B(e)) = Y; +LL + let (A(A(c, b) | B(c), d) | B(e)) = Y; + | error[E0408]: variable `b` is not bound in all patterns --> $DIR/missing-bindings.rs:47:22 @@ -102,6 +114,12 @@ LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; | - ^^^^ pattern doesn't bind `b` | | | variable not in all patterns + | +help: you might have meant to use the similarly named previously used binding `c` + | +LL - let (A(A(a, b) | B(c), d) | B(e)) = Y; +LL + let (A(A(a, c) | B(c), d) | B(e)) = Y; + | error[E0408]: variable `e` is not bound in all patterns --> $DIR/missing-bindings.rs:47:10 @@ -110,6 +128,12 @@ LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; | ^^^^^^^^^^^^^^^^^^^^ - variable not in all patterns | | | pattern doesn't bind `e` + | +help: you might have meant to use the similarly named previously used binding `c` + | +LL - let (A(A(a, b) | B(c), d) | B(e)) = Y; +LL + let (A(A(a, b) | B(c), d) | B(c)) = Y; + | error[E0408]: variable `a` is not bound in all patterns --> $DIR/missing-bindings.rs:47:33 @@ -118,6 +142,12 @@ LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; | - ^^^^ pattern doesn't bind `a` | | | variable not in all patterns + | +help: you might have meant to use the similarly named previously used binding `e` + | +LL - let (A(A(a, b) | B(c), d) | B(e)) = Y; +LL + let (A(A(e, b) | B(c), d) | B(e)) = Y; + | error[E0408]: variable `b` is not bound in all patterns --> $DIR/missing-bindings.rs:47:33 @@ -126,6 +156,12 @@ LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; | - ^^^^ pattern doesn't bind `b` | | | variable not in all patterns + | +help: you might have meant to use the similarly named previously used binding `e` + | +LL - let (A(A(a, b) | B(c), d) | B(e)) = Y; +LL + let (A(A(a, e) | B(c), d) | B(e)) = Y; + | error[E0408]: variable `c` is not bound in all patterns --> $DIR/missing-bindings.rs:47:33 @@ -134,6 +170,12 @@ LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; | - ^^^^ pattern doesn't bind `c` | | | variable not in all patterns + | +help: you might have meant to use the similarly named previously used binding `e` + | +LL - let (A(A(a, b) | B(c), d) | B(e)) = Y; +LL + let (A(A(a, b) | B(e), d) | B(e)) = Y; + | error[E0408]: variable `d` is not bound in all patterns --> $DIR/missing-bindings.rs:47:33 @@ -142,6 +184,12 @@ LL | let (A(A(a, b) | B(c), d) | B(e)) = Y; | - ^^^^ pattern doesn't bind `d` | | | variable not in all patterns + | +help: you might have meant to use the similarly named previously used binding `e` + | +LL - let (A(A(a, b) | B(c), d) | B(e)) = Y; +LL + let (A(A(a, b) | B(c), e) | B(e)) = Y; + | error[E0408]: variable `a` is not bound in all patterns --> $DIR/missing-bindings.rs:63:29 @@ -158,6 +206,12 @@ LL | A(_, a) | | ^^^^^^^ pattern doesn't bind `b` LL | B(b), | - variable not in all patterns + | +help: you might have meant to use the similarly named previously used binding `a` + | +LL - B(b), +LL + B(a), + | error[E0408]: variable `a` is not bound in all patterns --> $DIR/missing-bindings.rs:71:21 @@ -166,6 +220,12 @@ LL | A(_, a) | | - variable not in all patterns LL | B(b), | ^^^^ pattern doesn't bind `a` + | +help: you might have meant to use the similarly named previously used binding `b` + | +LL - A(_, a) | +LL + A(_, b) | + | error[E0408]: variable `a` is not bound in all patterns --> $DIR/missing-bindings.rs:74:17 @@ -202,6 +262,12 @@ LL | B(b), ... LL | V3(c), | ^^^^^ pattern doesn't bind `b` + | +help: you might have meant to use the similarly named previously used binding `c` + | +LL - B(b), +LL + B(c), + | error[E0408]: variable `c` is not bound in all patterns --> $DIR/missing-bindings.rs:59:13 @@ -223,6 +289,12 @@ LL | | ) | | |_____________^ pattern doesn't bind `c` LL | V3(c), | - variable not in all patterns + | +help: you might have meant to use the similarly named previously used binding `a` + | +LL - V3(c), +LL + V3(a), + | error[E0408]: variable `a` is not bound in all patterns --> $DIR/missing-bindings.rs:78:13 @@ -235,6 +307,15 @@ LL | A(_, a) | ... LL | V3(c), | ^^^^^ pattern doesn't bind `a` + | +help: you might have meant to use the similarly named previously used binding `c` + | +LL ~ B(Ok(a) | Err(c)) +LL | ) | +LL | V2( +LL | A( +LL ~ A(_, c) | + | error[E0170]: pattern binding `beta` is named the same as one of the variants of the type `check_handling_of_paths::bar::foo` --> $DIR/missing-bindings.rs:19:18 diff --git a/tests/ui/pattern/at-in-struct-patterns.rs b/tests/ui/pattern/at-in-struct-patterns.rs index e8fad61f317..b0557220d05 100644 --- a/tests/ui/pattern/at-in-struct-patterns.rs +++ b/tests/ui/pattern/at-in-struct-patterns.rs @@ -5,7 +5,7 @@ struct Foo { fn main() { let foo = Foo { field1: 1, field2: 2 }; - let Foo { var @ field1, .. } = foo; //~ ERROR Unexpected `@` in struct pattern + let Foo { var @ field1, .. } = foo; //~ ERROR unexpected `@` in struct pattern dbg!(var); //~ ERROR cannot find value `var` in this scope let Foo { field1: _, bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns let Foo { bar @ .. } = foo; //~ ERROR `@ ..` is not supported in struct patterns diff --git a/tests/ui/pattern/at-in-struct-patterns.stderr b/tests/ui/pattern/at-in-struct-patterns.stderr index ff75edfe681..20832897ca5 100644 --- a/tests/ui/pattern/at-in-struct-patterns.stderr +++ b/tests/ui/pattern/at-in-struct-patterns.stderr @@ -1,4 +1,4 @@ -error: Unexpected `@` in struct pattern +error: unexpected `@` in struct pattern --> $DIR/at-in-struct-patterns.rs:8:15 | LL | let Foo { var @ field1, .. } = foo; diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr index d76e60478a1..a5d9fd2b1a6 100644 --- a/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr +++ b/tests/ui/pattern/rfc-3637-guard-patterns/name-resolution.stderr @@ -5,6 +5,12 @@ LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, | ^^^^^^^^^^^^ - variable not in all patterns | | | pattern doesn't bind `y` + | +help: you might have meant to use the similarly named previously used binding `x` + | +LL - ((Ok(x) if y) | (Err(y) if x),) => x && y, +LL + ((Ok(x) if y) | (Err(x) if x),) => x && y, + | error[E0408]: variable `x` is not bound in all patterns --> $DIR/name-resolution.rs:37:25 @@ -13,6 +19,12 @@ LL | ((Ok(x) if y) | (Err(y) if x),) => x && y, | - ^^^^^^^^^^^^^ pattern doesn't bind `x` | | | variable not in all patterns + | +help: you might have meant to use the similarly named previously used binding `y` + | +LL - ((Ok(x) if y) | (Err(y) if x),) => x && y, +LL + ((Ok(y) if y) | (Err(y) if x),) => x && y, + | error[E0408]: variable `x` is not bound in all patterns --> $DIR/name-resolution.rs:63:28 diff --git a/tests/ui/resolve/resolve-inconsistent-names.rs b/tests/ui/resolve/resolve-inconsistent-names.rs index 9a40b20346c..96504720e83 100644 --- a/tests/ui/resolve/resolve-inconsistent-names.rs +++ b/tests/ui/resolve/resolve-inconsistent-names.rs @@ -10,8 +10,8 @@ pub mod m { fn main() { let y = 1; match y { - a | b => {} //~ ERROR variable `a` is not bound in all patterns - //~| ERROR variable `b` is not bound in all patterns + a | b => {} //~ ERROR variable `a` is not bound in all patterns + //~| ERROR variable `b` is not bound in all patterns } let x = (E::A, E::B); diff --git a/tests/ui/resolve/resolve-inconsistent-names.stderr b/tests/ui/resolve/resolve-inconsistent-names.stderr index 5fac622eef2..d2333150961 100644 --- a/tests/ui/resolve/resolve-inconsistent-names.stderr +++ b/tests/ui/resolve/resolve-inconsistent-names.stderr @@ -1,18 +1,18 @@ error[E0408]: variable `b` is not bound in all patterns - --> $DIR/resolve-inconsistent-names.rs:13:8 + --> $DIR/resolve-inconsistent-names.rs:13:9 | -LL | a | b => {} - | ^ - variable not in all patterns - | | - | pattern doesn't bind `b` +LL | a | b => {} + | ^ - variable not in all patterns + | | + | pattern doesn't bind `b` error[E0408]: variable `a` is not bound in all patterns - --> $DIR/resolve-inconsistent-names.rs:13:12 + --> $DIR/resolve-inconsistent-names.rs:13:13 | -LL | a | b => {} - | - ^ pattern doesn't bind `a` - | | - | variable not in all patterns +LL | a | b => {} + | - ^ pattern doesn't bind `a` + | | + | variable not in all patterns error[E0408]: variable `c` is not bound in all patterns --> $DIR/resolve-inconsistent-names.rs:19:9 diff --git a/tests/ui/sanitizer/cfi/no_builtins.rs b/tests/ui/sanitizer/cfi/no_builtins.rs deleted file mode 100644 index 949057689ab..00000000000 --- a/tests/ui/sanitizer/cfi/no_builtins.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Verifies that `#![no_builtins]` crates can be built with linker-plugin-lto and CFI. -// See Issue #142284 -// -//@ needs-sanitizer-cfi -//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -//@ compile-flags: --crate-type rlib -//@ build-pass - -#![no_builtins] -#![no_std] - -pub static FUNC: fn() = initializer; - -pub fn initializer() { - call(fma_with_fma); -} - -pub fn call(fn_ptr: fn()) { - fn_ptr(); -} - -pub fn fma_with_fma() {} diff --git a/tests/ui/span/issue-39698.stderr b/tests/ui/span/issue-39698.stderr index 73fcc5c8477..eb18969c3c0 100644 --- a/tests/ui/span/issue-39698.stderr +++ b/tests/ui/span/issue-39698.stderr @@ -7,6 +7,12 @@ LL | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?} | | | pattern doesn't bind `b` | | variable not in all patterns | pattern doesn't bind `b` + | +help: you might have meant to use the similarly named previously used binding `c` + | +LL - T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } +LL + T::T1(a, d) | T::T2(d, c) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } + | error[E0408]: variable `c` is not bound in all patterns --> $DIR/issue-39698.rs:10:9 @@ -17,6 +23,12 @@ LL | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?} | | | variable not in all patterns | | pattern doesn't bind `c` | pattern doesn't bind `c` + | +help: you might have meant to use the similarly named previously used binding `d` + | +LL - T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } +LL + T::T1(a, d) | T::T2(d, b) | T::T3(d) | T::T4(a) => { println!("{:?}", a); } + | error[E0408]: variable `a` is not bound in all patterns --> $DIR/issue-39698.rs:10:23 @@ -27,6 +39,12 @@ LL | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?} | | | pattern doesn't bind `a` | | pattern doesn't bind `a` | variable not in all patterns + | +help: you might have meant to use the similarly named previously used binding `c` + | +LL - T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } +LL + T::T1(c, d) | T::T2(d, b) | T::T3(c) | T::T4(c) => { println!("{:?}", a); } + | error[E0408]: variable `d` is not bound in all patterns --> $DIR/issue-39698.rs:10:37 @@ -37,6 +55,12 @@ LL | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?} | | | pattern doesn't bind `d` | | variable not in all patterns | variable not in all patterns + | +help: you might have meant to use the similarly named previously used binding `c` + | +LL - T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } +LL + T::T1(a, c) | T::T2(c, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } + | error[E0381]: used binding `a` is possibly-uninitialized --> $DIR/issue-39698.rs:10:79 diff --git a/tests/ui/statics/mutable_memory_validation.stderr b/tests/ui/statics/mutable_memory_validation.stderr index df36287cc69..1d6ba195fa2 100644 --- a/tests/ui/statics/mutable_memory_validation.stderr +++ b/tests/ui/statics/mutable_memory_validation.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value at .x.<deref>: encountered `UnsafeCell` LL | const MUH: Meh = Meh { x: unsafe { &mut *(&READONLY as *const _ as *mut _) } }; | ^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } diff --git a/tests/ui/target-feature/inline-always.aarch64.stderr b/tests/ui/target-feature/inline-always.aarch64.stderr new file mode 100644 index 00000000000..a9ffb425c52 --- /dev/null +++ b/tests/ui/target-feature/inline-always.aarch64.stderr @@ -0,0 +1,60 @@ +warning: call to `#[inline(always)]`-annotated `target_feature_identity` requires the same target features to be inlined + --> $DIR/inline-always.rs:19:5 + | +LL | target_feature_identity(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: function will not be inlined + = note: the following target features are on `target_feature_identity` but missing from `call_no_target_features`: neon, fp16 +note: `target_feature_identity` is defined here + --> $DIR/inline-always.rs:16:1 + | +LL | pub unsafe fn target_feature_identity() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(inline_always_mismatching_target_features)]` on by default +help: add `#[target_feature]` attribute to `call_no_target_features` + | +LL + #[target_feature(enable = "neon,fp16")] +LL | unsafe fn call_no_target_features() { + | + +warning: call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined + --> $DIR/inline-always.rs:22:5 + | +LL | multiple_target_features(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: function will not be inlined + = note: the following target features are on `multiple_target_features` but missing from `call_no_target_features`: fp16, sve, rdm +note: `multiple_target_features` is defined here + --> $DIR/inline-always.rs:52:1 + | +LL | fn multiple_target_features() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add `#[target_feature]` attribute to `call_no_target_features` + | +LL + #[target_feature(enable = "fp16,sve,rdm")] +LL | unsafe fn call_no_target_features() { + | + +warning: call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined + --> $DIR/inline-always.rs:28:5 + | +LL | multiple_target_features(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: function will not be inlined + = note: the following target features are on `multiple_target_features` but missing from `call_to_first_set`: rdm +note: `multiple_target_features` is defined here + --> $DIR/inline-always.rs:52:1 + | +LL | fn multiple_target_features() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add `#[target_feature]` attribute to `call_to_first_set` + | +LL + #[target_feature(enable = "rdm")] +LL | unsafe fn call_to_first_set() { + | + +warning: 3 warnings emitted + diff --git a/tests/ui/target-feature/inline-always.rs b/tests/ui/target-feature/inline-always.rs new file mode 100644 index 00000000000..dbf46537caa --- /dev/null +++ b/tests/ui/target-feature/inline-always.rs @@ -0,0 +1,54 @@ +//@ add-core-stubs +//@ build-pass +//@ compile-flags: --crate-type=lib +//@ revisions: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 + +#![feature(no_core, target_feature_inline_always)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[inline(always)] +#[target_feature(enable = "neon,fp16")] +pub unsafe fn target_feature_identity() {} + +unsafe fn call_no_target_features() { + target_feature_identity(); + //~^ WARNING call to `#[inline(always)]`-annotated `target_feature_identity` requires the same target features to be inlined [inline_always_mismatching_target_features] + global_feature_enabled(); + multiple_target_features(); + //~^ WARNING call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined [inline_always_mismatching_target_features] +} + +#[target_feature(enable = "fp16,sve")] +unsafe fn call_to_first_set() { + multiple_target_features(); + //~^ WARNING call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined [inline_always_mismatching_target_features] +} + +/* You can't have "fhm" without "fp16" */ +#[target_feature(enable = "fhm")] +unsafe fn mismatching_features() { + target_feature_identity() +} + +#[target_feature(enable = "fp16")] +unsafe fn matching_target_features() { + target_feature_identity() +} + +#[inline(always)] +#[target_feature(enable = "neon")] +unsafe fn global_feature_enabled() { + +} + +#[inline(always)] +#[target_feature(enable = "fp16,sve")] +#[target_feature(enable="rdm")] +fn multiple_target_features() { + + } diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs index b34a48aba26..a958700231a 100644 --- a/tests/ui/target-feature/invalid-attribute.rs +++ b/tests/ui/target-feature/invalid-attribute.rs @@ -61,6 +61,8 @@ trait Baz {} #[inline(always)] //~^ ERROR: cannot use `#[inline(always)]` +//~| NOTE: see issue #145574 <https://github.com/rust-lang/rust/issues/145574> for more information +//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date #[target_feature(enable = "sse2")] unsafe fn test() {} diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index 7b75367b48c..d85bccce441 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -106,7 +106,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on statics - --> $DIR/invalid-attribute.rs:67:1 + --> $DIR/invalid-attribute.rs:69:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -114,7 +114,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on trait impl blocks - --> $DIR/invalid-attribute.rs:71:1 + --> $DIR/invalid-attribute.rs:73:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +122,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on inherent impl blocks - --> $DIR/invalid-attribute.rs:77:1 + --> $DIR/invalid-attribute.rs:79:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -130,7 +130,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on expressions - --> $DIR/invalid-attribute.rs:98:5 + --> $DIR/invalid-attribute.rs:100:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,18 +138,22 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on closures - --> $DIR/invalid-attribute.rs:104:5 + --> $DIR/invalid-attribute.rs:106:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: `#[target_feature]` can be applied to methods and functions -error: cannot use `#[inline(always)]` with `#[target_feature]` +error[E0658]: cannot use `#[inline(always)]` with `#[target_feature]` --> $DIR/invalid-attribute.rs:62:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #145574 <https://github.com/rust-lang/rust/issues/145574> for more information + = help: add `#![feature(target_feature_inline_always)]` 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: the feature named `foo` is not valid for this target --> $DIR/invalid-attribute.rs:20:18 @@ -158,7 +162,7 @@ LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ `foo` is not valid for this target error[E0046]: not all trait items implemented, missing: `foo` - --> $DIR/invalid-attribute.rs:73:1 + --> $DIR/invalid-attribute.rs:75:1 | LL | impl Quux for u8 {} | ^^^^^^^^^^^^^^^^ missing `foo` in implementation @@ -167,7 +171,7 @@ LL | fn foo(); | --------- `foo` from trait error: `#[target_feature(..)]` cannot be applied to safe trait method - --> $DIR/invalid-attribute.rs:87:5 + --> $DIR/invalid-attribute.rs:89:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method @@ -176,13 +180,13 @@ LL | fn foo() {} | -------- not an `unsafe` function error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/invalid-attribute.rs:90:5 + --> $DIR/invalid-attribute.rs:92:5 | LL | fn foo() {} | ^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait - --> $DIR/invalid-attribute.rs:82:5 + --> $DIR/invalid-attribute.rs:84:5 | LL | fn foo(); | ^^^^^^^^^ @@ -190,7 +194,7 @@ LL | fn foo(); found signature `#[target_features] fn()` error: the feature named `+sse2` is not valid for this target - --> $DIR/invalid-attribute.rs:109:18 + --> $DIR/invalid-attribute.rs:111:18 | LL | #[target_feature(enable = "+sse2")] | ^^^^^^^^^^^^^^^^ `+sse2` is not valid for this target @@ -199,5 +203,5 @@ LL | #[target_feature(enable = "+sse2")] error: aborting due to 24 previous errors -Some errors have detailed explanations: E0046, E0053, E0539. +Some errors have detailed explanations: E0046, E0053, E0539, E0658. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/traits/const-traits/enforce-deref-on-adjust.rs b/tests/ui/traits/const-traits/enforce-deref-on-adjust.rs index d5240b7e18d..cba207f0953 100644 --- a/tests/ui/traits/const-traits/enforce-deref-on-adjust.rs +++ b/tests/ui/traits/const-traits/enforce-deref-on-adjust.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(const_deref)] +#![feature(const_convert)] #![feature(const_trait_impl)] use std::ops::Deref; diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs index d5f80acc15b..50c985096d1 100644 --- a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs +++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, const_from)] +#![feature(const_trait_impl, const_convert)] //@ check-pass diff --git a/tests/ui/traits/const-traits/reservation-impl-ice.rs b/tests/ui/traits/const-traits/reservation-impl-ice.rs index efaea1cc6b2..7fefb4ec543 100644 --- a/tests/ui/traits/const-traits/reservation-impl-ice.rs +++ b/tests/ui/traits/const-traits/reservation-impl-ice.rs @@ -1,5 +1,5 @@ //@ compile-flags: -Znext-solver -#![feature(const_from, never_type, const_trait_impl)] +#![feature(const_convert, never_type, const_trait_impl)] const fn impls_from<T: ~const From<!>>() {} diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr index b545cd75ddb..e19915a58a3 100644 --- a/tests/ui/type/pattern_types/validity.stderr +++ b/tests/ui/type/pattern_types/validity.stderr @@ -4,7 +4,7 @@ error[E0080]: constructing invalid value: encountered 0, but expected something LL | const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { HEX_DUMP } @@ -34,7 +34,7 @@ error[E0080]: constructing invalid value at .0: encountered 0, but expected some LL | const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { HEX_DUMP } @@ -45,7 +45,7 @@ error[E0080]: constructing invalid value at .0.0: encountered 0, but expected so LL | const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); | ^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { HEX_DUMP } @@ -66,7 +66,7 @@ error[E0080]: constructing invalid value: encountered 97, but expected something LL | const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { HEX_DUMP } @@ -77,7 +77,7 @@ error[E0080]: constructing invalid value: encountered 0xffffffff, but expected a LL | const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { HEX_DUMP } diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs index 1a9652c1023..5a683884238 100644 --- a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs @@ -9,6 +9,6 @@ #[stable(feature = "a", since = "1.1.1")] #[unstable_feature_bound(feat_bar)] fn bar() {} -//~^ ERROR Item annotated with `#[unstable_feature_bound]` should not be stable +//~^ ERROR item annotated with `#[unstable_feature_bound]` should not be stable fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr index 9cb6a181bef..9f07e63e454 100644 --- a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr @@ -1,4 +1,4 @@ -error: Item annotated with `#[unstable_feature_bound]` should not be stable +error: item annotated with `#[unstable_feature_bound]` should not be stable --> $DIR/unstable_feature_bound_incompatible_stability.rs:11:1 | LL | fn bar() {} diff --git a/triagebot.toml b/triagebot.toml index 3b7b216c0d2..fd6329de923 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -450,7 +450,8 @@ trigger_files = [ [autolabel."O-wasi"] trigger_files = [ - "library/std/src/sys/pal/wasi", + "library/std/src/sys/pal/wasip1", + "library/std/src/sys/pal/wasip2", "library/std/src/os/wasi" ] @@ -1305,6 +1306,21 @@ cc = ["@m-ou-se"] [mentions."compiler/rustc_ast_lowering/src/format.rs"] cc = ["@m-ou-se"] +[mentions."#[miri::intrinsic_fallback_is_spec]"] +type = "content" +message = """ +`#[miri::intrinsic_fallback_is_spec]` must only be used if the function actively checks for all UB cases, +and explores the possible non-determinism of the intrinsic. +""" +cc = ["@rust-lang/miri"] +[mentions."#[rustc_allow_const_fn_unstable]"] +type = "content" +message = """ +`#[rustc_allow_const_fn_unstable]` needs careful audit to avoid accidentally exposing unstable +implementation details on stable. +""" +cc = ["@rust-lang/wg-const-eval"] + # ------------------------------------------------------------------------------ # PR assignments |
