diff --git a/Cargo.lock b/Cargo.lock index 52f504811575..c4c96f1569b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5152,9 +5152,9 @@ dependencies = [ [[package]] name = "stringdex" -version = "0.0.1-alpha4" +version = "0.0.1-alpha9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2841fd43df5b1ff1b042e167068a1fe9b163dc93041eae56ab2296859013a9a0" +checksum = "7081029913fd7d591c0112182aba8c98ae886b4f12edb208130496cd17dc3c15" dependencies = [ "stacker", ] diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 16fd9241a172..eac939577979 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 ea98bebd3055..6dc6d1026f62 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 b8a748563d52..7fa1293463cc 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 7e77781dc2fc..c3adb5e767e2 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 { @@ -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 { 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 fcee6b6df623..9d8ce2383f2b 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 5affb26483aa..9f2d37d39d87 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::>(); + // 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 fc38c4f3e513..326b876e7e68 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::>(); - 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 37379586d582..7d0691366e60 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 4fd6110ac4a1..257c7b95666f 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 49d3dedbeabd..85f71f331a49 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 44b9941691a6..dd688b8b3454 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 19c919c0e4ef..48b01ea2df19 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 df1e91b12f90..a2efd420a327 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 c95038375a1b..f4a9037940a6 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 d8a1480e911f..b49e67217fb0 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 { + 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 8586615f7c76..f637e7f58dbf 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -333,8 +333,7 @@ pub struct CodegenContext { pub crate_types: Vec, pub output_filenames: Arc, pub invocation_temp: Option, - pub regular_module_config: Arc, - pub allocator_module_config: Arc, + pub module_config: Arc, pub tm_factory: TargetMachineFactoryFn, pub msvc_imps_needed: bool, pub is_pe_coff: bool, @@ -372,13 +371,6 @@ impl CodegenContext { 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( @@ -442,6 +434,7 @@ pub(crate) fn start_async_codegen( backend: B, tcx: TyCtxt<'_>, target_cpu: String, + allocator_module: Option>, ) -> OngoingCodegen { let (coordinator_send, coordinator_receive) = channel(); @@ -465,6 +458,7 @@ pub(crate) fn start_async_codegen( coordinator_receive, Arc::new(regular_config), Arc::new(allocator_config), + allocator_module, coordinator_send.clone(), ); @@ -495,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())); @@ -720,15 +714,6 @@ pub(crate) enum WorkItem { } impl WorkItem { - 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 @@ -809,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. @@ -833,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, @@ -843,23 +821,22 @@ pub(crate) fn compute_per_cgu_lto_type( fn execute_optimize_work_item( cgcx: &CodegenContext, mut module: ModuleCodegen, - module_config: &ModuleConfig, ) -> WorkItemResult { 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 { @@ -868,7 +845,7 @@ fn execute_optimize_work_item( 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 => { @@ -899,7 +876,6 @@ fn execute_optimize_work_item( fn execute_copy_from_cache_work_item( cgcx: &CodegenContext, module: CachedModuleCodegen, - module_config: &ModuleConfig, ) -> WorkItemResult { let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap(); @@ -959,6 +935,7 @@ fn execute_copy_from_cache_work_item( } }; + 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); @@ -971,7 +948,6 @@ fn execute_copy_from_cache_work_item( WorkItemResult::Finished(CompiledModule { links_from_incr_cache, name: module.name, - kind: ModuleKind::Regular, object, dwarf_object, bytecode, @@ -986,7 +962,6 @@ fn execute_fat_lto_work_item( each_linked_rlib_for_lto: &[PathBuf], mut needs_fat_lto: Vec>, import_only_modules: Vec<(SerializedModule, WorkProduct)>, - module_config: &ModuleConfig, ) -> WorkItemResult { for (module, wp) in import_only_modules { needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module }) @@ -998,17 +973,16 @@ fn execute_fat_lto_work_item( 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( cgcx: &CodegenContext, module: lto::ThinModule, - module_config: &ModuleConfig, ) -> WorkItemResult { 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) } @@ -1093,6 +1067,7 @@ fn start_executing_work( coordinator_receive: Receiver>, regular_config: Arc, allocator_config: Arc, + allocator_module: Option>, tx_to_llvm_workers: Sender>, ) -> thread::JoinHandle> { let coordinator_send = tx_to_llvm_workers; @@ -1157,8 +1132,7 @@ fn start_executing_work( 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, @@ -1173,6 +1147,11 @@ fn start_executing_work( 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. @@ -1312,7 +1291,6 @@ fn start_executing_work( // 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(); @@ -1586,15 +1564,7 @@ fn start_executing_work( 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); @@ -1722,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 8abaf201abae..a9a2ae1b3dbc 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 { // 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( @@ -647,7 +662,7 @@ pub fn codegen_crate( ) -> OngoingCodegen { // 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( } } - 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( } } - // 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 961bb788149d..008340e614de 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 fe0500a5d4cf..5b90ffaa0566 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -120,7 +120,6 @@ impl ModuleCodegen { CompiledModule { name: self.name.clone(), - kind: self.kind, object, dwarf_object, bytecode, @@ -134,7 +133,6 @@ impl ModuleCodegen { #[derive(Debug, Encodable, Decodable)] pub struct CompiledModule { pub name: String, - pub kind: ModuleKind, pub object: Option, pub dwarf_object: Option, pub bytecode: Option, diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 60518dafbf2b..700d7c26752b 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 2c6a0291ac29..b62cdc35f513 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 71fc54f0d33f..a56e0f3fae13 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 0324057e331a..ab8e059b7b77 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: + // + // 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 573e9aab0554..4f35bf63a1a4 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 cfc6bc2f3a0a..aa2d27ab8094 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 f5770b7312dd..2ba7ed46f92c 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 8f131f45bbdd..4c820b8877b7 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) -> 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) -> 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_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index ce92263babd8..b79075ac09b9 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_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 5d776ea581dd..9e23da88f5e1 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -412,7 +412,7 @@ impl CStore { match (&left_name_val, &right_name_val) { (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) { cmp::Ordering::Equal => { - if l.0.tech_value != r.0.tech_value { + if !l.1.consistent(&tcx.sess.opts, Some(&r.1)) { report_diff( &l.0.prefix, &l.0.name, @@ -424,20 +424,28 @@ impl CStore { right_name_val = None; } cmp::Ordering::Greater => { - report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name)); + if !r.1.consistent(&tcx.sess.opts, None) { + report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name)); + } right_name_val = None; } cmp::Ordering::Less => { - report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None); + if !l.1.consistent(&tcx.sess.opts, None) { + report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None); + } left_name_val = None; } }, (Some(l), None) => { - report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None); + if !l.1.consistent(&tcx.sess.opts, None) { + report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None); + } left_name_val = None; } (None, Some(r)) => { - report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name)); + if !r.1.consistent(&tcx.sess.opts, None) { + report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name)); + } right_name_val = None; } (None, None) => break, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 866736f74a05..8b4503073b0d 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 857d041224fa..5367e5edd496 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, Option) { + 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 72ab6ac612c6..97c8a0336c21 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>; - fn mk_probe_ref(self, probe: inspect::Probe) -> &'tcx inspect::Probe> { + type Probe = &'tcx inspect::Probe>; + fn mk_probe(self, probe: inspect::Probe) -> &'tcx inspect::Probe> { 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 7dfe2d280514..8b92e48ed1a0 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 000000000000..abad28f0a8f8 --- /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::>(), + ) { + 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 ad9635aae330..775f5f9a7cf1 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 8f319e649166..1663dfa744f4 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> { // 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 31106a745279..443aebbdb4d6 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, -) -> (QueryResult, I::ProbeRef) { +) -> (QueryResult, I::Probe) { let mut inspect = inspect::ProofTreeBuilder::new(); let canonical_result = SearchGraph::::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 4ca2f57bd875..77dd313d9b8e 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/lib.rs b/compiler/rustc_parse/src/lib.rs index 197333d942d2..b790966acfd9 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, Vec>> { 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, Vec>> { + 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( @@ -147,9 +160,10 @@ pub fn utf8_error( fn new_parser_from_source_file( psess: &ParseSess, source_file: Arc, + frontmatter_allowed: FrontmatterAllowed, ) -> Result, Vec>> { 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 498d9a405fa2..afd08319738d 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 680e2a26d840..23dcabef1a17 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, +} + +#[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, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index ae16a51bc693..1b2ffb5b3db2 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::>(), - 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 f48dc60afa0e..f686608034cb 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 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 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 47280a936779..0e566e20a124 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 5dfc4292a380..abbacc70b3e6 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::>(); - let origin_sp = origin.iter().copied().collect::>(); + let mut target_sp = target.iter().map(|pat| pat.span).collect::>(); + target_sp.sort(); + target_sp.dedup(); + let mut origin_sp = origin.iter().map(|(span, _)| *span).collect::>(); + 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::>() + .join("::") + } + pub(crate) fn add_scope_set_candidates( &mut self, suggestions: &mut Vec, @@ -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, + spans: FxHashMap>, +} + +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]) -> Option { 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 63d6fa23a148..72be94e58db9 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, + pub(crate) typo: Symbol, +} + #[derive(Diagnostic)] #[diag(resolve_name_defined_multiple_time)] #[note] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6a12fafcb1e8..521fef2b9d43 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); + let inners = not_never_pats.iter().filter(|(_, pat)| pat.id != pat_outer.id); - 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)); + 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 9674c0356c21..0dea6ae33273 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, - target: BTreeSet, + origin: Vec<(Span, ast::Pat)>, + target: Vec, could_be_path: bool, } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 6d5be2d92cd2..69facde69368 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -83,10 +83,77 @@ pub struct TargetModifier { pub value_name: String, } +mod target_modifier_consistency_check { + use super::*; + pub(super) fn sanitizer(l: &TargetModifier, r: Option<&TargetModifier>) -> bool { + let mut lparsed: SanitizerSet = Default::default(); + let lval = if l.value_name.is_empty() { None } else { Some(l.value_name.as_str()) }; + parse::parse_sanitizers(&mut lparsed, lval); + + let mut rparsed: SanitizerSet = Default::default(); + let rval = r.filter(|v| !v.value_name.is_empty()).map(|v| v.value_name.as_str()); + parse::parse_sanitizers(&mut rparsed, rval); + + // Some sanitizers need to be target modifiers, and some do not. + // For now, we should mark all sanitizers as target modifiers except for these: + // AddressSanitizer, LeakSanitizer + let tmod_sanitizers = SanitizerSet::MEMORY + | SanitizerSet::THREAD + | SanitizerSet::HWADDRESS + | SanitizerSet::CFI + | SanitizerSet::MEMTAG + | SanitizerSet::SHADOWCALLSTACK + | SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::SAFESTACK + | SanitizerSet::DATAFLOW; + + lparsed & tmod_sanitizers == rparsed & tmod_sanitizers + } + pub(super) fn sanitizer_cfi_normalize_integers( + opts: &Options, + l: &TargetModifier, + r: Option<&TargetModifier>, + ) -> bool { + // For kCFI, the helper flag -Zsanitizer-cfi-normalize-integers should also be a target modifier + if opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI) { + if let Some(r) = r { + return l.extend().tech_value == r.extend().tech_value; + } else { + return false; + } + } + true + } +} + impl TargetModifier { pub fn extend(&self) -> ExtendedTargetModifierInfo { self.opt.reparse(&self.value_name) } + // Custom consistency check for target modifiers (or default `l.tech_value == r.tech_value`) + // When other is None, consistency with default value is checked + pub fn consistent(&self, opts: &Options, other: Option<&TargetModifier>) -> bool { + assert!(other.is_none() || self.opt == other.unwrap().opt); + match self.opt { + OptionsTargetModifiers::UnstableOptions(unstable) => match unstable { + UnstableOptionsTargetModifiers::sanitizer => { + return target_modifier_consistency_check::sanitizer(self, other); + } + UnstableOptionsTargetModifiers::sanitizer_cfi_normalize_integers => { + return target_modifier_consistency_check::sanitizer_cfi_normalize_integers( + opts, self, other, + ); + } + _ => {} + }, + _ => {} + }; + match other { + Some(other) => self.extend().tech_value == other.extend().tech_value, + None => false, + } + } } fn tmod_push_impl( @@ -2504,13 +2571,13 @@ written to standard error output)"), retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], "enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \ target features (default: no)"), - sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], + sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER], "use a sanitizer"), sanitizer_cfi_canonical_jump_tables: Option = (Some(true), parse_opt_bool, [TRACKED], "enable canonical jump tables (default: yes)"), sanitizer_cfi_generalize_pointers: Option = (None, parse_opt_bool, [TRACKED], "enable generalizing pointer types (default: no)"), - sanitizer_cfi_normalize_integers: Option = (None, parse_opt_bool, [TRACKED], + sanitizer_cfi_normalize_integers: Option = (None, parse_opt_bool, [TRACKED TARGET_MODIFIER], "enable normalizing integer types (default: no)"), sanitizer_dataflow_abilist: Vec = (Vec::new(), parse_comma_list, [TRACKED], "additional ABI list files that control how shadow parameters are passed (comma separated)"), diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index c32593a6d95a..bb2cda77dfff 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, + multi_byte_chars: &mut Vec, + ) { + 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, + multi_byte_chars: &mut Vec, + ) { + use std::arch::loongarch64::*; + + const CHUNK_SIZE: usize = 16; + + let (chunks, tail) = src.as_bytes().as_chunks::(); + + // 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, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index ae6755f07642..8907c5e4c4ae 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 77260d07c995..e5108d8b7e92 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 f1b6fa123deb..cd55576ef816 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/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs index 598f0f19f0de..cada0dd640a4 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 f5448baf8c0b..3355c0c2104d 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>; - fn mk_probe_ref(self, probe: inspect::Probe) -> Self::ProbeRef; + type Probe: Debug + Hash + Eq + Borrow>; + fn mk_probe(self, probe: inspect::Probe) -> Self::Probe; fn evaluate_root_goal_for_proof_tree_raw( self, canonical_goal: CanonicalInput, - ) -> (QueryResult, Self::ProbeRef); + ) -> (QueryResult, 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 5452ac441589..3af2f8dbaf27 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 = Canonical>; pub struct GoalEvaluation { pub uncanonicalized_goal: Goal, pub orig_values: Vec, - pub final_revision: I::ProbeRef, + pub final_revision: I::Probe, pub result: QueryResult, } diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index fd05f9ca464d..b0027e964e46 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -468,10 +468,6 @@ impl RawVecInner { 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 RawVecInner { 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 RawVecInner { 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( 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 { elem_layout.repeat(cap).map(|(layout, _pad)| layout).map_err(|_| CapacityOverflow.into()) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 4cdc046f71ee..d14419a23a1d 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(val: T) -> [T; N] { from_trusted_iterator(repeat_n(val, N)) diff --git a/library/core/src/intrinsics/fallback.rs b/library/core/src/intrinsics/fallback.rs index eec5c4d646d0..96928325328a 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 904aa52c7845..bffffbc29c1e 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2102,6 +2102,61 @@ pub const fn saturating_add(a: T, b: T) -> T; #[rustc_intrinsic] pub const fn saturating_sub(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( + 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( + 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 943b88e23305..3ebdf7b47279 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -321,6 +321,7 @@ impl Default for Chain { /// /// // 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 a6522659620a..a55de75d56c6 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -317,6 +317,108 @@ impl Peekable { { 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::(), " 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) -> Vec { + /// let mut result = Vec::with_capacity(nodes.len()); + /// let mut iter = nodes.into_iter().peekable(); + /// let mut comment_text = None::; + /// 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(&mut self, f: impl FnOnce(I::Item) -> Result) -> Option { + 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 82506379cac7..c306011bdda3 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/num/int_macros.rs b/library/core/src/num/int_macros.rs index 25864db5fea7..db70fb65d444 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 69c6a7dbd897..54d5a63633c2 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", diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index c1e656fdea23..0ce9c259c40e 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/range.rs b/library/core/src/ops/range.rs index c0a27775694c..58a9431bd845 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -836,6 +836,7 @@ pub trait RangeBounds { /// 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(&self, item: &U) -> bool diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 3fe4b08d459e..ce6eee4f911e 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -106,6 +106,7 @@ impl *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/coretests/tests/iter/adapters/peekable.rs b/library/coretests/tests/iter/adapters/peekable.rs index 7f4341b8902c..f0549e8d6c2c 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 { + 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, + } + 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 ffb96b5a7cfd..b5658a9970fe 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -50,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)] @@ -82,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 c7d10ea4d880..63be8a45b5cf 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); @@ -150,6 +163,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; 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 d25050c3e4b4..e7253313f036 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 45d978068b66..e3ba8658bd80 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/src/fs/tests.rs b/library/std/src/fs/tests.rs index 5e51d5e52114..f4431cedd180 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -490,6 +490,85 @@ fn file_test_io_read_write_at() { check!(fs::remove_file(&filename)); } +#[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; 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; 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() { @@ -566,6 +645,39 @@ fn file_test_io_seek_read_write() { check!(fs::remove_file(&filename)); } +#[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; 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(); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index a4b63462053d..99b380c47936 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)] diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index b776df3dde1d..1d1a138b3025 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; 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; 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 { 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 { 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 ddb8dbd8feea..b445f368aeb1 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; + /// 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; 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 { self.as_inner().write_at(buf, offset) } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 5ccea1c972c1..19663e4a9df6 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>(&mut self, extension: S) -> bool { self._add_extension(extension.as_ref()) } @@ -2109,7 +2107,7 @@ impl PartialEq for PathBuf { impl cmp::PartialEq for PathBuf { #[inline] fn eq(&self, other: &str) -> bool { - &*self == other + Path::eq(self, other) } } @@ -2880,8 +2878,6 @@ impl Path { /// # Examples /// /// ``` - /// #![feature(path_add_extension)] - /// /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("foo.rs"); @@ -2892,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>(&self, extension: S) -> PathBuf { let mut new_path = self.to_path_buf(); new_path.add_extension(extension); diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index a12f692e7543..2b2dfe48e89e 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 { - #[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::(), cmp::min(cursor.capacity(), READ_LIMIT), ) })?; - // 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); + } + 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::(), + 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 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 { #[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 a89c3bbacfbf..3b525406223c 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 { 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 bac278f7c8f5..ccfe410627f7 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 { self.handle.write(buf) } diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 82a880faf5fa..76c8aa939d3b 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) -> io::Result { let mut me = self; diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index e1576a0d4231..fa76c50597b0 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; @@ -2526,3 +2526,9 @@ fn normalize_lexically() { check_err(r"\\?\UNC\server\share\a\..\.."); } } + +#[test] +/// See issue#146183 +fn compare_path_to_str() { + assert!(&PathBuf::from("x") == "x"); +} diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 1535d0870333..fe832652d25c 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]] @@ -433,6 +433,15 @@ version = "2.7.4" 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" @@ -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]] @@ -1043,22 +1053,22 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "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]] @@ -1083,48 +1109,96 @@ version = "0.52.6" 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" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index c71755844654..9a76a7dda2ac 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 a604e7c05859..49d12b64da51 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 05f8b240291e..2083c675e1fd 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 f113dd7683d8..820dda5a6524 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; 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 { diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 0789eefa8946..eb198a0051ab 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 d47c14958389..83ed7430c397 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 d9de6b7ef96b..9f7248b80f76 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 ee2cbe9385e4..cb81d738666a 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,63 +3191,93 @@ 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 = std::env::var("DISTCHECK_CONFIGURE_ARGS") - .map(|args| args.split(" ").map(|s| s.to_string()).collect::>()) - .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 = std::env::var("DISTCHECK_CONFIGURE_ARGS") + .map(|args| args.split(" ").map(|s| s.to_string()).collect::>()) + .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)] pub struct Bootstrap; @@ -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 65c4c4990865..c5308034fe30 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 cdf6fe573e58..cca0c803e63b 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 ef01f14f5e9a..9e8c13eb4dec 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::>(); - 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(v: Vec<(A, B)>) -> Vec { @@ -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 d12cc962187f..678a9b639522 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, pub rust_std_features: BTreeSet, + pub rust_break_on_ice: bool, pub llvm_profile_use: Option, pub llvm_profile_generate: bool, pub llvm_libunwind_default: Option, @@ -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 c54df456d52b..4832a1d37b77 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 = "lto", validate_mir_opts: Option = "validate-mir-opts", std_features: Option> = "std-features", + break_on_ice: Option = "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/lib.rs b/src/bootstrap/src/lib.rs index 59c0f9faacac..a2aeed20948e 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, &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 bed03c18aaad..a6233e6b61c1 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 2cc2fb486fad..01309072927d 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/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 41d0cf8d9fb3..c3660e24b152 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 fed19d6b667e..f37b27d88c38 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 dfe193e6e8ad..6c5b48d8c8f5 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 71dc4ddc2e65..826c75b79c57 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 8d7f7341c2e6..46a3a1602ac7 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/Cargo.toml b/src/librustdoc/Cargo.toml index 5d36ffc2d3a5..f37a8d85361f 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -21,7 +21,7 @@ rustdoc-json-types = { path = "../rustdoc-json-types" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" smallvec = "1.8.1" -stringdex = { version = "0.0.1-alpha4" } +stringdex = { version = "0.0.1-alpha9" } tempfile = "3" threadpool = "1.8.1" tracing = "0.1" diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 450ac04b40d9..d7f6fa347bec 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::>(); 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/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 5da37c97c6a7..b01b596da682 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1212,7 +1212,7 @@ class DocSearch { * will never fulfill. */ async buildIndex() { - const nn = this.database.getIndex("normalizedName"); + const nn = this.database.getData("normalizedName"); if (!nn) { return; } @@ -3722,7 +3722,7 @@ class DocSearch { * @returns {AsyncGenerator} */ async function*(currentCrate) { - const index = this.database.getIndex("normalizedName"); + const index = this.database.getData("normalizedName"); if (!index) { return; } @@ -3851,8 +3851,7 @@ class DocSearch { }; if (elem.normalizedPathLast === "") { // faster full-table scan for this specific case. - const nameData = this.database.getData("name"); - const l = nameData ? nameData.length : 0; + const l = index.length; for (let id = 0; id < l; ++id) { if (!idDuplicates.has(id)) { idDuplicates.add(id); @@ -3954,7 +3953,7 @@ class DocSearch { * @returns {AsyncGenerator} */ async function*(inputs, output, typeInfo, currentCrate) { - const index = this.database.getIndex("normalizedName"); + const index = this.database.getData("normalizedName"); if (!index) { return; } diff --git a/src/librustdoc/html/static/js/stringdex.d.ts b/src/librustdoc/html/static/js/stringdex.d.ts index cf9a8b6b5648..2eb1fdf95d84 100644 --- a/src/librustdoc/html/static/js/stringdex.d.ts +++ b/src/librustdoc/html/static/js/stringdex.d.ts @@ -5,17 +5,8 @@ declare namespace stringdex { * The client interface to Stringdex. */ interface Database { - getIndex(colname: string): SearchTree|undefined; getData(colname: string): DataColumn|undefined; } - /** - * A search index file. - */ - interface SearchTree { - trie(): Trie; - search(name: Uint8Array|string): Promise; - searchLev(name: Uint8Array|string): AsyncGenerator; - } /** * A compressed node in the search tree. * @@ -29,9 +20,7 @@ declare namespace stringdex { matches(): RoaringBitmap; substringMatches(): AsyncGenerator; prefixMatches(): AsyncGenerator; - keys(): Uint8Array; keysExcludeSuffixOnly(): Uint8Array; - children(): [number, Promise][]; childrenExcludeSuffixOnly(): [number, Promise][]; child(id: number): Promise?; } @@ -41,6 +30,8 @@ declare namespace stringdex { interface DataColumn { isEmpty(id: number): boolean; at(id: number): Promise; + search(name: Uint8Array|string): Promise; + searchLev(name: Uint8Array|string): AsyncGenerator; length: number, } /** diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js index cb956d926db9..b7f605a10351 100644 --- a/src/librustdoc/html/static/js/stringdex.js +++ b/src/librustdoc/html/static/js/stringdex.js @@ -1,3 +1,4 @@ +// ignore-tidy-filelength /** * @import * as stringdex from "./stringdex.d.ts" */ @@ -485,6 +486,63 @@ class RoaringBitmap { const mid = this.getContainerId(key); return mid === -1 ? false : this.containers[mid].contains(value); } + /** + * @param {number} keyvalue + * @returns {RoaringBitmap} + */ + remove(keyvalue) { + const key = keyvalue >> 16; + const value = keyvalue & 0xFFFF; + const mid = this.getContainerId(key); + if (mid === -1) { + return this; + } + const container = this.containers[mid]; + if (!container.contains(value)) { + return this; + } + const newCardinality = (this.keysAndCardinalities[(mid * 4) + 2] | + (this.keysAndCardinalities[(mid * 4) + 3] << 8)); + const l = this.containers.length; + const m = l - (newCardinality === 0 ? 1 : 0); + const result = new RoaringBitmap(null, 0); + result.keysAndCardinalities = new Uint8Array(m * 4); + let j = 0; + for (let i = 0; i < l; i += 1) { + if (i === mid) { + if (newCardinality !== 0) { + result.keysAndCardinalities[(j * 4) + 0] = key; + result.keysAndCardinalities[(j * 4) + 1] = key >> 8; + const card = newCardinality - 1; + result.keysAndCardinalities[(j * 4) + 2] = card; + result.keysAndCardinalities[(j * 4) + 3] = card >> 8; + const newContainer = new RoaringBitmapArray( + newCardinality, + new Uint8Array(newCardinality * 2), + ); + let newContainerSlot = 0; + for (const containerValue of container.values()) { + if (containerValue !== value) { + newContainer.array[newContainerSlot] = value & 0xFF; + newContainerSlot += 1; + newContainer.array[newContainerSlot] = value >> 8; + newContainerSlot += 1; + } + } + result.containers.push(newContainer); + j += 1; + } + } else { + result.keysAndCardinalities[(j * 4) + 0] = this.keysAndCardinalities[(i * 4) + 0]; + result.keysAndCardinalities[(j * 4) + 1] = this.keysAndCardinalities[(i * 4) + 1]; + result.keysAndCardinalities[(j * 4) + 2] = this.keysAndCardinalities[(i * 4) + 2]; + result.keysAndCardinalities[(j * 4) + 3] = this.keysAndCardinalities[(i * 4) + 3]; + result.containers.push(this.containers[i]); + j += 1; + } + } + return result; + } /** * @param {number} key * @returns {number} @@ -877,6 +935,46 @@ function bitCount(n) { } /*eslint-enable */ +/** + * https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm + */ +class Uint8ArraySearchPattern { + /** @param {Uint8Array} needle */ + constructor(needle) { + this.needle = needle; + this.skipTable = []; + const m = needle.length; + for (let i = 0; i < 256; i += 1) { + this.skipTable.push(m); + } + for (let i = 0; i < m - 1; i += 1) { + this.skipTable[needle[i]] = m - 1 - i; + } + } + /** + * @param {Uint8Array} haystack + * @returns {boolean} + */ + matches(haystack) { + const needle = this.needle; + const skipTable = this.skipTable; + const m = needle.length; + const n = haystack.length; + + let skip = 0; + search: while (n - skip >= m) { + for (let i = m - 1; i >= 0; i -= 1) { + if (haystack[skip + i] !== needle[i]) { + skip += skipTable[haystack[skip + m - 1]]; + continue search; + } + } + return true; + } + return false; + } +} + /** * @param {stringdex.Hooks} hooks * @returns {Promise} @@ -887,12 +985,6 @@ function loadDatabase(hooks) { rr_: function(data) { const dataObj = JSON.parse(data); for (const colName of Object.keys(dataObj)) { - if (Object.hasOwn(dataObj[colName], "I")) { - registry.searchTreeRoots.set( - colName, - makeSearchTreeFromBase64(dataObj[colName].I)[1], - ); - } if (Object.hasOwn(dataObj[colName], "N")) { const counts = []; const countsstring = dataObj[colName]["N"]; @@ -915,6 +1007,9 @@ function loadDatabase(hooks) { makeUint8ArrayFromBase64(dataObj[colName]["H"]), new RoaringBitmap(makeUint8ArrayFromBase64(dataObj[colName]["E"]), 0), colName, + Object.hasOwn(dataObj[colName], "I") ? + makeSearchTreeFromBase64(dataObj[colName].I)[1] : + null, )); } } @@ -978,7 +1073,7 @@ function loadDatabase(hooks) { * searchTreePromises: HashTable>; * dataColumnLoadPromiseCallbacks: HashTable; * dataColumns: Map; - * dataColumnsBuckets: Map>>; + * dataColumnsBuckets: HashTable>; * searchTreeLoadByNodeID: function(Uint8Array): Promise; * searchTreeRootCallback?: function(any, Database?): any; * dataLoadByNameAndHash: function(string, Uint8Array): Promise; @@ -990,7 +1085,7 @@ function loadDatabase(hooks) { searchTreePromises: new HashTable(), dataColumnLoadPromiseCallbacks: new HashTable(), dataColumns: new Map(), - dataColumnsBuckets: new Map(), + dataColumnsBuckets: new HashTable(), searchTreeLoadByNodeID: function(nodeid) { const existingPromise = registry.searchTreePromises.get(nodeid); if (existingPromise) { @@ -1022,7 +1117,7 @@ function loadDatabase(hooks) { const data = (nodeid[0] & 0x20) !== 0 ? Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) : EMPTY_UINT8; - newPromise = Promise.resolve(new SearchTree( + newPromise = Promise.resolve(new PrefixSearchTree( EMPTY_SEARCH_TREE_BRANCHES, EMPTY_SEARCH_TREE_BRANCHES, data, @@ -1058,12 +1153,7 @@ function loadDatabase(hooks) { return newPromise; }, dataLoadByNameAndHash: function(name, hash) { - let dataColumnBuckets = registry.dataColumnsBuckets.get(name); - if (dataColumnBuckets === undefined) { - dataColumnBuckets = new HashTable(); - registry.dataColumnsBuckets.set(name, dataColumnBuckets); - } - const existingBucket = dataColumnBuckets.get(hash); + const existingBucket = registry.dataColumnsBuckets.get(hash); if (existingBucket) { return existingBucket; } @@ -1091,16 +1181,17 @@ function loadDatabase(hooks) { hooks.loadDataByNameAndHash(name, hashHex); } }); - dataColumnBuckets.set(hash, newBucket); + registry.dataColumnsBuckets.set(hash, newBucket); return newBucket; }, }; /** * The set of child subtrees. + * @template ST * @type {{ * nodeids: Uint8Array, - * subtrees: Array|null>, + * subtrees: Array|null>, * }} */ class SearchTreeBranches { @@ -1128,7 +1219,7 @@ function loadDatabase(hooks) { ); } // https://github.com/microsoft/TypeScript/issues/17227 - /** @returns {Generator<[number, Promise|null]>} */ + /** @returns {Generator<[number, Promise|null]>} */ entries() { throw new Error(); } @@ -1157,10 +1248,12 @@ function loadDatabase(hooks) { /** * A sorted array of search tree branches. * + * @template ST + * @extends SearchTreeBranches * @type {{ * keys: Uint8Array, * nodeids: Uint8Array, - * subtrees: Array|null>, + * subtrees: Array|null>, * }} */ class SearchTreeBranchesArray extends SearchTreeBranches { @@ -1179,7 +1272,7 @@ function loadDatabase(hooks) { i += 1; } } - /** @returns {Generator<[number, Promise|null]>} */ + /** @returns {Generator<[number, Promise|null]>} */ * entries() { let i = 0; const l = this.keys.length; @@ -1246,12 +1339,16 @@ function loadDatabase(hooks) { } /** + * @template ST * @param {number[]} alphabitmap_chars * @param {number} width - * @return {(typeof SearchTreeBranches)&{"ALPHABITMAP_CHARS": number[], "width": number}} + * @return {(typeof SearchTreeBranches)&{"ALPHABITMAP_CHARS": number[], "width": number}} */ function makeSearchTreeBranchesAlphaBitmapClass(alphabitmap_chars, width) { const bitwidth = width * 8; + /** + * @extends SearchTreeBranches + */ const cls = class SearchTreeBranchesAlphaBitmap extends SearchTreeBranches { /** * @param {number} bitmap @@ -1265,7 +1362,7 @@ function loadDatabase(hooks) { this.bitmap = bitmap; this.nodeids = nodeids; } - /** @returns {Generator<[number, Promise|null]>} */ + /** @returns {Generator<[number, Promise|null]>} */ * entries() { let i = 0; let j = 0; @@ -1295,15 +1392,7 @@ function loadDatabase(hooks) { * @returns {number} */ getKey(branch_index) { - //return this.getKeys()[branch_index]; - let alpha_index = 0; - while (branch_index >= 0) { - if (this.bitmap & (1 << alpha_index)) { - branch_index -= 1; - } - alpha_index += 1; - } - return alphabitmap_chars[alpha_index]; + return this.getKeys()[branch_index]; } /** * @returns {Uint8Array} @@ -1326,20 +1415,35 @@ function loadDatabase(hooks) { return cls; } + /** + * @template ST + * @type {(typeof SearchTreeBranches)&{"ALPHABITMAP_CHARS": number[], "width": number}} + */ const SearchTreeBranchesShortAlphaBitmap = makeSearchTreeBranchesAlphaBitmapClass(SHORT_ALPHABITMAP_CHARS, 3); + /** + * @template ST + * @type {(typeof SearchTreeBranches)&{"ALPHABITMAP_CHARS": number[], "width": number}} + */ const SearchTreeBranchesLongAlphaBitmap = makeSearchTreeBranchesAlphaBitmapClass(LONG_ALPHABITMAP_CHARS, 4); /** - * A [suffix tree], used for name-based search. + * @typedef {PrefixSearchTree|SuffixSearchTree} SearchTree + * @typedef {PrefixTrie|SuffixTrie} Trie + */ + + /** + * An interleaved [prefix] and [suffix tree], + * used for name-based search. * - * This data structure is used to drive substring matches, + * This data structure is used to drive prefix matches, * such as matching the query "link" to `LinkedList`, * and Lev-distance matches, such as matching the * query "hahsmap" to `HashMap`. * + * [prefix tree]: https://en.wikipedia.org/wiki/Prefix_tree * [suffix tree]: https://en.wikipedia.org/wiki/Suffix_tree * * branches @@ -1358,17 +1462,17 @@ function loadDatabase(hooks) { * will include these. * * @type {{ - * might_have_prefix_branches: SearchTreeBranches, - * branches: SearchTreeBranches, + * might_have_prefix_branches: SearchTreeBranches, + * branches: SearchTreeBranches, * data: Uint8Array, * leaves_suffix: RoaringBitmap, * leaves_whole: RoaringBitmap, * }} */ - class SearchTree { + class PrefixSearchTree { /** - * @param {SearchTreeBranches} branches - * @param {SearchTreeBranches} might_have_prefix_branches + * @param {SearchTreeBranches} branches + * @param {SearchTreeBranches} might_have_prefix_branches * @param {Uint8Array} data * @param {RoaringBitmap} leaves_whole * @param {RoaringBitmap} leaves_suffix @@ -1392,25 +1496,31 @@ function loadDatabase(hooks) { * A Trie pointer refers to a single node in a logical decompressed search tree * (the real search tree is compressed). * - * @return {Trie} + * @param {DataColumn} dataColumn + * @param {Uint8ArraySearchPattern} searchPattern + * @return {PrefixTrie} */ - trie() { - return new Trie(this, 0); + trie(dataColumn, searchPattern) { + return new PrefixTrie(this, 0, dataColumn, searchPattern); } /** * Return the trie representing `name` * @param {Uint8Array|string} name + * @param {DataColumn} dataColumn * @returns {Promise} */ - async search(name) { + async search(name, dataColumn) { if (typeof name === "string") { const utf8encoder = new TextEncoder(); name = utf8encoder.encode(name); } - let trie = this.trie(); + const searchPattern = new Uint8ArraySearchPattern(name); + /** @type {Trie} */ + let trie = this.trie(dataColumn, searchPattern); for (const datum of name) { // code point definitely exists + /** @type {Promise?} */ const newTrie = trie.child(datum); if (newTrie) { trie = await newTrie; @@ -1423,26 +1533,28 @@ function loadDatabase(hooks) { /** * @param {Uint8Array|string} name + * @param {DataColumn} dataColumn * @returns {AsyncGenerator} */ - async* searchLev(name) { + async* searchLev(name, dataColumn) { if (typeof name === "string") { const utf8encoder = new TextEncoder(); name = utf8encoder.encode(name); } const w = name.length; if (w < 3) { - const trie = await this.search(name); + const trie = await this.search(name, dataColumn); if (trie !== null) { yield trie; } return; } + const searchPattern = new Uint8ArraySearchPattern(name); const levParams = w >= 6 ? new Lev2TParametricDescription(w) : new Lev1TParametricDescription(w); /** @type {Array<[Promise, number]>} */ - const stack = [[Promise.resolve(this.trie()), 0]]; + const stack = [[Promise.resolve(this.trie(dataColumn, searchPattern)), 0]]; const n = levParams.n; while (stack.length !== 0) { // It's not empty @@ -1475,20 +1587,29 @@ function loadDatabase(hooks) { } } } + + /** @returns {RoaringBitmap} */ + getCurrentLeaves() { + return this.leaves_whole.union(this.leaves_suffix); + } } /** * A representation of a set of strings in the search index, * as a subset of the entire tree. */ - class Trie { + class PrefixTrie { /** - * @param {SearchTree} tree + * @param {PrefixSearchTree} tree * @param {number} offset + * @param {DataColumn} dataColumn + * @param {Uint8ArraySearchPattern} searchPattern */ - constructor(tree, offset) { + constructor(tree, offset, dataColumn, searchPattern) { this.tree = tree; this.offset = offset; + this.dataColumn = dataColumn; + this.searchPattern = searchPattern; } /** @@ -1514,7 +1635,28 @@ function loadDatabase(hooks) { const current_layer = layer; layer = []; for await (const tree of current_layer) { - yield tree.leaves_whole.union(tree.leaves_suffix); + /** @type {number[]?} */ + let rejected = null; + let leaves = tree.getCurrentLeaves(); + for (const leaf of leaves.entries()) { + const haystack = await this.dataColumn.at(leaf); + if (haystack === undefined || !this.searchPattern.matches(haystack)) { + if (!rejected) { + rejected = []; + } + rejected.push(leaf); + } + } + if (rejected) { + if (leaves.cardinality() !== rejected.length) { + for (const rej of rejected) { + leaves = leaves.remove(rej); + } + yield leaves; + } + } else { + yield leaves; + } } /** @type {HashTable<[number, SearchTree][]>} */ const subnodes = new HashTable(); @@ -1548,12 +1690,14 @@ function loadDatabase(hooks) { const res = registry.searchTreeLoadByNodeID(newnode); for (const [byte, node] of subnode_list) { const branches = node.branches; - const might_have_prefix_branches = node.might_have_prefix_branches; const i = branches.getIndex(byte); branches.subtrees[i] = res; - const mhpI = might_have_prefix_branches.getIndex(byte); - if (mhpI !== -1) { - might_have_prefix_branches.subtrees[mhpI] = res; + if (node instanceof PrefixSearchTree) { + const might_have_prefix_branches = node.might_have_prefix_branches; + const mhpI = might_have_prefix_branches.getIndex(byte); + if (mhpI !== -1) { + might_have_prefix_branches.subtrees[mhpI] = res; + } } } layer.push(res); @@ -1581,6 +1725,9 @@ function loadDatabase(hooks) { // if we want to do them in order) for (const {node, len} of current_layer) { const tree = await node; + if (!(tree instanceof PrefixSearchTree)) { + continue; + } const length = len + tree.data.length; if (minLength === null || length < minLength) { minLength = length; @@ -1637,10 +1784,13 @@ function loadDatabase(hooks) { } } // if we still have more subtrees to walk, then keep going - /** @type {HashTable<{byte: number, tree: SearchTree, len: number}[]>} */ + /** @type {HashTable<{byte: number, tree: PrefixSearchTree, len: number}[]>} */ const subnodes = new HashTable(); for await (const {node, len} of current_layer) { const tree = await node; + if (!(tree instanceof PrefixSearchTree)) { + continue; + } const length = len + tree.data.length; const mhp_branches = tree.might_have_prefix_branches; const l = mhp_branches.subtrees.length; @@ -1663,8 +1813,6 @@ function loadDatabase(hooks) { subnode_list.push({byte, tree, len}); } } - } else { - throw new Error(`malformed tree; index ${i} does not exist`); } } } @@ -1728,14 +1876,21 @@ function loadDatabase(hooks) { this.tree.might_have_prefix_branches.subtrees[mhpI] = node; } } - nodes.push([k, node.then(node => node.trie())]); + nodes.push([k, node.then(node => { + return node.trie(this.dataColumn, this.searchPattern); + })]); i += 1; } return nodes; } else { /** @type {number} */ const codePoint = data[this.offset]; - const trie = new Trie(this.tree, this.offset + 1); + const trie = new PrefixTrie( + this.tree, + this.offset + 1, + this.dataColumn, + this.searchPattern, + ); return [[codePoint, Promise.resolve(trie)]]; } } @@ -1777,14 +1932,21 @@ function loadDatabase(hooks) { this.tree.might_have_prefix_branches.subtrees[i] = node; this.tree.branches.subtrees[this.tree.branches.getIndex(k)] = node; } - nodes.push([k, node.then(node => node.trie())]); + nodes.push([k, node.then(node => { + return node.trie(this.dataColumn, this.searchPattern); + })]); i += 1; } return nodes; } else { /** @type {number} */ const codePoint = data[this.offset]; - const trie = new Trie(this.tree, this.offset + 1); + const trie = new PrefixTrie( + this.tree, + this.offset + 1, + this.dataColumn, + this.searchPattern, + ); return [[codePoint, Promise.resolve(trie)]]; } } @@ -1811,10 +1973,275 @@ function loadDatabase(hooks) { this.tree.might_have_prefix_branches.subtrees[mhpI] = branch; } } - return branch.then(branch => branch.trie()); + return branch.then(branch => branch.trie(this.dataColumn, this.searchPattern)); } } else if (this.tree.data[this.offset] === byte) { - return Promise.resolve(new Trie(this.tree, this.offset + 1)); + return Promise.resolve(new PrefixTrie( + this.tree, + this.offset + 1, + this.dataColumn, + this.searchPattern, + )); + } + return null; + } + } + /** + * A [suffix tree], used for name-based search. + * + * This data structure is used to drive substring matches, + * such as matching the query "inked" to `LinkedList`. + * + * [suffix tree]: https://en.wikipedia.org/wiki/Suffix_tree + * + * Suffix trees do not actually carry the intermediate data + * between branches, so, in order to validate the results, + * they must go through a filtering step at the end. + * Suffix trees also cannot match lev and exact matches, + * so those just return empty sets. + * + * branches + * : A sorted-array map of subtrees. + * + * dataLen + * : The length of the substring used by this node. + * + * leaves_suffix + * : The IDs of every entry that matches. Levenshtein matches + * won't include these. + * + * @type {{ + * branches: SearchTreeBranches, + * dataLen: number, + * leaves_suffix: RoaringBitmap, + * }} + */ + class SuffixSearchTree { + /** + * @param {SearchTreeBranches} branches + * @param {number} dataLen + * @param {RoaringBitmap} leaves_suffix + */ + constructor( + branches, + dataLen, + leaves_suffix, + ) { + this.branches = branches; + this.dataLen = dataLen; + this.leaves_suffix = leaves_suffix; + } + /** + * Returns the Trie for the root node. + * + * A Trie pointer refers to a single node in a logical decompressed search tree + * (the real search tree is compressed). + * + * @param {DataColumn} dataColumn + * @param {Uint8ArraySearchPattern} searchPattern + * @return {Trie} + */ + trie(dataColumn, searchPattern) { + return new SuffixTrie(this, 0, dataColumn, searchPattern); + } + + /** + * Return the trie representing `name` + * @param {Uint8Array|string} name + * @param {DataColumn} dataColumn + * @returns {Promise} + */ + async search(name, dataColumn) { + if (typeof name === "string") { + const utf8encoder = new TextEncoder(); + name = utf8encoder.encode(name); + } + const searchPattern = new Uint8ArraySearchPattern(name); + let trie = this.trie(dataColumn, searchPattern); + for (const datum of name) { + // code point definitely exists + const newTrie = trie.child(datum); + if (newTrie) { + trie = await newTrie; + } else { + return null; + } + } + return trie; + } + + /** + * @param {Uint8Array|string} _name + * @param {DataColumn} _dataColumn + * @returns {AsyncGenerator} + */ + async* searchLev(_name, _dataColumn) { + // this function only returns whole-string matches, + // which pure-suffix nodes don't have, so is + // intentionally blank + } + + /** @returns {RoaringBitmap} */ + getCurrentLeaves() { + return this.leaves_suffix; + } + } + + /** + * A representation of a set of strings in the search index, + * as a subset of the entire tree (suffix-only). + */ + class SuffixTrie { + /** + * @param {SuffixSearchTree} tree + * @param {number} offset + * @param {DataColumn} dataColumn + * @param {Uint8ArraySearchPattern} searchPattern + */ + constructor(tree, offset, dataColumn, searchPattern) { + this.tree = tree; + this.offset = offset; + this.dataColumn = dataColumn; + this.searchPattern = searchPattern; + } + + /** + * All exact matches for the string represented by this node. + * Since pure-suffix nodes have no exactly-matching children, + * this function returns the empty bitmap. + * @returns {RoaringBitmap} + */ + matches() { + return EMPTY_BITMAP; + } + + /** + * All matches for strings that contain the string represented by this node. + * @returns {AsyncGenerator} + */ + async* substringMatches() { + /** @type {Promise[]} */ + let layer = [Promise.resolve(this.tree)]; + while (layer.length) { + const current_layer = layer; + layer = []; + for await (const tree of current_layer) { + /** @type {number[]?} */ + let rejected = null; + let leaves = tree.getCurrentLeaves(); + for (const leaf of leaves.entries()) { + const haystack = await this.dataColumn.at(leaf); + if (haystack === undefined || !this.searchPattern.matches(haystack)) { + if (!rejected) { + rejected = []; + } + rejected.push(leaf); + } + } + if (rejected) { + if (leaves.cardinality() !== rejected.length) { + for (const rej of rejected) { + leaves = leaves.remove(rej); + } + yield leaves; + } + } else { + yield leaves; + } + } + /** @type {HashTable<[number, SearchTree][]>} */ + const subnodes = new HashTable(); + for await (const node of current_layer) { + const branches = node.branches; + const l = branches.subtrees.length; + for (let i = 0; i < l; ++i) { + const subtree = branches.subtrees[i]; + if (subtree) { + layer.push(subtree); + } else if (subtree === null) { + const newnode = branches.getNodeID(i); + if (!newnode) { + throw new Error(`malformed tree; no node for index ${i}`); + } else { + let subnode_list = subnodes.get(newnode); + if (!subnode_list) { + subnode_list = [[i, node]]; + subnodes.set(newnode, subnode_list); + } else { + subnode_list.push([i, node]); + } + } + } else { + throw new Error(`malformed tree; index ${i} does not exist`); + } + } + } + for (const [newnode, subnode_list] of subnodes.entries()) { + const res = registry.searchTreeLoadByNodeID(newnode); + for (const [i, node] of subnode_list) { + const branches = node.branches; + branches.subtrees[i] = res; + } + layer.push(res); + } + } + } + + /** + * All matches for strings that start with the string represented by this node. + * Since this is a pure-suffix node, there aren't any. + * @returns {AsyncGenerator} + */ + async* prefixMatches() { + // this function only returns prefix matches, + // which pure-suffix nodes don't have, so is + // intentionally blank + } + + /** + * Returns all keys that are children of this node. + * @returns {Uint8Array} + */ + keysExcludeSuffixOnly() { + return EMPTY_UINT8; + } + + /** + * Returns all nodes that are direct children of this node. + * @returns {[number, Promise][]} + */ + childrenExcludeSuffixOnly() { + return []; + } + + /** + * Returns a single node that is a direct child of this node. + * @param {number} byte + * @returns {Promise?} + */ + child(byte) { + if (this.offset === this.tree.dataLen) { + const i = this.tree.branches.getIndex(byte); + if (i !== -1) { + /** @type {Promise?} */ + let branch = this.tree.branches.subtrees[i]; + if (branch === null) { + const newnode = this.tree.branches.getNodeID(i); + if (!newnode) { + throw new Error(`malformed tree; no node for key ${byte}`); + } + branch = registry.searchTreeLoadByNodeID(newnode); + this.tree.branches.subtrees[i] = branch; + } + return branch.then(branch => branch.trie(this.dataColumn, this.searchPattern)); + } + } else { + return Promise.resolve(new SuffixTrie( + this.tree, + this.offset + 1, + this.dataColumn, + this.searchPattern, + )); } return null; } @@ -1827,8 +2254,10 @@ function loadDatabase(hooks) { * @param {Uint8Array} hashes * @param {RoaringBitmap} emptyset * @param {string} name + * @param {SearchTree?} searchTree */ - constructor(counts, hashes, emptyset, name) { + constructor(counts, hashes, emptyset, name, searchTree) { + this.searchTree = searchTree; this.hashes = hashes; this.emptyset = emptyset; this.name = name; @@ -1883,7 +2312,7 @@ function loadDatabase(hooks) { const {hash, end} = this.buckets[idx]; let data = this.buckets[idx].data; if (data === null) { - const dataSansEmptyset = await registry.dataLoadByNameAndHash( + const dataSansEmptysetOrig = await registry.dataLoadByNameAndHash( this.name, hash, ); @@ -1893,6 +2322,7 @@ function loadDatabase(hooks) { if (data !== null) { return (await data)[id - start]; } + const dataSansEmptyset = [...dataSansEmptysetOrig]; /** @type {(Uint8Array[])|null} */ let dataWithEmptyset = null; let pos = start; @@ -1924,6 +2354,24 @@ function loadDatabase(hooks) { } } } + /** + * Search by exact substring + * @param {Uint8Array|string} name + * @returns {Promise} + */ + async search(name) { + return await (this.searchTree ? this.searchTree.search(name, this) : null); + } + /** + * Search by whole, inexact match + * @param {Uint8Array|string} name + * @returns {AsyncGenerator} + */ + async *searchLev(name) { + if (this.searchTree) { + yield* this.searchTree.searchLev(name, this); + } + } } class Database { @@ -2015,7 +2463,7 @@ function loadDatabase(hooks) { const data_history = []; let canonical = EMPTY_UINT8; /** @type {SearchTree} */ - let tree = new SearchTree( + let tree = new PrefixSearchTree( EMPTY_SEARCH_TREE_BRANCHES, EMPTY_SEARCH_TREE_BRANCHES, EMPTY_UINT8, @@ -2029,8 +2477,8 @@ function loadDatabase(hooks) { * @returns {{ * "cpbranches": Uint8Array, * "csbranches": Uint8Array, - * "might_have_prefix_branches": SearchTreeBranches, - * "branches": SearchTreeBranches, + * "might_have_prefix_branches": SearchTreeBranches, + * "branches": SearchTreeBranches, * "cpnodes": Uint8Array, * "csnodes": Uint8Array, * "consumed_len_bytes": number, @@ -2051,6 +2499,12 @@ function loadDatabase(hooks) { const start_point = i; let cplen; let cslen; + /** + * @type {( + * typeof SearchTreeBranches & + * {"ALPHABITMAP_CHARS": number[], "width": number} + * )?} + */ let alphabitmap = null; if (is_pure_suffixes_only_node) { cplen = 0; @@ -2299,6 +2753,8 @@ function loadDatabase(hooks) { if (is_data_compressed) { data = data_history[data_history.length - dlen - 1]; dlen = data.length; + } else if (is_pure_suffixes_only_node) { + data = EMPTY_UINT8; } else { data = dlen === 0 ? EMPTY_UINT8 : @@ -2319,80 +2775,109 @@ function loadDatabase(hooks) { let whole; let suffix; if (is_pure_suffixes_only_node) { - whole = EMPTY_BITMAP; suffix = input[i] === 0 ? EMPTY_BITMAP1 : new RoaringBitmap(input, i); i += suffix.consumed_len_bytes; - } else if (input[i] === 0xff) { - whole = EMPTY_BITMAP; - suffix = EMPTY_BITMAP1; - i += 1; - } else { - whole = input[i] === 0 ? - EMPTY_BITMAP1 : - new RoaringBitmap(input, i); - i += whole.consumed_len_bytes; - suffix = input[i] === 0 ? - EMPTY_BITMAP1 : - new RoaringBitmap(input, i); - i += suffix.consumed_len_bytes; - } - tree = new SearchTree( - branches, - might_have_prefix_branches, - data, - whole, - suffix, - ); - const clen = ( - (is_pure_suffixes_only_node ? 3 : 4) + // lengths of children and data - dlen + - cpnodes.length + csnodes.length + - cpbranches.length + csbranches.length + - whole.consumed_len_bytes + - suffix.consumed_len_bytes - ); - if (canonical.length < clen) { - canonical = new Uint8Array(clen); - } - let ci = 0; - canonical[ci] = is_pure_suffixes_only_node ? 1 : 0; - ci += 1; - canonical[ci] = dlen; - ci += 1; - canonical.set(data, ci); - ci += dlen; - canonical[ci] = input[coffset]; - ci += 1; - if (!is_pure_suffixes_only_node) { - canonical[ci] = input[coffset + 1]; + tree = new SuffixSearchTree( + branches, + dlen, + suffix, + ); + const clen = ( + 3 + // lengths of children and data + csnodes.length + + csbranches.length + + suffix.consumed_len_bytes + ); + if (canonical.length < clen) { + canonical = new Uint8Array(clen); + } + let ci = 0; + canonical[ci] = 1; ci += 1; + canonical[ci] = dlen; + ci += 1; + canonical[ci] = input[coffset]; // suffix child count + ci += 1; + canonical.set(csnodes, ci); + ci += csnodes.length; + canonical.set(csbranches, ci); + ci += csbranches.length; + const leavesOffset = i - suffix.consumed_len_bytes; + for (let j = leavesOffset; j < i; j += 1) { + canonical[ci + j - leavesOffset] = input[j]; + } + siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash); + } else { + if (input[i] === 0xff) { + whole = EMPTY_BITMAP; + suffix = EMPTY_BITMAP1; + i += 1; + } else { + whole = input[i] === 0 ? + EMPTY_BITMAP1 : + new RoaringBitmap(input, i); + i += whole.consumed_len_bytes; + suffix = input[i] === 0 ? + EMPTY_BITMAP1 : + new RoaringBitmap(input, i); + i += suffix.consumed_len_bytes; + } + tree = new PrefixSearchTree( + branches, + might_have_prefix_branches, + data, + whole, + suffix, + ); + const clen = ( + 4 + // lengths of children and data + dlen + + cpnodes.length + csnodes.length + + cpbranches.length + csbranches.length + + whole.consumed_len_bytes + + suffix.consumed_len_bytes + ); + if (canonical.length < clen) { + canonical = new Uint8Array(clen); + } + let ci = 0; + canonical[ci] = 0; + ci += 1; + canonical[ci] = dlen; + ci += 1; + canonical.set(data, ci); + ci += data.length; + canonical[ci] = input[coffset]; // prefix child count + ci += 1; + canonical[ci] = input[coffset + 1]; // suffix child count + ci += 1; + canonical.set(cpnodes, ci); + ci += cpnodes.length; + canonical.set(csnodes, ci); + ci += csnodes.length; + canonical.set(cpbranches, ci); + ci += cpbranches.length; + canonical.set(csbranches, ci); + ci += csbranches.length; + const leavesOffset = i - whole.consumed_len_bytes - suffix.consumed_len_bytes; + for (let j = leavesOffset; j < i; j += 1) { + canonical[ci + j - leavesOffset] = input[j]; + } + siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash); } - canonical.set(cpnodes, ci); - ci += cpnodes.length; - canonical.set(csnodes, ci); - ci += csnodes.length; - canonical.set(cpbranches, ci); - ci += cpbranches.length; - canonical.set(csbranches, ci); - ci += csbranches.length; - const leavesOffset = i - whole.consumed_len_bytes - suffix.consumed_len_bytes; - for (let j = leavesOffset; j < i; j += 1) { - canonical[ci + j - leavesOffset] = input[j]; - } - siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash); hash[2] &= 0x7f; } else { // uncompressed node const dlen = input [i + 1]; i += 2; - if (dlen === 0) { + if (dlen === 0 || is_pure_suffixes_only_node) { data = EMPTY_UINT8; } else { data = new Uint8Array(input.buffer, i + input.byteOffset, dlen); + i += dlen; } - i += dlen; const { consumed_len_bytes: branches_consumed_len_bytes, branches, @@ -2427,13 +2912,19 @@ function loadDatabase(hooks) { i - start, ), 0, 0, 0, 0, hash); hash[2] &= 0x7f; - tree = new SearchTree( - branches, - might_have_prefix_branches, - data, - whole, - suffix, - ); + tree = is_pure_suffixes_only_node ? + new SuffixSearchTree( + branches, + dlen, + suffix, + ) : + new PrefixSearchTree( + branches, + might_have_prefix_branches, + data, + whole, + suffix, + ); } hash_history.push({hash: truncatedHash.slice(), used: false}); if (data.length !== 0) { @@ -2454,20 +2945,22 @@ function loadDatabase(hooks) { } j += 1; } - const tree_mhp_branch_nodeids = tree.might_have_prefix_branches.nodeids; - const tree_mhp_branch_subtrees = tree.might_have_prefix_branches.subtrees; - j = 0; - lb = tree.might_have_prefix_branches.subtrees.length; - while (j < lb) { - // node id with a 1 in its most significant bit is inlined, and, so - // it won't be in the stash - if ((tree_mhp_branch_nodeids[j * 6] & 0x80) === 0) { - const subtree = stash.getWithOffsetKey(tree_mhp_branch_nodeids, j * 6); - if (subtree !== undefined) { - tree_mhp_branch_subtrees[j] = Promise.resolve(subtree); + if (tree instanceof PrefixSearchTree) { + const tree_mhp_branch_nodeids = tree.might_have_prefix_branches.nodeids; + const tree_mhp_branch_subtrees = tree.might_have_prefix_branches.subtrees; + j = 0; + lb = tree.might_have_prefix_branches.subtrees.length; + while (j < lb) { + // node id with a 1 in its most significant bit is inlined, and, so + // it won't be in the stash + if ((tree_mhp_branch_nodeids[j * 6] & 0x80) === 0) { + const subtree = stash.getWithOffsetKey(tree_mhp_branch_nodeids, j * 6); + if (subtree !== undefined) { + tree_mhp_branch_subtrees[j] = Promise.resolve(subtree); + } } + j += 1; } - j += 1; } if (i !== l) { stash.set(truncatedHash, tree); diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 16034c118272..471e966e2c24 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, dcx: DiagCtxtHandle<'_>, + loaded_paths: &mut Vec, ) -> 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: . - // - // 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 index a6c58d43051d..761c4658d007 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit a6c58d43051d01d83f55a3e61ef5f5b2b0dd6bd9 +Subproject commit 761c4658d0079d607e6d33cf0c060e61a617cad3 diff --git a/src/tools/clippy/.cargo/config.toml b/src/tools/clippy/.cargo/config.toml index d9c635df5dc7..a09bf95e87bd 100644 --- a/src/tools/clippy/.cargo/config.toml +++ b/src/tools/clippy/.cargo/config.toml @@ -23,3 +23,10 @@ split-debuginfo = "unpacked" rustflags = ["--remap-path-prefix", "=clippy_dev"] [profile.dev.package.lintcheck] rustflags = ["--remap-path-prefix", "=lintcheck"] + +# quine-mc_cluskey makes up a significant part of the runtime in dogfood +# due to the number of conditions in the clippy_lints crate +# and enabling optimizations for that specific dependency helps a bit +# without increasing total build times. +[profile.dev.package.quine-mc_cluskey] +opt-level = 3 diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index bc60b1c57f7d..eb2a76a81836 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -30,6 +30,8 @@ Current stable, released 2025-08-07 * Removed superseded lints: `transmute_float_to_int`, `transmute_int_to_char`, `transmute_int_to_float`, `transmute_num_to_bytes` (now in rustc) [#14703](https://github.com/rust-lang/rust-clippy/pull/14703) +* Move [`uninlined_format_args`] to `pedantic` (from `style`, now allow-by-default) + [#15287](https://github.com/rust-lang/rust-clippy/pull/15287) ### Enhancements @@ -74,6 +76,9 @@ Current stable, released 2025-08-07 [#14719](https://github.com/rust-lang/rust-clippy/pull/14719) * [`unnecessary_to_owned`] fixed FP when map key is a reference [#14834](https://github.com/rust-lang/rust-clippy/pull/14834) +* [`swap_with_temporary`]: fix false positive leading to different semantics + being suggested, and use the right number of dereferences in suggestion + [#15172](https://github.com/rust-lang/rust-clippy/pull/15172) ### ICE Fixes @@ -6707,6 +6712,7 @@ Released 2018-09-13 [`check-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-inconsistent-struct-field-initializers [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items [`cognitive-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cognitive-complexity-threshold +[`const-literal-digits-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#const-literal-digits-threshold [`disallowed-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-macros [`disallowed-methods`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-methods [`disallowed-names`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-names diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 05590ff7b1c9..c2d080cd96a1 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -485,6 +485,16 @@ The maximum cognitive complexity a function can have * [`cognitive_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity) +## `const-literal-digits-threshold` +The minimum digits a const float literal must have to supress the `excessive_precicion` lint + +**Default Value:** `30` + +--- +**Affected lints:** +* [`excessive_precision`](https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision) + + ## `disallowed-macros` The list of disallowed macros, written as fully qualified paths. @@ -555,7 +565,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "InfiniBand", "RoCE", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** @@ -873,7 +883,6 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`needless_borrow`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow) * [`non_std_lazy_statics`](https://rust-lang.github.io/rust-clippy/master/index.html#non_std_lazy_statics) * [`option_as_ref_deref`](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref) -* [`option_map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or) * [`ptr_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr) * [`question_mark`](https://rust-lang.github.io/rust-clippy/master/index.html#question_mark) * [`redundant_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names) @@ -881,7 +890,6 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`repeat_vec_with_capacity`](https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity) * [`same_item_push`](https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push) * [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) -* [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) * [`to_digit_is_some`](https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some) * [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml index 77573105d86a..d9bcfd17606e 100644 --- a/src/tools/clippy/clippy.toml +++ b/src/tools/clippy/clippy.toml @@ -6,12 +6,12 @@ lint-commented-code = true [[disallowed-methods]] path = "rustc_lint::context::LintContext::lint" -reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" +reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead" [[disallowed-methods]] path = "rustc_lint::context::LintContext::span_lint" -reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead" +reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead" [[disallowed-methods]] path = "rustc_middle::ty::context::TyCtxt::node_span_lint" -reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead" +reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead" diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 2ad3f2efcdd7..2f28f6175ad8 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -33,6 +33,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", + "InfiniBand", "RoCE", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "WebAssembly", "NaN", "NaNs", @@ -569,6 +570,9 @@ define_Conf! { /// The maximum cognitive complexity a function can have #[lints(cognitive_complexity)] cognitive_complexity_threshold: u64 = 25, + /// The minimum digits a const float literal must have to supress the `excessive_precicion` lint + #[lints(excessive_precision)] + const_literal_digits_threshold: usize = 30, /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. /// /// Use the Cognitive Complexity lint instead. @@ -775,7 +779,6 @@ define_Conf! { needless_borrow, non_std_lazy_statics, option_as_ref_deref, - option_map_unwrap_or, ptr_as_ptr, question_mark, redundant_field_names, @@ -783,7 +786,6 @@ define_Conf! { repeat_vec_with_capacity, same_item_push, seek_from_current, - seek_rewind, to_digit_is_some, transmute_ptr_to_ref, tuple_array_conversions, diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index b9e6de79cc05..70184ee2ca59 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -27,6 +27,10 @@ url = "2.2" [dev-dependencies] walkdir = "2.3" +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = ['cfg(bootstrap)'] + [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)] rustc_private = true diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs index 6f2a6a36a38b..08253b0c4995 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs @@ -3,10 +3,10 @@ use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_no use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item}; use clippy_utils::usage::local_used_after_expr; -use clippy_utils::{is_expr_final_block_expr, path_res, sym}; +use clippy_utils::{path_res, sym}; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; @@ -77,17 +77,20 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { _ => return, }; span_lint_and_then(cx, ASSERTIONS_ON_RESULT_STATES, macro_call.span, message, |diag| { - let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" }; let mut app = Applicability::MachineApplicable; - diag.span_suggestion( - macro_call.span, - "replace with", - format!( - "{}.{replacement}(){semicolon}", - snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0 - ), - app, - ); + let recv = snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0; + + // `assert!` doesn't return anything, but `Result::unwrap(_err)` does, so we might need to add a + // semicolon to the suggestion to avoid leaking the type + let sugg = match cx.tcx.parent_hir_node(e.hir_id) { + // trailing expr of a block + Node::Block(..) => format!("{recv}.{replacement}();"), + // already has a trailing semicolon + Node::Stmt(..) => format!("{recv}.{replacement}()"), + // this is the last-resort option, because it's rather verbose + _ => format!("{{ {recv}.{replacement}(); }}"), + }; + diag.span_suggestion(macro_call.span, "replace with", sugg, app); }); } } diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index 013819b0da8a..1a10db291cde 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -1,8 +1,12 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet; +use clippy_utils::is_expr_async_block; +use clippy_utils::source::walk_span_to_context; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath}; +use rustc_hir::{ + Block, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -87,31 +91,37 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { let expr_ty = typeck_results.expr_ty(body_expr); if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { - let return_expr_span = match &body_expr.kind { - // XXXkhuey there has to be a better way. - ExprKind::Block(block, _) => block.expr.map(|e| e.span), - ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span), - _ => None, + let (return_expr, return_expr_span) = match &body_expr.kind { + ExprKind::Block(Block { expr: Some(e), .. }, _) => (*e, e.span), + ExprKind::Path(QPath::Resolved(_, path)) => (body_expr, path.span), + _ => return, }; - if let Some(return_expr_span) = return_expr_span { - span_lint_hir_and_then( - cx, - ASYNC_YIELDS_ASYNC, - body_expr.hir_id, - return_expr_span, - "an async construct yields a type which is itself awaitable", - |db| { - db.span_label(body_expr.span, "outer async construct"); - db.span_label(return_expr_span, "awaitable value not awaited"); - db.span_suggestion( - return_expr_span, - "consider awaiting this value", - format!("{}.await", snippet(cx, return_expr_span, "..")), - Applicability::MaybeIncorrect, - ); - }, - ); + + let return_expr_span = walk_span_to_context(return_expr_span, expr.span.ctxt()).unwrap_or(return_expr_span); + let mut applicability = Applicability::MaybeIncorrect; + let mut return_expr_snip = + Sugg::hir_with_context(cx, return_expr, expr.span.ctxt(), "..", &mut applicability); + if !is_expr_async_block(return_expr) { + return_expr_snip = return_expr_snip.maybe_paren(); } + + span_lint_hir_and_then( + cx, + ASYNC_YIELDS_ASYNC, + body_expr.hir_id, + return_expr_span, + "an async construct yields a type which is itself awaitable", + |db| { + db.span_label(body_expr.span, "outer async construct"); + db.span_label(return_expr_span, "awaitable value not awaited"); + db.span_suggestion( + return_expr_span, + "consider awaiting this value", + format!("{return_expr_snip}.await"), + applicability, + ); + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/bool_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_comparison.rs new file mode 100644 index 000000000000..722095909a6f --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/bool_comparison.rs @@ -0,0 +1,179 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; +use clippy_utils::{is_expn_of, peel_blocks, sym}; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::Span; +use rustc_span::source_map::Spanned; + +declare_clippy_lint! { + /// ### What it does + /// Checks for expressions of the form `x == true`, + /// `x != true` and order comparisons such as `x < true` (or vice versa) and + /// suggest using the variable directly. + /// + /// ### Why is this bad? + /// Unnecessary code. + /// + /// ### Example + /// ```rust,ignore + /// if x == true {} + /// if y == false {} + /// ``` + /// use `x` directly: + /// ```rust,ignore + /// if x {} + /// if !y {} + /// ``` + #[clippy::version = "pre 1.29.0"] + pub BOOL_COMPARISON, + complexity, + "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`" +} + +declare_lint_pass!(BoolComparison => [BOOL_COMPARISON]); + +impl<'tcx> LateLintPass<'tcx> for BoolComparison { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if e.span.from_expansion() { + return; + } + + if let ExprKind::Binary(Spanned { node, .. }, left_side, right_side) = e.kind + && is_expn_of(left_side.span, sym::cfg).is_none() + && is_expn_of(right_side.span, sym::cfg).is_none() + && cx.typeck_results().expr_ty(left_side).is_bool() + && cx.typeck_results().expr_ty(right_side).is_bool() + { + let ignore_case = None::<(fn(_) -> _, &str)>; + let ignore_no_literal = None::<(fn(_, _) -> _, &str)>; + match node { + BinOpKind::Eq => { + let true_case = Some((|h| h, "equality checks against true are unnecessary")); + let false_case = Some(( + |h: Sugg<'tcx>| !h, + "equality checks against false can be replaced by a negation", + )); + check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); + }, + BinOpKind::Ne => { + let true_case = Some(( + |h: Sugg<'tcx>| !h, + "inequality checks against true can be replaced by a negation", + )); + let false_case = Some((|h| h, "inequality checks against false are unnecessary")); + check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); + }, + BinOpKind::Lt => check_comparison( + cx, + e, + ignore_case, + Some((|h| h, "greater than checks against false are unnecessary")), + Some(( + |h: Sugg<'tcx>| !h, + "less than comparison against true can be replaced by a negation", + )), + ignore_case, + Some(( + |l: Sugg<'tcx>, r: Sugg<'tcx>| (!l).bit_and(&r), + "order comparisons between booleans can be simplified", + )), + ), + BinOpKind::Gt => check_comparison( + cx, + e, + Some(( + |h: Sugg<'tcx>| !h, + "less than comparison against true can be replaced by a negation", + )), + ignore_case, + ignore_case, + Some((|h| h, "greater than checks against false are unnecessary")), + Some(( + |l: Sugg<'tcx>, r: Sugg<'tcx>| l.bit_and(&(!r)), + "order comparisons between booleans can be simplified", + )), + ), + _ => (), + } + } + } +} + +fn check_comparison<'a, 'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &'static str)>, +) { + if let ExprKind::Binary(_, left_side, right_side) = e.kind { + let mut applicability = Applicability::MachineApplicable; + // Eliminate parentheses in `e` by using the lo pos of lhs and hi pos of rhs, + // calling `source_callsite` make sure macros are handled correctly, see issue #9907 + let binop_span = left_side.span.source_callsite().to(right_side.span.source_callsite()); + + match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) { + (Some(true), None) => left_true.map_or((), |(h, m)| { + suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h); + }), + (None, Some(true)) => right_true.map_or((), |(h, m)| { + suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h); + }), + (Some(false), None) => left_false.map_or((), |(h, m)| { + suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h); + }), + (None, Some(false)) => right_false.map_or((), |(h, m)| { + suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h); + }), + (None, None) => no_literal.map_or((), |(h, m)| { + let left_side = Sugg::hir_with_context(cx, left_side, binop_span.ctxt(), "..", &mut applicability); + let right_side = Sugg::hir_with_context(cx, right_side, binop_span.ctxt(), "..", &mut applicability); + span_lint_and_sugg( + cx, + BOOL_COMPARISON, + binop_span, + m, + "try", + h(left_side, right_side).into_string(), + applicability, + ); + }), + _ => (), + } + } +} + +fn suggest_bool_comparison<'a, 'tcx>( + cx: &LateContext<'tcx>, + span: Span, + expr: &Expr<'_>, + mut app: Applicability, + message: &'static str, + conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>, +) { + let hint = Sugg::hir_with_context(cx, expr, span.ctxt(), "..", &mut app); + span_lint_and_sugg( + cx, + BOOL_COMPARISON, + span, + message, + "try", + conv_hint(hint).into_string(), + app, + ); +} + +fn fetch_bool_expr(expr: &Expr<'_>) -> Option { + if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind + && let LitKind::Bool(value) = lit_ptr.node + { + return Some(value); + } + None +} diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs index a1543cabd2f9..d78da9396faf 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -8,17 +8,12 @@ use rustc_middle::ty::{self, Ty}; use super::CAST_PTR_ALIGNMENT; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Cast(cast_expr, cast_to) = expr.kind { - if is_hir_ty_cfg_dependant(cx, cast_to) { - return; - } - let (cast_from, cast_to) = ( - cx.typeck_results().expr_ty(cast_expr), - cx.typeck_results().expr_ty(expr), - ); - lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); - } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>) { + lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); +} + +pub(super) fn check_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind && method_path.ident.name == sym::cast && let Some(generic_args) = method_path.args && let [GenericArg::Type(cast_to)] = generic_args.args @@ -74,14 +69,13 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { ExprKind::Call(func, [arg, ..]) if arg.hir_id == e.hir_id => { if let ExprKind::Path(path) = &func.kind && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() + && let Some(name) = cx.tcx.get_diagnostic_name(def_id) && matches!( - cx.tcx.get_diagnostic_name(def_id), - Some( - sym::ptr_write_unaligned - | sym::ptr_read_unaligned - | sym::intrinsics_unaligned_volatile_load - | sym::intrinsics_unaligned_volatile_store - ) + name, + sym::ptr_write_unaligned + | sym::ptr_read_unaligned + | sym::intrinsics_unaligned_volatile_load + | sym::intrinsics_unaligned_volatile_store ) { true diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 46b0c88d3fed..bce7b4c69cc6 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -1,10 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; +use clippy_utils::{get_parent_expr, is_no_std_crate}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::{self, Ty}; use rustc_span::sym; @@ -42,13 +44,52 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, let mut applicability = Applicability::MachineApplicable; let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0; let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0; + let krate = if is_no_std_crate(cx) { "core" } else { "std" }; span_lint_and_sugg( cx, CAST_SLICE_FROM_RAW_PARTS, span, format!("casting the result of `{func}` to {cast_to}"), "replace with", - format!("core::ptr::slice_{func}({ptr}, {len})"), + format!("{krate}::ptr::slice_{func}({ptr}, {len})"), + applicability, + ); + } +} + +/// Checks for implicit cast from slice reference to raw slice pointer. +pub(super) fn check_implicit_cast(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Call(fun, [ptr_arg, len_arg]) = expr.peel_blocks().kind + && let ExprKind::Path(ref qpath) = fun.kind + && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() + && let Some(rpk) = raw_parts_kind(cx, fun_def_id) + && !matches!(get_parent_expr(cx, expr).map(|e| e.kind), Some(ExprKind::Cast(..))) + && let [deref, borrow] = cx.typeck_results().expr_adjustments(expr) + && matches!(deref.kind, Adjust::Deref(..)) + && let Adjustment { + kind: Adjust::Borrow(AutoBorrow::RawPtr(..)), + target, + } = borrow + && let ty::RawPtr(pointee_ty, _) = target.kind() + && pointee_ty.is_slice() + && !expr.span.from_expansion() + { + let func = match rpk { + RawPartsKind::Immutable => "from_raw_parts", + RawPartsKind::Mutable => "from_raw_parts_mut", + }; + let mut applicability = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); + let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0; + let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0; + let krate = if is_no_std_crate(cx) { "core" } else { "std" }; + span_lint_and_sugg( + cx, + CAST_SLICE_FROM_RAW_PARTS, + expr.span, + format!("implicitly casting the result of `{func}` to `{target}`"), + "replace_with", + format!("{krate}::ptr::slice_{func}({ptr}, {len})"), applicability, ); } diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index e25df9dd249a..d2e62ee56e43 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -873,7 +873,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts { } char_lit_as_u8::check(cx, expr, cast_from_expr, cast_to); cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, self.msrv); + cast_ptr_alignment::check(cx, expr, cast_from, cast_to); ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); + ptr_as_ptr::check(cx, expr, cast_from_expr, cast_from, cast_to_hir, cast_to, self.msrv); as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to); fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to); confusing_method_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to); @@ -911,8 +913,10 @@ impl<'tcx> LateLintPass<'tcx> for Casts { if self.msrv.meets(cx, msrvs::RAW_REF_OP) { borrow_as_ptr::check_implicit_cast(cx, expr); } - cast_ptr_alignment::check(cx, expr); - ptr_as_ptr::check(cx, expr, self.msrv); + if self.msrv.meets(cx, msrvs::PTR_SLICE_RAW_PARTS) { + cast_slice_from_raw_parts::check_implicit_cast(cx, expr); + } + cast_ptr_alignment::check_cast_method(cx, expr); cast_slice_different_sizes::check(cx, expr, self.msrv); ptr_cast_constness::check_null_ptr_cast_method(cx, expr); } diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs index 890754090989..d012380cb762 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs @@ -4,9 +4,9 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Mutability, QPath, TyKind}; +use rustc_hir::{self as hir, Expr, ExprKind, QPath, TyKind}; use rustc_lint::LateContext; -use rustc_middle::ty; +use rustc_middle::ty::{self, Ty}; use rustc_span::{Span, sym}; use super::PTR_AS_PTR; @@ -26,13 +26,18 @@ impl OmitFollowedCastReason<'_> { } } -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv) { - if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind - && let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr)) - && let ty::RawPtr(_, from_mutbl) = cast_from.kind() +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + cast_from_expr: &Expr<'_>, + cast_from: Ty<'_>, + cast_to_hir: &hir::Ty<'_>, + cast_to: Ty<'tcx>, + msrv: Msrv, +) { + if let ty::RawPtr(_, from_mutbl) = cast_from.kind() && let ty::RawPtr(to_pointee_ty, to_mutbl) = cast_to.kind() - && matches!((from_mutbl, to_mutbl), - (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut)) + && from_mutbl == to_mutbl // The `U` in `pointer::cast` have to be `Sized` // as explained here: https://github.com/rust-lang/rust/issues/60602. && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) @@ -40,7 +45,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv) && !is_from_proc_macro(cx, expr) { let mut app = Applicability::MachineApplicable; - let turbofish = match &cast_to_hir_ty.kind { + let turbofish = match &cast_to_hir.kind { TyKind::Infer(()) => String::new(), TyKind::Ptr(mut_ty) => { if matches!(mut_ty.ty.kind, TyKind::Infer(())) { @@ -58,16 +63,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv) // following `cast` does not compile because it fails to infer what type is expected // as type argument to `std::ptr::ptr_null` or `std::ptr::ptr_null_mut`, so // we omit following `cast`: - let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind + let omit_cast = if let ExprKind::Call(func, []) = cast_from_expr.kind && let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind && let Some(method_defid) = path.res.opt_def_id() { - if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) { - OmitFollowedCastReason::Null(qpath) - } else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) { - OmitFollowedCastReason::NullMut(qpath) - } else { - OmitFollowedCastReason::None + match cx.tcx.get_diagnostic_name(method_defid) { + Some(sym::ptr_null) => OmitFollowedCastReason::Null(qpath), + Some(sym::ptr_null_mut) => OmitFollowedCastReason::NullMut(qpath), + _ => OmitFollowedCastReason::None, } } else { OmitFollowedCastReason::None @@ -78,7 +81,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv) let method = snippet_with_applicability(cx, qpath_span_without_turbofish(method), "..", &mut app); ("try call directly", format!("{method}{turbofish}()")) } else { - let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app); + let cast_expr_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "_", &mut app); ( "try `pointer::cast`, a safer alternative", diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs index c0c0a47f8551..c0f13f5e5782 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{std_or_core, sym}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Mutability, QPath}; +use rustc_hir::{self as hir, Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; @@ -12,26 +13,23 @@ use super::PTR_CAST_CONSTNESS; pub(super) fn check<'tcx>( cx: &LateContext<'_>, expr: &Expr<'_>, - cast_expr: &Expr<'_>, + cast_from_expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>, msrv: Msrv, ) { if let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind() && let ty::RawPtr(to_ty, to_mutbl) = cast_to.kind() - && matches!( - (from_mutbl, to_mutbl), - (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not) - ) + && from_mutbl != to_mutbl && from_ty == to_ty && !from_ty.has_erased_regions() { - if let ExprKind::Call(func, []) = cast_expr.kind + if let ExprKind::Call(func, []) = cast_from_expr.kind && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind && let Some(defid) = path.res.opt_def_id() && let Some(prefix) = std_or_core(cx) && let mut app = Applicability::MachineApplicable - && let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app)) + && let sugg = snippet_with_applicability(cx, cast_from_expr.span, "_", &mut app) && let Some((_, after_lt)) = sugg.split_once("::<") && let Some((source, target, target_func)) = match cx.tcx.get_diagnostic_name(defid) { Some(sym::ptr_null) => Some(("const", "mutable", "null_mut")), @@ -53,11 +51,17 @@ pub(super) fn check<'tcx>( if msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) { let mut app = Applicability::MachineApplicable; - let sugg = Sugg::hir_with_context(cx, cast_expr, expr.span.ctxt(), "_", &mut app); - let constness = match *to_mutbl { - Mutability::Not => "const", - Mutability::Mut => "mut", + let sugg = if let ExprKind::Cast(nested_from, nested_hir_ty) = cast_from_expr.kind + && let hir::TyKind::Ptr(ptr_ty) = nested_hir_ty.kind + && let hir::TyKind::Infer(()) = ptr_ty.ty.kind + { + // `(foo as *const _).cast_mut()` fails method name resolution + // avoid this by `as`-ing the full type + Sugg::hir_with_context(cx, nested_from, expr.span.ctxt(), "_", &mut app).as_ty(cast_from) + } else { + Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "_", &mut app) }; + let constness = to_mutbl.ptr_str(); span_lint_and_sugg( cx, @@ -73,8 +77,8 @@ pub(super) fn check<'tcx>( } pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::MethodCall(method, cast_expr, [], _) = expr.kind - && let ExprKind::Call(func, []) = cast_expr.kind + if let ExprKind::MethodCall(method, cast_from_expr, [], _) = expr.kind + && let ExprKind::Call(func, []) = cast_from_expr.kind && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind && let Some(defid) = path.res.opt_def_id() && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.name) { @@ -84,7 +88,7 @@ pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) } && let Some(prefix) = std_or_core(cx) && let mut app = Applicability::MachineApplicable - && let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app)) + && let sugg = snippet_with_applicability(cx, cast_from_expr.span, "_", &mut app) && let Some((_, after_lt)) = sugg.split_once("::<") { span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 8f95c63a854f..7646aa48b772 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -23,8 +23,8 @@ declare_clippy_lint! { /// /// ### Known problems /// The true Cognitive Complexity of a method is not something we can - /// calculate using modern technology. This lint has been left in the - /// `nursery` so as to not mislead users into using this lint as a + /// calculate using modern technology. This lint has been left in + /// `restriction` so as to not mislead users into using this lint as a /// measurement tool. /// /// For more detailed information, see [rust-clippy#3793](https://github.com/rust-lang/rust-clippy/issues/3793) diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index e67e8d9070f2..d0c7443a4a4b 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -35,6 +35,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::await_holding_invalid::AWAIT_HOLDING_REFCELL_REF_INFO, crate::blocks_in_conditions::BLOCKS_IN_CONDITIONS_INFO, crate::bool_assert_comparison::BOOL_ASSERT_COMPARISON_INFO, + crate::bool_comparison::BOOL_COMPARISON_INFO, crate::bool_to_int_with_if::BOOL_TO_INT_WITH_IF_INFO, crate::booleans::NONMINIMAL_BOOL_INFO, crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO, @@ -538,7 +539,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::mutex_atomic::MUTEX_ATOMIC_INFO, crate::mutex_atomic::MUTEX_INTEGER_INFO, crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO, - crate::needless_bool::BOOL_COMPARISON_INFO, crate::needless_bool::NEEDLESS_BOOL_INFO, crate::needless_bool::NEEDLESS_BOOL_ASSIGN_INFO, crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO, diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index 7580d6cab66d..06c2393e0a39 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -10,7 +10,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; -use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty, TypeckResults}; +use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty, TypeckResults, VariantDef}; use rustc_session::impl_lint_pass; use rustc_span::sym; @@ -85,6 +85,13 @@ fn contains_trait_object(ty: Ty<'_>) -> bool { } } +fn determine_derive_macro(cx: &LateContext<'_>, is_const: bool) -> Option<&'static str> { + (!is_const) + .then_some("derive") + .or_else(|| cx.tcx.features().enabled(sym::derive_const).then_some("derive_const")) +} + +#[expect(clippy::too_many_arguments)] fn check_struct<'tcx>( cx: &LateContext<'tcx>, item: &'tcx Item<'_>, @@ -93,6 +100,7 @@ fn check_struct<'tcx>( adt_def: AdtDef<'_>, ty_args: GenericArgsRef<'_>, typeck_results: &'tcx TypeckResults<'tcx>, + is_const: bool, ) { if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind && let Some(PathSegment { args, .. }) = p.segments.last() @@ -125,14 +133,18 @@ fn check_struct<'tcx>( ExprKind::Tup(fields) => fields.iter().all(is_default_without_adjusts), ExprKind::Call(callee, args) if is_path_self(callee) => args.iter().all(is_default_without_adjusts), ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_without_adjusts(ef.expr)), - _ => false, + _ => return, }; - if should_emit { + if should_emit && let Some(derive_snippet) = determine_derive_macro(cx, is_const) { let struct_span = cx.tcx.def_span(adt_def.did()); + let indent_enum = indent_of(cx, struct_span).unwrap_or(0); let suggestions = vec![ (item.span, String::new()), // Remove the manual implementation - (struct_span.shrink_to_lo(), "#[derive(Default)]\n".to_string()), // Add the derive attribute + ( + struct_span.shrink_to_lo(), + format!("#[{derive_snippet}(Default)]\n{}", " ".repeat(indent_enum)), + ), // Add the derive attribute ]; span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| { @@ -145,11 +157,41 @@ fn check_struct<'tcx>( } } -fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Expr<'_>, adt_def: AdtDef<'_>) { - if let ExprKind::Path(QPath::Resolved(None, p)) = &peel_blocks(func_expr).kind - && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res - && let variant_id = cx.tcx.parent(id) - && let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id) +fn extract_enum_variant<'tcx>( + cx: &LateContext<'tcx>, + func_expr: &'tcx Expr<'tcx>, + adt_def: AdtDef<'tcx>, +) -> Option<&'tcx VariantDef> { + match &peel_blocks(func_expr).kind { + ExprKind::Path(QPath::Resolved(None, p)) + if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res + && let variant_id = cx.tcx.parent(id) + && let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id) => + { + Some(variant_def) + }, + ExprKind::Path(QPath::TypeRelative(ty, segment)) + if let TyKind::Path(QPath::Resolved(None, p)) = &ty.kind + && let Res::SelfTyAlias { + is_trait_impl: true, .. + } = p.res + && let variant_ident = segment.ident + && let Some(variant_def) = adt_def.variants().iter().find(|v| v.ident(cx.tcx) == variant_ident) => + { + Some(variant_def) + }, + _ => None, + } +} + +fn check_enum<'tcx>( + cx: &LateContext<'tcx>, + item: &'tcx Item<'tcx>, + func_expr: &'tcx Expr<'tcx>, + adt_def: AdtDef<'tcx>, + is_const: bool, +) { + if let Some(variant_def) = extract_enum_variant(cx, func_expr, adt_def) && variant_def.fields.is_empty() && !variant_def.is_field_list_non_exhaustive() { @@ -158,11 +200,15 @@ fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Ex let variant_span = cx.tcx.def_span(variant_def.def_id); let indent_variant = indent_of(cx, variant_span).unwrap_or(0); + let Some(derive_snippet) = determine_derive_macro(cx, is_const) else { + return; + }; + let suggestions = vec![ (item.span, String::new()), // Remove the manual implementation ( enum_span.shrink_to_lo(), - format!("#[derive(Default)]\n{}", " ".repeat(indent_enum)), + format!("#[{derive_snippet}(Default)]\n{}", " ".repeat(indent_enum)), ), // Add the derive attribute ( variant_span.shrink_to_lo(), @@ -201,10 +247,20 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { && !attrs.iter().any(|attr| attr.doc_str().is_some()) && cx.tcx.hir_attrs(impl_item_hir).is_empty() { + let is_const = of_trait.constness == hir::Constness::Const; if adt_def.is_struct() { - check_struct(cx, item, self_ty, func_expr, adt_def, args, cx.tcx.typeck_body(*b)); + check_struct( + cx, + item, + self_ty, + func_expr, + adt_def, + args, + cx.tcx.typeck_body(*b), + is_const, + ); } else if adt_def.is_enum() && self.msrv.meets(cx, msrvs::DEFAULT_ENUM_ATTRIBUTE) { - check_enum(cx, item, func_expr, adt_def); + check_enum(cx, item, func_expr, adt_def, is_const); } } } diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 182cb4e46d2b..a5ec6777b434 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context}; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_expr; @@ -194,7 +194,17 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { if let Some(sugg) = sugg { span_lint_and_sugg(cx, MAP_ENTRY, expr.span, lint_msg, "try", sugg, app); } else { - span_lint(cx, MAP_ENTRY, expr.span, lint_msg); + span_lint_and_help( + cx, + MAP_ENTRY, + expr.span, + lint_msg, + None, + format!( + "consider using the `Entry` API: https://doc.rust-lang.org/std/collections/struct.{}.html#entry-api", + map_ty.name() + ), + ); } } } @@ -254,35 +264,28 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio _ => None, }); - match expr.kind { - ExprKind::MethodCall( - _, + if let ExprKind::MethodCall(_, map, [arg], _) = expr.kind + && let Expr { + kind: ExprKind::AddrOf(_, _, key), + span: key_span, + .. + } = arg + && key_span.eq_ctxt(expr.span) + { + let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; + let expr = ContainsExpr { + negated, map, - [ - Expr { - kind: ExprKind::AddrOf(_, _, key), - span: key_span, - .. - }, - ], - _, - ) if key_span.eq_ctxt(expr.span) => { - let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; - let expr = ContainsExpr { - negated, - map, - key, - call_ctxt: expr.span.ctxt(), - }; - if cx.tcx.is_diagnostic_item(sym::btreemap_contains_key, id) { - Some((MapType::BTree, expr)) - } else if cx.tcx.is_diagnostic_item(sym::hashmap_contains_key, id) { - Some((MapType::Hash, expr)) - } else { - None - } - }, - _ => None, + key, + call_ctxt: expr.span.ctxt(), + }; + match cx.tcx.get_diagnostic_name(id) { + Some(sym::btreemap_contains_key) => Some((MapType::BTree, expr)), + Some(sym::hashmap_contains_key) => Some((MapType::Hash, expr)), + _ => None, + } + } else { + None } } @@ -311,7 +314,9 @@ struct InsertExpr<'tcx> { fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; - if cx.tcx.is_diagnostic_item(sym::btreemap_insert, id) || cx.tcx.is_diagnostic_item(sym::hashmap_insert, id) { + if let Some(insert) = cx.tcx.get_diagnostic_name(id) + && matches!(insert, sym::btreemap_insert | sym::hashmap_insert) + { Some(InsertExpr { map, key, value }) } else { None diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 0eefc2f61096..2da1c2bad117 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -12,6 +12,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind, find_attr}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{ self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, TypeckResults, }; @@ -148,10 +149,9 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx { return; } - let callee_ty_adjusted = typeck - .expr_adjustments(callee) - .last() - .map_or(callee_ty, |a| a.target.peel_refs()); + + let callee_ty_adjustments = typeck.expr_adjustments(callee); + let callee_ty_adjusted = callee_ty_adjustments.last().map_or(callee_ty, |a| a.target); let sig = match callee_ty_adjusted.kind() { ty::FnDef(def, _) => { @@ -230,7 +230,20 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx }, _ => (), } + } else if let n_refs = + callee_ty_adjustments + .iter() + .rev() + .fold(0, |acc, adjustment| match adjustment.kind { + Adjust::Deref(Some(_)) => acc + 1, + Adjust::Deref(_) if acc > 0 => acc + 1, + _ => acc, + }) + && n_refs > 0 + { + snippet = format!("{}{snippet}", "*".repeat(n_refs)); } + let replace_with = match callee_ty_adjusted.kind() { ty::FnDef(def, _) => cx.tcx.def_descr(*def), _ => "function", diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index ccaf38aee4d8..6178addfff12 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -1,11 +1,12 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::numeric_literal; +use clippy_utils::{ExprUseNode, expr_use_ctxt, numeric_literal}; use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, FloatTy}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use std::fmt; declare_clippy_lint! { @@ -13,6 +14,8 @@ declare_clippy_lint! { /// Checks for float literals with a precision greater /// than that supported by the underlying type. /// + /// The lint is suppressed for literals with over `const_literal_digits_threshold` digits. + /// /// ### Why is this bad? /// Rust will truncate the literal silently. /// @@ -58,7 +61,21 @@ declare_clippy_lint! { "lossy whole number float literals" } -declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]); +pub struct FloatLiteral { + const_literal_digits_threshold: usize, +} + +impl_lint_pass!(FloatLiteral => [ + EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL +]); + +impl FloatLiteral { + pub fn new(conf: &'static Conf) -> Self { + Self { + const_literal_digits_threshold: conf.const_literal_digits_threshold, + } + } +} impl<'tcx> LateLintPass<'tcx> for FloatLiteral { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { @@ -126,13 +143,25 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { }, ); } - } else if digits > max as usize && count_digits(&float_str) < count_digits(sym_str) { + } else if digits > max as usize && count_digits(&float_str) < digits { + if digits >= self.const_literal_digits_threshold + && matches!(expr_use_ctxt(cx, expr).use_node(cx), ExprUseNode::ConstStatic(_)) + { + // If a big enough number of digits is specified and it's a constant + // we assume the user is definining a constant, and excessive precision is ok + return; + } span_lint_and_then( cx, EXCESSIVE_PRECISION, expr.span, "float has excessive precision", |diag| { + if digits >= self.const_literal_digits_threshold + && let Some(let_stmt) = maybe_let_stmt(cx, expr) + { + diag.span_note(let_stmt.span, "consider making it a `const` item"); + } diag.span_suggestion_verbose( expr.span, "consider changing the type or truncating it to", @@ -196,3 +225,11 @@ impl FloatFormat { } } } + +fn maybe_let_stmt<'a>(cx: &LateContext<'a>, expr: &hir::Expr<'_>) -> Option<&'a hir::LetStmt<'a>> { + let parent = cx.tcx.parent_hir_node(expr.hir_id); + match parent { + hir::Node::LetStmt(let_stmt) => Some(let_stmt), + _ => None, + } +} diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index ca5ea9018149..5a40af421942 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -535,7 +535,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { def_id: LocalDefId, ) { let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); - too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold); + too_many_arguments::check_fn(cx, kind, decl, hir_id, def_id, self.too_many_arguments_threshold); too_many_lines::check_fn(cx, kind, body, span, def_id, self.too_many_lines_threshold); not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id); misnamed_getters::check_fn(cx, kind, decl, body, span); diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs index 48d050aa36aa..6c3c3d354ecc 100644 --- a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs +++ b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs @@ -1,5 +1,7 @@ use rustc_abi::ExternAbi; -use rustc_hir::{self as hir, intravisit}; +use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::FnKind; use rustc_lint::LateContext; use rustc_span::Span; @@ -10,39 +12,18 @@ use super::TOO_MANY_ARGUMENTS; pub(super) fn check_fn( cx: &LateContext<'_>, - kind: intravisit::FnKind<'_>, + kind: FnKind<'_>, decl: &hir::FnDecl<'_>, - span: Span, hir_id: hir::HirId, + def_id: LocalDefId, too_many_arguments_threshold: u64, ) { // don't warn for implementations, it's not their fault - if !is_trait_impl_item(cx, hir_id) { + if !is_trait_impl_item(cx, hir_id) // don't lint extern functions decls, it's not their fault either - match kind { - intravisit::FnKind::Method( - _, - &hir::FnSig { - header: hir::FnHeader { - abi: ExternAbi::Rust, .. - }, - .. - }, - ) - | intravisit::FnKind::ItemFn( - _, - _, - hir::FnHeader { - abi: ExternAbi::Rust, .. - }, - ) => check_arg_number( - cx, - decl, - span.with_hi(decl.output.span().hi()), - too_many_arguments_threshold, - ), - _ => {}, - } + && kind.header().is_some_and(|header| header.abi == ExternAbi::Rust) + { + check_arg_number(cx, decl, cx.tcx.def_span(def_id), too_many_arguments_threshold); } } diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs index 7158f9419c1c..b50d91f10146 100644 --- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs +++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs @@ -2,16 +2,16 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}; use clippy_utils::sugg::Sugg; use clippy_utils::{ contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, is_res_lang_ctor, - path_res, peel_blocks, + path_res, peel_blocks, sym, }; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -71,21 +71,21 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind - && let ctxt = expr.span.ctxt() - && then_expr.span.ctxt() == ctxt + && !expr.span.from_expansion() + && !then_expr.span.from_expansion() && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome) && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone) && !is_else_clause(cx.tcx, expr) && !is_in_const_context(cx) - && !expr.span.in_external_macro(cx.sess().source_map()) && self.msrv.meets(cx, msrvs::BOOL_THEN) && !contains_return(then_block.stmts) { let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { - "then_some" + sym::then_some } else { - "then" + sym::then }; + let ctxt = expr.span.ctxt(); span_lint_and_then( cx, @@ -98,16 +98,18 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { } let mut app = Applicability::MachineApplicable; - let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app) + let cond_snip = Sugg::hir_with_context(cx, cond, ctxt, "[condition]", &mut app) .maybe_paren() .to_string(); let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; - let method_body = if let Some(first_stmt) = then_block.stmts.first() { - let (block_snippet, _) = - snippet_with_context(cx, first_stmt.span.until(then_arg.span), ctxt, "..", &mut app); - let closure = if method_name == "then" { "|| " } else { "" }; - format!("{closure} {{ {block_snippet}; {arg_snip} }}") - } else if method_name == "then" { + let method_body = if let Some(first_stmt) = then_block.stmts.first() + && let Some(first_stmt_span) = walk_span_to_context(first_stmt.span, ctxt) + { + let block_snippet = + snippet_with_applicability(cx, first_stmt_span.until(then_expr.span), "..", &mut app); + let closure = if method_name == sym::then { "|| " } else { "" }; + format!("{closure} {{ {} {arg_snip} }}", block_snippet.trim_end()) + } else if method_name == sym::then { (std::borrow::Cow::Borrowed("|| ") + arg_snip).into_owned() } else { arg_snip.into_owned() diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs index 91f65d0b79ca..13117f60abd5 100644 --- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; -use clippy_utils::ty; +use clippy_utils::{is_path_diagnostic_item, ty}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -107,8 +107,7 @@ impl LateLintPass<'_> for InstantSubtraction { fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { if let ExprKind::Call(fn_expr, []) = expr_block.kind - && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr) - && cx.tcx.is_diagnostic_item(sym::instant_now, fn_id) + && is_path_diagnostic_item(cx, fn_expr, sym::instant_now) { true } else { diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index 8707612fbdd0..48ce1afc6e69 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -64,8 +64,8 @@ impl LateLintPass<'_> for LargeIncludeFile { } && len as u64 > self.max_file_size && let Some(macro_call) = root_macro_call_first_node(cx, expr) - && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) - || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) + && let Some(macro_name) = cx.tcx.get_diagnostic_name(macro_call.def_id) + && matches!(macro_name, sym::include_bytes_macro | sym::include_str_macro) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 57deb011f2b0..f44a5fdf715e 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -355,12 +355,15 @@ fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option Some(LenOutput::Option(def_id)), + Some(sym::Result) => Some(LenOutput::Result(def_id)), + _ => None, } + && is_first_generic_integral(segment) + { + return Some(res); } return None; @@ -368,11 +371,10 @@ fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option Some(LenOutput::Integral), - ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) => { - subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did())) - }, - ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) => { - subs.type_at(0).is_integral().then(|| LenOutput::Result(adt.did())) + ty::Adt(adt, subs) if subs.type_at(0).is_integral() => match cx.tcx.get_diagnostic_name(adt.did()) { + Some(sym::Option) => Some(LenOutput::Option(adt.did())), + Some(sym::Result) => Some(LenOutput::Result(adt.did())), + _ => None, }, _ => None, } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index c8594cf35e23..a89cf3fdc1ee 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -84,6 +84,7 @@ mod attrs; mod await_holding_invalid; mod blocks_in_conditions; mod bool_assert_comparison; +mod bool_comparison; mod bool_to_int_with_if; mod booleans; mod borrow_deref_ref; @@ -474,10 +475,10 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co store.register_late_pass(move |_| Box::new(types::Types::new(conf))); store.register_late_pass(move |_| Box::new(booleans::NonminimalBool::new(conf))); store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant)); - store.register_late_pass(|_| Box::new(float_literal::FloatLiteral)); + store.register_late_pass(move |_| Box::new(float_literal::FloatLiteral::new(conf))); store.register_late_pass(|_| Box::new(ptr::Ptr)); store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool)); - store.register_late_pass(|_| Box::new(needless_bool::BoolComparison)); + store.register_late_pass(|_| Box::new(bool_comparison::BoolComparison)); store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach)); store.register_late_pass(|_| Box::new(misc::LintPass)); store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction)); @@ -655,7 +656,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(conf))); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch)); - store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult)); + store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync)); let attrs = attr_storage.clone(); diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs index a71e6963f8ca..74c0b1780189 100644 --- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs @@ -4,7 +4,8 @@ use hir::intravisit::{Visitor, walk_expr}; use rustc_ast::Label; use rustc_errors::Applicability; use rustc_hir::{ - self as hir, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, Expr, ExprKind, FnRetTy, FnSig, Node, TyKind, + self as hir, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnRetTy, + FnSig, Node, TyKind, }; use rustc_lint::{LateContext, LintContext}; use rustc_span::sym; @@ -73,7 +74,11 @@ fn is_inside_unawaited_async_block(cx: &LateContext<'_>, expr: &Expr<'_>) -> boo if let Node::Expr(Expr { kind: ExprKind::Closure(Closure { - kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)), + kind: + ClosureKind::Coroutine(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + CoroutineSource::Block | CoroutineSource::Closure, + )), .. }), .. diff --git a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs index a9944d64ce2d..8a2d0036203a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs @@ -1,10 +1,10 @@ use super::MISSING_SPIN_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::std_or_core; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::ty; use rustc_span::sym; fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { @@ -39,8 +39,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &' ) = body.kind && let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind && [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name) - && let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind() - && cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did()) + && let callee_ty = cx.typeck_results().expr_ty(callee) + && is_type_diagnostic_item(cx, callee_ty, sym::AtomicBool) && let Some(std_or_core) = std_or_core(cx) { span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 7bb684d65bb4..11edb929d70b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::has_iter_method; use clippy_utils::visitors::is_local_used; -use clippy_utils::{SpanlessEq, contains_name, higher, is_integer_const, sugg}; +use clippy_utils::{SpanlessEq, contains_name, higher, is_integer_const, peel_hir_expr_while, sugg}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::Applicability; @@ -253,12 +253,38 @@ struct VarVisitor<'a, 'tcx> { impl<'tcx> VarVisitor<'_, 'tcx> { fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool { - let index_used_directly = matches!(idx.kind, ExprKind::Path(_)); + let mut used_cnt = 0; + // It is `true` if all indices are direct + let mut index_used_directly = true; + + // Handle initial index + if is_local_used(self.cx, idx, self.var) { + used_cnt += 1; + index_used_directly &= matches!(idx.kind, ExprKind::Path(_)); + } + // Handle nested indices + let seqexpr = peel_hir_expr_while(seqexpr, |e| { + if let ExprKind::Index(e, idx, _) = e.kind { + if is_local_used(self.cx, idx, self.var) { + used_cnt += 1; + index_used_directly &= matches!(idx.kind, ExprKind::Path(_)); + } + Some(e) + } else { + None + } + }); + + match used_cnt { + 0 => return true, + n if n > 1 => self.nonindex = true, // Optimize code like `a[i][i]` + _ => {}, + } + if let ExprKind::Path(ref seqpath) = seqexpr.kind // the indexed container is referenced by a name && let QPath::Resolved(None, seqvar) = *seqpath && seqvar.segments.len() == 1 - && is_local_used(self.cx, idx, self.var) { if self.prefer_mutable { self.indexed_mut.insert(seqvar.segments[0].ident.name); @@ -312,7 +338,6 @@ impl<'tcx> VarVisitor<'_, 'tcx> { impl<'tcx> Visitor<'tcx> for VarVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind - // a range index op && let Some(trait_id) = self .cx .typeck_results() diff --git a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs index 51e21aa9734e..13b93d2c0097 100644 --- a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs +++ b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs @@ -1,12 +1,12 @@ use super::UNUSED_ENUMERATE_INDEX; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{pat_is_wild, sugg}; use rustc_errors::Applicability; use rustc_hir::def::DefKind; use rustc_hir::{Expr, ExprKind, Pat, PatKind}; use rustc_lint::LateContext; -use rustc_middle::ty; use rustc_span::sym; /// Checks for the `UNUSED_ENUMERATE_INDEX` lint. @@ -17,8 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_ && let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind && let ty = cx.typeck_results().expr_ty(arg) && pat_is_wild(cx, &index.kind, body) - && let ty::Adt(base, _) = *ty.kind() - && cx.tcx.is_diagnostic_item(sym::Enumerate, base.did()) + && is_type_diagnostic_item(cx, ty, sym::Enumerate) && let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id) && cx.tcx.is_diagnostic_item(sym::enumerate_method, call_id) { diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index ac8c88f02057..2eebb2430fd9 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -97,11 +97,12 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { return; } - if let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro) { - if let ExprKind::Match(recv, [arm, ..], _) = expr.kind { - let range = check_pat(&arm.pat.kind); - check_is_ascii(cx, macro_call.span, recv, &range, None); - } + let (arg, span, range) = if let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro) + && let ExprKind::Match(recv, [arm, ..], _) = expr.kind + { + let recv = peel_ref_operators(cx, recv); + let range = check_pat(&arm.pat.kind); + (recv, macro_call.span, range) } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind && path.ident.name == sym::contains && let Some(higher::Range { @@ -112,10 +113,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { && !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_)) { let arg = peel_ref_operators(cx, arg); - let ty_sugg = get_ty_sugg(cx, arg); let range = check_expr_range(start, end); - check_is_ascii(cx, expr.span, arg, &range, ty_sugg); - } + (arg, expr.span, range) + } else { + return; + }; + + let ty_sugg = get_ty_sugg(cx, arg); + check_is_ascii(cx, span, arg, &range, ty_sugg); } } @@ -146,9 +151,8 @@ fn check_is_ascii( CharRange::HexDigit => "is_ascii_hexdigit", CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => return, }; - let default_snip = ".."; let mut app = Applicability::MachineApplicable; - let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_paren(); + let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), "_", &mut app).maybe_paren(); let mut suggestion = vec![(span, format!("{recv}.{sugg}()"))]; if let Some((ty_span, ty)) = ty_sugg { suggestion.push((ty_span, format!("{recv}: {ty}"))); @@ -182,7 +186,7 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange { CharRange::Otherwise } }, - PatKind::Range(Some(start), Some(end), kind) if *kind == RangeEnd::Included => check_range(start, end), + PatKind::Range(Some(start), Some(end), RangeEnd::Included) => check_range(start, end), _ => CharRange::Otherwise, } } diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index 98e8b1f5cf92..7fb88763e640 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -123,8 +123,8 @@ fn check_iter( ) { if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) - && (cx.tcx.is_diagnostic_item(sym::iter_copied, copied_def_id) - || cx.tcx.is_diagnostic_item(sym::iter_cloned, copied_def_id)) + && let Some(copied_name) = cx.tcx.get_diagnostic_name(copied_def_id) + && matches!(copied_name, sym::iter_copied | sym::iter_cloned) && let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) && cx.tcx.is_diagnostic_item(sym::iter_filter, filter_def_id) @@ -243,9 +243,9 @@ fn make_sugg( } fn match_acceptable_sym(cx: &LateContext<'_>, collect_def_id: DefId) -> bool { - ACCEPTABLE_METHODS - .iter() - .any(|&method| cx.tcx.is_diagnostic_item(method, collect_def_id)) + cx.tcx + .get_diagnostic_name(collect_def_id) + .is_some_and(|collect_name| ACCEPTABLE_METHODS.contains(&collect_name)) } fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Msrv) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 6bf43a1c6d47..07cce4046ca4 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -75,12 +75,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { && let ExprKind::Path(target_path) = &target_arg.kind && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id) { - let strip_kind = if cx.tcx.is_diagnostic_item(sym::str_starts_with, method_def_id) { - StripKind::Prefix - } else if cx.tcx.is_diagnostic_item(sym::str_ends_with, method_def_id) { - StripKind::Suffix - } else { - return; + let strip_kind = match cx.tcx.get_diagnostic_name(method_def_id) { + Some(sym::str_starts_with) => StripKind::Prefix, + Some(sym::str_ends_with) => StripKind::Suffix, + _ => return, }; let target_res = cx.qpath_res(target_path, target_arg.hir_id); if target_res == Res::Err { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index af6a1b07a492..39e5289c62ae 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -116,8 +116,10 @@ fn is_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { /// The expression inside a closure may or may not have surrounding braces and /// semicolons, which causes problems when generating a suggestion. Given an /// expression that evaluates to '()' or '!', recursively remove useless braces -/// and semi-colons until is suitable for including in the suggestion template -fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { +/// and semi-colons until is suitable for including in the suggestion template. +/// The `bool` is `true` when the resulting `span` needs to be enclosed in an +/// `unsafe` block. +fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<(Span, bool)> { if !is_unit_expression(cx, expr) { return None; } @@ -125,22 +127,24 @@ fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option< match expr.kind { hir::ExprKind::Call(_, _) | hir::ExprKind::MethodCall(..) => { // Calls can't be reduced any more - Some(expr.span) + Some((expr.span, false)) }, hir::ExprKind::Block(block, _) => { + let is_unsafe = matches!(block.rules, hir::BlockCheckMode::UnsafeBlock(_)); match (block.stmts, block.expr.as_ref()) { ([], Some(inner_expr)) => { // If block only contains an expression, // reduce `{ X }` to `X` reduce_unit_expression(cx, inner_expr) + .map(|(span, inner_is_unsafe)| (span, inner_is_unsafe || is_unsafe)) }, ([inner_stmt], None) => { // If block only contains statements, // reduce `{ X; }` to `X` or `X;` match inner_stmt.kind { - hir::StmtKind::Let(local) => Some(local.span), - hir::StmtKind::Expr(e) => Some(e.span), - hir::StmtKind::Semi(..) => Some(inner_stmt.span), + hir::StmtKind::Let(local) => Some((local.span, is_unsafe)), + hir::StmtKind::Expr(e) => Some((e.span, is_unsafe)), + hir::StmtKind::Semi(..) => Some((inner_stmt.span, is_unsafe)), hir::StmtKind::Item(..) => None, } }, @@ -228,10 +232,11 @@ fn lint_map_unit_fn( let msg = suggestion_msg("closure", map_type); span_lint_and_then(cx, lint, expr.span, msg, |diag| { - if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) { + if let Some((reduced_expr_span, is_unsafe)) = reduce_unit_expression(cx, closure_expr) { let mut applicability = Applicability::MachineApplicable; + let (prefix_is_unsafe, suffix_is_unsafe) = if is_unsafe { ("unsafe { ", " }") } else { ("", "") }; let suggestion = format!( - "if let {0}({1}) = {2} {{ {3} }}", + "if let {0}({1}) = {2} {{ {prefix_is_unsafe}{3}{suffix_is_unsafe} }}", variant, snippet_with_applicability(cx, binding.pat.span, "_", &mut applicability), snippet_with_applicability(cx, var_arg.span, "_", &mut applicability), diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs index 5b50efad3e44..aaf559fc4439 100644 --- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs @@ -4,20 +4,22 @@ use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet; use clippy_utils::visitors::is_local_used; use clippy_utils::{ - SpanlessEq, is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, + SpanlessEq, get_ref_operators, is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, + peel_ref_operators, }; +use rustc_ast::BorrowKind; use rustc_errors::MultiSpan; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{Arm, Expr, HirId, Pat, PatExpr, PatExprKind, PatKind}; +use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatExpr, PatExprKind, PatKind}; use rustc_lint::LateContext; use rustc_span::Span; use super::{COLLAPSIBLE_MATCH, pat_contains_disallowed_or}; -pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], msrv: Msrv) { +pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>], msrv: Msrv) { if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) { for arm in arms { - check_arm(cx, true, arm.pat, arm.body, arm.guard, Some(els_arm.body), msrv); + check_arm(cx, true, arm.pat, expr, arm.body, arm.guard, Some(els_arm.body), msrv); } } } @@ -27,15 +29,18 @@ pub(super) fn check_if_let<'tcx>( pat: &'tcx Pat<'_>, body: &'tcx Expr<'_>, else_expr: Option<&'tcx Expr<'_>>, + let_expr: &'tcx Expr<'_>, msrv: Msrv, ) { - check_arm(cx, false, pat, body, None, else_expr, msrv); + check_arm(cx, false, pat, let_expr, body, None, else_expr, msrv); } +#[allow(clippy::too_many_arguments)] fn check_arm<'tcx>( cx: &LateContext<'tcx>, outer_is_match: bool, outer_pat: &'tcx Pat<'tcx>, + outer_cond: &'tcx Expr<'tcx>, outer_then_body: &'tcx Expr<'tcx>, outer_guard: Option<&'tcx Expr<'tcx>>, outer_else_body: Option<&'tcx Expr<'tcx>>, @@ -82,6 +87,9 @@ fn check_arm<'tcx>( }, IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)), } + // Check if the inner expression contains any borrows/dereferences + && let ref_types = get_ref_operators(cx, inner_scrutinee) + && let Some(method) = build_ref_method_chain(ref_types) { let msg = format!( "this `{}` can be collapsed into the outer `{}`", @@ -103,6 +111,10 @@ fn check_arm<'tcx>( let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]); help_span.push_span_label(binding_span, "replace this binding"); help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}")); + if !method.is_empty() { + let outer_cond_msg = format!("use: `{}{}`", snippet(cx, outer_cond.span, ".."), method); + help_span.push_span_label(outer_cond.span, outer_cond_msg); + } diag.span_help( help_span, "the outer pattern can be modified to include the inner pattern", @@ -148,3 +160,30 @@ fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: Hi }); (span, is_innermost_parent_pat_struct) } + +/// Builds a chain of reference-manipulation method calls (e.g., `.as_ref()`, `.as_mut()`, +/// `.copied()`) based on reference operators +fn build_ref_method_chain(expr: Vec<&Expr<'_>>) -> Option { + let mut req_method_calls = String::new(); + + for ref_operator in expr { + match ref_operator.kind { + ExprKind::AddrOf(BorrowKind::Raw, _, _) => { + return None; + }, + ExprKind::AddrOf(_, m, _) if m.is_mut() => { + req_method_calls.push_str(".as_mut()"); + }, + ExprKind::AddrOf(_, _, _) => { + req_method_calls.push_str(".as_ref()"); + }, + // Deref operator is the only operator that this function should have received + ExprKind::Unary(_, _) => { + req_method_calls.push_str(".copied()"); + }, + _ => (), + } + } + + Some(req_method_calls) +} diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index c128fc40b733..6f49c5524118 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -1073,7 +1073,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { significant_drop_in_scrutinee::check_match(cx, expr, ex, arms, source); } - collapsible_match::check_match(cx, arms, self.msrv); + collapsible_match::check_match(cx, ex, arms, self.msrv); if !from_expansion { // These don't depend on a relationship between multiple arms match_wild_err_arm::check(cx, ex, arms); @@ -1137,7 +1137,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches { match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr); } } else if let Some(if_let) = higher::IfLet::hir(cx, expr) { - collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, self.msrv); + collapsible_match::check_if_let( + cx, + if_let.let_pat, + if_let.if_then, + if_let.if_else, + if_let.let_expr, + self.msrv, + ); significant_drop_in_scrutinee::check_if_let(cx, expr, if_let.let_expr, if_let.if_then, if_let.if_else); if !from_expansion { if let Some(else_expr) = if_let.if_else { diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 027dd7ce0534..81fecc87256c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -226,11 +226,12 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)] enum SigDropHolder { /// No values with significant drop present in this expression. /// /// Expressions that we've emitted lints do not count. + #[default] None, /// Some field in this expression references to values with significant drop. /// @@ -244,12 +245,6 @@ enum SigDropHolder { Moved, } -impl Default for SigDropHolder { - fn default() -> Self { - Self::None - } -} - struct SigDropHelper<'a, 'tcx> { cx: &'a LateContext<'tcx>, parent_expr: Option<&'tcx Expr<'tcx>>, diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs index ff7769af1df4..af90cb5e6733 100644 --- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs +++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::option_arg_ty; use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res}; use rustc_errors::Applicability; use rustc_hir::LangItem::ResultErr; @@ -28,25 +28,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine && is_res_lang_ctor(cx, path_res(cx, err_fun), ResultErr) && let Some(return_ty) = find_return_type(cx, &expr.kind) { - let prefix; - let suffix; - let err_ty; - - if let Some(ty) = result_error_type(cx, return_ty) { - prefix = "Err("; - suffix = ")"; - err_ty = ty; + let (prefix, suffix, err_ty) = if let Some(ty) = result_error_type(cx, return_ty) { + ("Err(", ")", ty) } else if let Some(ty) = poll_result_error_type(cx, return_ty) { - prefix = "Poll::Ready(Err("; - suffix = "))"; - err_ty = ty; + ("Poll::Ready(Err(", "))", ty) } else if let Some(ty) = poll_option_result_error_type(cx, return_ty) { - prefix = "Poll::Ready(Some(Err("; - suffix = ")))"; - err_ty = ty; + ("Poll::Ready(Some(Err(", ")))", ty) } else { return; - } + }; span_lint_and_then( cx, @@ -88,8 +78,8 @@ fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> O /// Extracts the error type from Result. fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { - if let ty::Adt(_, subst) = ty.kind() - && is_type_diagnostic_item(cx, ty, sym::Result) + if let ty::Adt(def, subst) = ty.kind() + && cx.tcx.is_diagnostic_item(sym::Result, def.did()) { Some(subst.type_at(1)) } else { @@ -101,11 +91,9 @@ fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { if let ty::Adt(def, subst) = ty.kind() && cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did()) - && let ready_ty = subst.type_at(0) - && let ty::Adt(ready_def, ready_subst) = ready_ty.kind() - && cx.tcx.is_diagnostic_item(sym::Result, ready_def.did()) { - Some(ready_subst.type_at(1)) + let ready_ty = subst.type_at(0); + result_error_type(cx, ready_ty) } else { None } @@ -116,13 +104,9 @@ fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> if let ty::Adt(def, subst) = ty.kind() && cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did()) && let ready_ty = subst.type_at(0) - && let ty::Adt(ready_def, ready_subst) = ready_ty.kind() - && cx.tcx.is_diagnostic_item(sym::Option, ready_def.did()) - && let some_ty = ready_subst.type_at(0) - && let ty::Adt(some_def, some_subst) = some_ty.kind() - && cx.tcx.is_diagnostic_item(sym::Result, some_def.did()) + && let Some(some_ty) = option_arg_ty(cx, ready_ty) { - Some(some_subst.type_at(1)) + result_error_type(cx, some_ty) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index 28efd2038b38..e39916f733d5 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -215,7 +215,8 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' && let ExprKind::Path(ref repl_func_qpath) = repl_func.kind && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id() { - if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) { + let repl_name = cx.tcx.get_diagnostic_name(repl_def_id); + if repl_name == Some(sym::mem_uninitialized) { let Some(top_crate) = std_or_core(cx) else { return }; let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( @@ -230,9 +231,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' ), applicability, ); - } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) - && !cx.typeck_results().expr_ty(src).is_primitive() - { + } else if repl_name == Some(sym::mem_zeroed) && !cx.typeck_results().expr_ty(src).is_primitive() { span_lint_and_help( cx, MEM_REPLACE_WITH_UNINIT, diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs index 96e2de0dc1cb..65583c6a9811 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -24,9 +24,10 @@ pub(super) fn check( && let Some(name) = cx.tcx.get_diagnostic_name(adt.did()) { let caller_type = match name { - sym::Rc => "Rc", - sym::Arc => "Arc", - sym::RcWeak | sym::ArcWeak => "Weak", + sym::Rc => "std::rc::Rc", + sym::Arc => "std::sync::Arc", + sym::RcWeak => "std::rc::Weak", + sym::ArcWeak => "std::sync::Weak", _ => return, }; span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index 5b8457bdd164..2da0f8341b17 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -233,18 +233,16 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // the latter only calls `effect` once let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span); - if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym::is_some { - Some(Self::IsSome { + match (cx.tcx.get_diagnostic_name(recv_ty.did()), path.ident.name) { + (Some(sym::Option), sym::is_some) => Some(Self::IsSome { receiver, side_effect_expr_span, - }) - } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym::is_ok { - Some(Self::IsOk { + }), + (Some(sym::Result), sym::is_ok) => Some(Self::IsOk { receiver, side_effect_expr_span, - }) - } else { - None + }), + _ => None, } } else if matching_root_macro_call(cx, expr.span, sym::matches_macro).is_some() // we know for a fact that the wildcard pattern is the second arm diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs index 9a62b719a8fb..fa8f9d640ee6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs @@ -24,32 +24,29 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> let ty::Adt(adt, substs) = cx.typeck_results().expr_ty(iter).kind() else { return None; }; - let did = adt.did(); - if cx.tcx.is_diagnostic_item(sym::ArrayIntoIter, did) { - // For array::IntoIter, the length is the second generic - // parameter. - substs.const_at(1).try_to_target_usize(cx.tcx).map(u128::from) - } else if cx.tcx.is_diagnostic_item(sym::SliceIter, did) - && let ExprKind::MethodCall(_, recv, ..) = iter.kind - { - if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() { - // For slice::Iter<'_, T>, the receiver might be an array literal: [1,2,3].iter().skip(..) - len.try_to_target_usize(cx.tcx).map(u128::from) - } else if let Some(args) = VecArgs::hir(cx, expr_or_init(cx, recv)) { - match args { - VecArgs::Vec(vec) => vec.len().try_into().ok(), - VecArgs::Repeat(_, len) => expr_as_u128(cx, len), + match cx.tcx.get_diagnostic_name(adt.did()) { + Some(sym::ArrayIntoIter) => { + // For array::IntoIter, the length is the second generic + // parameter. + substs.const_at(1).try_to_target_usize(cx.tcx).map(u128::from) + }, + Some(sym::SliceIter) if let ExprKind::MethodCall(_, recv, ..) = iter.kind => { + if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() { + // For slice::Iter<'_, T>, the receiver might be an array literal: [1,2,3].iter().skip(..) + len.try_to_target_usize(cx.tcx).map(u128::from) + } else if let Some(args) = VecArgs::hir(cx, expr_or_init(cx, recv)) { + match args { + VecArgs::Vec(vec) => vec.len().try_into().ok(), + VecArgs::Repeat(_, len) => expr_as_u128(cx, len), + } + } else { + None } - } else { - None - } - } else if cx.tcx.is_diagnostic_item(sym::IterEmpty, did) { - Some(0) - } else if cx.tcx.is_diagnostic_item(sym::IterOnce, did) { - Some(1) - } else { - None + }, + Some(sym::IterEmpty) => Some(0), + Some(sym::IterOnce) => Some(1), + _ => None, } } diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs index f7bb8c1d696d..750f933330a2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs @@ -50,10 +50,10 @@ fn try_get_caller_ty_name_and_method_name( } } else { if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(caller_expr).kind() { - if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) { - return Some(("Option", "and_then")); - } else if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) { - return Some(("Result", "and_then")); + match cx.tcx.get_diagnostic_name(adt.did()) { + Some(sym::Option) => return Some(("Option", "and_then")), + Some(sym::Result) => return Some(("Result", "and_then")), + _ => {}, } } None diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs index 98def66ca149..a98cfff8bfbd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs @@ -1,14 +1,16 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_expr_untyped_identity_function, is_trait_method, path_to_local}; -use rustc_ast::BindingMode; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; +use clippy_utils::{is_expr_untyped_identity_function, is_mutable, is_trait_method, path_to_local_with_projections}; use rustc_errors::Applicability; -use rustc_hir::{self as hir, Node, PatKind}; -use rustc_lint::LateContext; +use rustc_hir::{self as hir, ExprKind, Node, PatKind}; +use rustc_lint::{LateContext, LintContext}; use rustc_span::{Span, Symbol, sym}; use super::MAP_IDENTITY; +const MSG: &str = "unnecessary map of the identity function"; + pub(super) fn check( cx: &LateContext<'_>, expr: &hir::Expr<'_>, @@ -23,26 +25,70 @@ pub(super) fn check( || is_type_diagnostic_item(cx, caller_ty, sym::Result) || is_type_diagnostic_item(cx, caller_ty, sym::Option)) && is_expr_untyped_identity_function(cx, map_arg) - && let Some(sugg_span) = expr.span.trim_start(caller.span) + && let Some(call_span) = expr.span.trim_start(caller.span) { - // If the result of `.map(identity)` is used as a mutable reference, - // the caller must not be an immutable binding. - if cx.typeck_results().expr_ty_adjusted(expr).is_mutable_ptr() - && let Some(hir_id) = path_to_local(caller) - && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) - && !matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..)) - { - return; - } + let main_sugg = (call_span, String::new()); + let mut app = if is_copy(cx, caller_ty) { + // there is technically a behavioral change here for `Copy` iterators, where + // `iter.map(|x| x).next()` would mutate a temporary copy of the iterator and + // changing it to `iter.next()` mutates iter directly + Applicability::Unspecified + } else { + Applicability::MachineApplicable + }; - span_lint_and_sugg( - cx, - MAP_IDENTITY, - sugg_span, - "unnecessary map of the identity function", - format!("remove the call to `{name}`"), - String::new(), - Applicability::MachineApplicable, - ); + let needs_to_be_mutable = cx.typeck_results().expr_ty_adjusted(expr).is_mutable_ptr(); + if needs_to_be_mutable && !is_mutable(cx, caller) { + if let Some(hir_id) = path_to_local_with_projections(caller) + && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) + && let PatKind::Binding(_, _, ident, _) = pat.kind + { + // We can reach the binding -- suggest making it mutable + let suggs = vec![main_sugg, (ident.span.shrink_to_lo(), String::from("mut "))]; + + let ident = snippet_with_applicability(cx.sess(), ident.span, "_", &mut app); + + span_lint_and_then(cx, MAP_IDENTITY, call_span, MSG, |diag| { + diag.multipart_suggestion( + format!("remove the call to `{name}`, and make `{ident}` mutable"), + suggs, + app, + ); + }); + } else { + // If we can't make the binding mutable, prevent the suggestion from being automatically applied, + // and add a complementary help message. + app = Applicability::Unspecified; + + let method_requiring_mut = if let Node::Expr(expr) = cx.tcx.parent_hir_node(expr.hir_id) + && let ExprKind::MethodCall(method, ..) = expr.kind + { + Some(method.ident) + } else { + None + }; + + span_lint_and_then(cx, MAP_IDENTITY, call_span, MSG, |diag| { + diag.span_suggestion(main_sugg.0, format!("remove the call to `{name}`"), main_sugg.1, app); + + let note = if let Some(method_requiring_mut) = method_requiring_mut { + format!("this must be made mutable to use `{method_requiring_mut}`") + } else { + "this must be made mutable".to_string() + }; + diag.span_note(caller.span, note); + }); + } + } else { + span_lint_and_sugg( + cx, + MAP_IDENTITY, + main_sugg.0, + MSG, + format!("remove the call to `{name}`"), + main_sugg.1, + app, + ); + } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index 63ee922acfa0..906ead16fd0d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs @@ -38,17 +38,13 @@ pub(super) fn check( ]; let is_deref = match map_arg.kind { - hir::ExprKind::Path(ref expr_qpath) => { - cx.qpath_res(expr_qpath, map_arg.hir_id) - .opt_def_id() - .is_some_and(|fun_def_id| { - cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id) - || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id) - || deref_aliases - .iter() - .any(|&sym| cx.tcx.is_diagnostic_item(sym, fun_def_id)) - }) - }, + hir::ExprKind::Path(ref expr_qpath) => cx + .qpath_res(expr_qpath, map_arg.hir_id) + .opt_def_id() + .and_then(|fun_def_id| cx.tcx.get_diagnostic_name(fun_def_id)) + .is_some_and(|fun_name| { + matches!(fun_name, sym::deref_method | sym::deref_mut_method) || deref_aliases.contains(&fun_name) + }), hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let closure_body = cx.tcx.hir_body(body); let closure_expr = peel_blocks(closure_body.value); @@ -63,13 +59,11 @@ pub(super) fn check( .map(|x| &x.kind) .collect::>() && let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj + && let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap() + && let Some(method_name) = cx.tcx.get_diagnostic_name(method_did) { - let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); - cx.tcx.is_diagnostic_item(sym::deref_method, method_did) - || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did) - || deref_aliases - .iter() - .any(|&sym| cx.tcx.is_diagnostic_item(sym, method_did)) + matches!(method_name, sym::deref_method | sym::deref_mut_method) + || deref_aliases.contains(&method_name) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs index 3e64e15dc860..1a760ea733d7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs @@ -62,7 +62,7 @@ fn get_content_if_ctor_matches(cx: &LateContext<'_>, expr: &Expr<'_>, item: Lang if let ExprKind::Call(some_expr, [arg]) = expr.kind && is_res_lang_ctor(cx, path_res(cx, some_expr), item) { - Some(arg.span) + Some(arg.span.source_callsite()) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs index 407f2e80aff2..6738bbf0a12b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs +++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs @@ -31,8 +31,8 @@ fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool { } pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { - if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() - && cx.tcx.is_diagnostic_item(sym::Stdin, recv_adt.did()) + let recv_ty = cx.typeck_results().expr_ty(recv); + if is_type_diagnostic_item(cx, recv_ty, sym::Stdin) && let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind && let Res::Local(local_id) = path.res { diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs index ccdf5529d537..ef3d7acdc01e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs @@ -5,10 +5,10 @@ use rustc_span::sym; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { - if cx.tcx.is_diagnostic_item(sym::string_push_str, fn_def_id) { - single_char_push_string::check(cx, expr, receiver, args); - } else if cx.tcx.is_diagnostic_item(sym::string_insert_str, fn_def_id) { - single_char_insert_string::check(cx, expr, receiver, args); + match cx.tcx.get_diagnostic_name(fn_def_id) { + Some(sym::string_push_str) => single_char_push_string::check(cx, expr, receiver, args), + Some(sym::string_insert_str) => single_char_insert_string::check(cx, expr, receiver, args), + _ => {}, } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs index ce7aefed01f4..ffc237e3c24c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_diag_trait_item; use clippy_utils::source::snippet_with_context; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::print::with_forced_trimmed_paths; -use rustc_middle::ty::{self}; use rustc_span::sym; use super::SUSPICIOUS_TO_OWNED; @@ -14,8 +14,7 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && is_diag_trait_item(cx, method_def_id, sym::ToOwned) && let input_type = cx.typeck_results().expr_ty(expr) - && let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind() - && cx.tcx.is_diagnostic_item(sym::Cow, adt.did()) + && is_type_diagnostic_item(cx, input_type, sym::Cow) { let mut app = Applicability::MaybeIncorrect; let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs index 413881d5ec99..b87d81b71026 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -22,7 +22,8 @@ pub(super) fn check<'tcx>( let typeck_results = cx.typeck_results(); let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.typing_env(), typeck_results); if let Some(id) = typeck_results.type_dependent_def_id(expr.hir_id) - && (cx.tcx.is_diagnostic_item(sym::cmp_ord_min, id) || cx.tcx.is_diagnostic_item(sym::cmp_ord_max, id)) + && let Some(fn_name) = cx.tcx.get_diagnostic_name(id) + && matches!(fn_name, sym::cmp_ord_min | sym::cmp_ord_max) { if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(recv) && let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(arg) diff --git a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs index af466fe091c2..af4ade3cc0f7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind}; use rustc_lint::LateContext; -use rustc_middle::ty::AdtDef; use rustc_span::{Span, sym}; use crate::loops::UNUSED_ENUMERATE_INDEX; @@ -39,9 +39,8 @@ use crate::loops::UNUSED_ENUMERATE_INDEX; /// * `closure_arg`: The argument to the map function call containing the closure/function to apply pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) { let recv_ty = cx.typeck_results().expr_ty(recv); - if let Some(recv_ty_defid) = recv_ty.ty_adt_def().map(AdtDef::did) - // If we call a method on a `std::iter::Enumerate` instance - && cx.tcx.is_diagnostic_item(sym::Enumerate, recv_ty_defid) + // If we call a method on a `std::iter::Enumerate` instance + if is_type_diagnostic_item(cx, recv_ty, sym::Enumerate) // If we are calling a method of the `Iterator` trait && is_trait_method(cx, call_expr, sym::Iterator) // And the map argument is a closure diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index d02952eb4870..28555a610900 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::{span_lint, span_lint_hir}; use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, Attribute, find_attr}; @@ -64,14 +64,20 @@ declare_clippy_lint! { "detects missing `#[inline]` attribute for public callables (functions, trait methods, methods...)" } -fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[Attribute], sp: Span, desc: &'static str) { +fn check_missing_inline_attrs( + cx: &LateContext<'_>, + attrs: &[Attribute], + sp: Span, + desc: &'static str, + hir_id: Option, +) { if !find_attr!(attrs, AttributeKind::Inline(..)) { - span_lint( - cx, - MISSING_INLINE_IN_PUBLIC_ITEMS, - sp, - format!("missing `#[inline]` for {desc}"), - ); + let msg = format!("missing `#[inline]` for {desc}"); + if let Some(hir_id) = hir_id { + span_lint_hir(cx, MISSING_INLINE_IN_PUBLIC_ITEMS, hir_id, sp, msg); + } else { + span_lint(cx, MISSING_INLINE_IN_PUBLIC_ITEMS, sp, msg); + } } } @@ -103,17 +109,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { let desc = "a function"; let attrs = cx.tcx.hir_attrs(it.hir_id()); - check_missing_inline_attrs(cx, attrs, it.span, desc); + check_missing_inline_attrs(cx, attrs, it.span, desc, None); }, - hir::ItemKind::Trait( - ref _constness, - ref _is_auto, - ref _unsafe, - _ident, - _generics, - _bounds, - trait_items, - ) => { + hir::ItemKind::Trait(.., trait_items) => { // note: we need to check if the trait is exported so we can't use // `LateLintPass::check_trait_item` here. for &tit in trait_items { @@ -127,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { let desc = "a default trait method"; let item = cx.tcx.hir_trait_item(tit); let attrs = cx.tcx.hir_attrs(item.hir_id()); - check_missing_inline_attrs(cx, attrs, item.span, desc); + check_missing_inline_attrs(cx, attrs, item.span, desc, Some(tit.hir_id())); } }, } @@ -182,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { } let attrs = cx.tcx.hir_attrs(impl_item.hir_id()); - check_missing_inline_attrs(cx, attrs, impl_item.span, desc); + check_missing_inline_attrs(cx, attrs, impl_item.span, desc, None); } } diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index 31f51b457540..ec93ef97cfaf 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -1,4 +1,6 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; +use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; @@ -83,13 +85,18 @@ fn check_arguments<'tcx>( let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); for (argument, parameter) in iter::zip(arguments, parameters) { if let ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) = parameter.kind() - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, arg) = argument.kind { - span_lint( + let mut applicability = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability).addr(); + span_lint_and_sugg( cx, UNNECESSARY_MUT_PASSED, argument.span, format!("the {fn_kind} `{name}` doesn't need a mutable reference"), + "remove this `mut`", + sugg.to_string(), + applicability, ); } } diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index 6ae26156bc44..854e927aa2f7 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -2,16 +2,14 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ - SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, - is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_contains_comment, sym, + SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_parent_stmt, is_receiver_of_method_call, + peel_blocks, peel_blocks_with_stmt, span_contains_comment, }; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::Span; -use rustc_span::source_map::Spanned; declare_clippy_lint! { /// ### What it does @@ -50,31 +48,6 @@ declare_clippy_lint! { "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`" } -declare_clippy_lint! { - /// ### What it does - /// Checks for expressions of the form `x == true`, - /// `x != true` and order comparisons such as `x < true` (or vice versa) and - /// suggest using the variable directly. - /// - /// ### Why is this bad? - /// Unnecessary code. - /// - /// ### Example - /// ```rust,ignore - /// if x == true {} - /// if y == false {} - /// ``` - /// use `x` directly: - /// ```rust,ignore - /// if x {} - /// if !y {} - /// ``` - #[clippy::version = "pre 1.29.0"] - pub BOOL_COMPARISON, - complexity, - "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`" -} - declare_clippy_lint! { /// ### What it does /// Checks for expressions of the form `if c { x = true } else { x = false }` @@ -224,201 +197,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { } } -declare_lint_pass!(BoolComparison => [BOOL_COMPARISON]); - -impl<'tcx> LateLintPass<'tcx> for BoolComparison { - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if e.span.from_expansion() { - return; - } - - if let ExprKind::Binary(Spanned { node, .. }, ..) = e.kind { - let ignore_case = None::<(fn(_) -> _, &str)>; - let ignore_no_literal = None::<(fn(_, _) -> _, &str)>; - match node { - BinOpKind::Eq => { - let true_case = Some((|h| h, "equality checks against true are unnecessary")); - let false_case = Some(( - |h: Sugg<'tcx>| !h, - "equality checks against false can be replaced by a negation", - )); - check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); - }, - BinOpKind::Ne => { - let true_case = Some(( - |h: Sugg<'tcx>| !h, - "inequality checks against true can be replaced by a negation", - )); - let false_case = Some((|h| h, "inequality checks against false are unnecessary")); - check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); - }, - BinOpKind::Lt => check_comparison( - cx, - e, - ignore_case, - Some((|h| h, "greater than checks against false are unnecessary")), - Some(( - |h: Sugg<'tcx>| !h, - "less than comparison against true can be replaced by a negation", - )), - ignore_case, - Some(( - |l: Sugg<'tcx>, r: Sugg<'tcx>| (!l).bit_and(&r), - "order comparisons between booleans can be simplified", - )), - ), - BinOpKind::Gt => check_comparison( - cx, - e, - Some(( - |h: Sugg<'tcx>| !h, - "less than comparison against true can be replaced by a negation", - )), - ignore_case, - ignore_case, - Some((|h| h, "greater than checks against false are unnecessary")), - Some(( - |l: Sugg<'tcx>, r: Sugg<'tcx>| l.bit_and(&(!r)), - "order comparisons between booleans can be simplified", - )), - ), - _ => (), - } - } - } -} - -struct ExpressionInfoWithSpan { - one_side_is_unary_not: bool, - left_span: Span, - right_span: Span, -} - -fn is_unary_not(e: &Expr<'_>) -> (bool, Span) { - if let ExprKind::Unary(UnOp::Not, operand) = e.kind { - return (true, operand.span); - } - (false, e.span) -} - -fn one_side_is_unary_not<'tcx>(left_side: &'tcx Expr<'_>, right_side: &'tcx Expr<'_>) -> ExpressionInfoWithSpan { - let left = is_unary_not(left_side); - let right = is_unary_not(right_side); - - ExpressionInfoWithSpan { - one_side_is_unary_not: left.0 != right.0, - left_span: left.1, - right_span: right.1, - } -} - -fn check_comparison<'a, 'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, - left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, - right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, - right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, - no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &'static str)>, -) { - if let ExprKind::Binary(op, left_side, right_side) = e.kind { - let (l_ty, r_ty) = ( - cx.typeck_results().expr_ty(left_side), - cx.typeck_results().expr_ty(right_side), - ); - if is_expn_of(left_side.span, sym::cfg).is_some() || is_expn_of(right_side.span, sym::cfg).is_some() { - return; - } - if l_ty.is_bool() && r_ty.is_bool() { - let mut applicability = Applicability::MachineApplicable; - // Eliminate parentheses in `e` by using the lo pos of lhs and hi pos of rhs, - // calling `source_callsite` make sure macros are handled correctly, see issue #9907 - let binop_span = left_side - .span - .source_callsite() - .with_hi(right_side.span.source_callsite().hi()); - - if op.node == BinOpKind::Eq { - let expression_info = one_side_is_unary_not(left_side, right_side); - if expression_info.one_side_is_unary_not { - span_lint_and_sugg( - cx, - BOOL_COMPARISON, - binop_span, - "this comparison might be written more concisely", - "try simplifying it as shown", - format!( - "{} != {}", - snippet_with_applicability( - cx, - expression_info.left_span.source_callsite(), - "..", - &mut applicability - ), - snippet_with_applicability( - cx, - expression_info.right_span.source_callsite(), - "..", - &mut applicability - ) - ), - applicability, - ); - } - } - - match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) { - (Some(true), None) => left_true.map_or((), |(h, m)| { - suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h); - }), - (None, Some(true)) => right_true.map_or((), |(h, m)| { - suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h); - }), - (Some(false), None) => left_false.map_or((), |(h, m)| { - suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h); - }), - (None, Some(false)) => right_false.map_or((), |(h, m)| { - suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h); - }), - (None, None) => no_literal.map_or((), |(h, m)| { - let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability); - let right_side = Sugg::hir_with_applicability(cx, right_side, "..", &mut applicability); - span_lint_and_sugg( - cx, - BOOL_COMPARISON, - binop_span, - m, - "try simplifying it as shown", - h(left_side, right_side).into_string(), - applicability, - ); - }), - _ => (), - } - } - } -} - -fn suggest_bool_comparison<'a, 'tcx>( - cx: &LateContext<'tcx>, - span: Span, - expr: &Expr<'_>, - mut app: Applicability, - message: &'static str, - conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>, -) { - let hint = Sugg::hir_with_context(cx, expr, span.ctxt(), "..", &mut app); - span_lint_and_sugg( - cx, - BOOL_COMPARISON, - span, - message, - "try simplifying it as shown", - conv_hint(hint).into_string(), - app, - ); -} - enum Expression { Bool(bool), RetBool(bool), diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index a67545e419ce..3a6ccc2bca99 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -1,6 +1,6 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_expr}; -use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind}; +use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::Span; @@ -70,12 +70,24 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some() // Skip the lint if the body is not block because this is simpler than `for` loop. // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop. - && let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind + && let ExprKind::Closure(&Closure { body, fn_decl, .. }) = for_each_arg.kind && let body = cx.tcx.hir_body(body) // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}` // and suggesting `for … in … { unsafe { } }` is a little ugly. && !matches!(body.value.kind, ExprKind::Block(Block { rules: BlockCheckMode::UnsafeBlock(_), .. }, ..)) { + let mut applicability = Applicability::MachineApplicable; + + // If any closure parameter has an explicit type specified, applying the lint would necessarily + // remove that specification, possibly breaking type inference + if fn_decl + .inputs + .iter() + .any(|input| matches!(input.kind, TyKind::Infer(..))) + { + applicability = Applicability::MaybeIncorrect; + } + let mut ret_collector = RetCollector::default(); ret_collector.visit_expr(body.value); @@ -84,18 +96,16 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { return; } - let (mut applicability, ret_suggs) = if ret_collector.spans.is_empty() { - (Applicability::MachineApplicable, None) + let ret_suggs = if ret_collector.spans.is_empty() { + None } else { - ( - Applicability::MaybeIncorrect, - Some( - ret_collector - .spans - .into_iter() - .map(|span| (span, "continue".to_string())) - .collect(), - ), + applicability = Applicability::MaybeIncorrect; + Some( + ret_collector + .spans + .into_iter() + .map(|span| (span, "continue".to_string())) + .collect(), ) }; diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs index 04b092769666..ba67dc62abbd 100644 --- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs +++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs @@ -134,7 +134,8 @@ impl LateLintPass<'_> for NonCanonicalImpls { return; } - if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id) + let trait_name = cx.tcx.get_diagnostic_name(trait_impl.def_id); + if trait_name == Some(sym::Clone) && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy) && implements_trait(cx, trait_impl.self_ty(), copy_def_id, &[]) { @@ -170,12 +171,8 @@ impl LateLintPass<'_> for NonCanonicalImpls { String::new(), Applicability::MaybeIncorrect, ); - - return; } - } - - if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl.def_id) + } else if trait_name == Some(sym::PartialOrd) && impl_item.ident.name == sym::partial_cmp && let Some(ord_def_id) = cx.tcx.get_diagnostic_item(sym::Ord) && implements_trait(cx, trait_impl.self_ty(), ord_def_id, &[]) diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs index 23a1622f30ff..cb934466bd89 100644 --- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs +++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs @@ -43,13 +43,11 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { match &expr.kind { ExprKind::MethodCall(path, func, [param], _) => { if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def() - && ((path.ident.name == sym::mode - && matches!( - cx.tcx.get_diagnostic_name(adt.did()), - Some(sym::FsOpenOptions | sym::DirBuilder) - )) - || (path.ident.name == sym::set_mode - && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()))) + && matches!( + (cx.tcx.get_diagnostic_name(adt.did()), path.ident.name), + (Some(sym::FsOpenOptions | sym::DirBuilder), sym::mode) + | (Some(sym::FsPermissions), sym::set_mode) + ) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) && param diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs index 7317c62df7fe..2d303e40bd1c 100644 --- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::Msrv; +use clippy_utils::qualify_min_const_fn::is_stable_const_fn; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::for_each_expr_without_closures; @@ -20,7 +21,7 @@ pub(super) fn check<'tcx>( expr: &'tcx hir::Expr<'_>, assignee: &'tcx hir::Expr<'_>, e: &'tcx hir::Expr<'_>, - _msrv: Msrv, + msrv: Msrv, ) { if let hir::ExprKind::Binary(op, l, r) = &e.kind { let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| { @@ -43,10 +44,28 @@ pub(super) fn check<'tcx>( } } - // Skip if the trait is not stable in const contexts - // FIXME: reintroduce a better check after this is merged back into Clippy + // Skip if the trait or the implementation is not stable in const contexts if is_in_const_context(cx) { - return; + if cx + .tcx + .associated_item_def_ids(trait_id) + .first() + .is_none_or(|binop_id| !is_stable_const_fn(cx, *binop_id, msrv)) + { + return; + } + + let impls = cx.tcx.non_blanket_impls_for_ty(trait_id, rty).collect::>(); + if impls.is_empty() + || impls.into_iter().any(|impl_id| { + cx.tcx + .associated_item_def_ids(impl_id) + .first() + .is_none_or(|fn_id| !is_stable_const_fn(cx, *fn_id, msrv)) + }) + { + return; + } } span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index 22ec4fe60fb0..604f8f5da0b8 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -47,14 +47,10 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) (arg, arg.span) }, ExprKind::Call(path, [arg]) - if path_def_id(cx, path).is_some_and(|did| { - if cx.tcx.is_diagnostic_item(sym::from_str_method, did) { - true - } else if cx.tcx.is_diagnostic_item(sym::from_fn, did) { - !is_copy(cx, typeck.expr_ty(expr)) - } else { - false - } + if path_def_id(cx, path).is_some_and(|did| match cx.tcx.get_diagnostic_name(did) { + Some(sym::from_str_method) => true, + Some(sym::from_fn) => !is_copy(cx, typeck.expr_ty(expr)), + _ => false, }) => { (arg, arg.span) diff --git a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs index 047a5a0159cb..17fa8017c978 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs @@ -34,10 +34,11 @@ pub(crate) fn check<'tcx>( val_r, ) = lhs.kind - // right hand side matches either f32::EPSILON or f64::EPSILON + // right hand side matches _::EPSILON && let ExprKind::Path(ref epsilon_path) = rhs.kind && let Res::Def(DefKind::AssocConst, def_id) = cx.qpath_res(epsilon_path, rhs.hir_id) - && ([sym::f32_epsilon, sym::f64_epsilon].into_iter().any(|sym| cx.tcx.is_diagnostic_item(sym, def_id))) + && let Some(sym) = cx.tcx.get_diagnostic_name(def_id) + && matches!(sym, sym::f16_epsilon | sym::f32_epsilon | sym::f64_epsilon | sym::f128_epsilon) // values of the subtractions on the left hand side are of the type float && let t_val_l = cx.typeck_results().expr_ty(val_l) diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs index 449d3da76394..43db0085f2e3 100644 --- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs +++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_in_test; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; +use clippy_utils::{is_in_test, is_inside_always_const_context}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(macro_call) = root_macro_call_first_node(cx, expr) { if is_panic(cx, macro_call.def_id) { - if cx.tcx.hir_is_inside_const_context(expr.hir_id) + if is_inside_always_const_context(cx.tcx, expr.hir_id) || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id) { return; @@ -140,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { && let Res::Def(DefKind::Fn, def_id) = expr_path.res && cx.tcx.is_diagnostic_item(sym::panic_any, def_id) { - if cx.tcx.hir_is_inside_const_context(expr.hir_id) + if is_inside_always_const_context(cx.tcx, expr.hir_id) || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id) { return; diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index e57b8cc2d84e..1d58cdd26d88 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::fn_has_unsatisfiable_preds; use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage}; use clippy_utils::source::SpanRangeExt; -use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth}; +use clippy_utils::ty::{has_drop, is_copy, is_type_lang_item, walk_ptrs_ty_depth}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, LangItem, def_id}; @@ -96,14 +96,13 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { let (fn_def_id, arg, arg_ty, clone_ret) = unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind)); - let from_borrow = cx.tcx.lang_items().get(LangItem::CloneFn) == Some(fn_def_id) - || cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id) - || (cx.tcx.is_diagnostic_item(sym::to_string_method, fn_def_id) - && is_type_lang_item(cx, arg_ty, LangItem::String)); + let fn_name = cx.tcx.get_diagnostic_name(fn_def_id); - let from_deref = !from_borrow - && (cx.tcx.is_diagnostic_item(sym::path_to_pathbuf, fn_def_id) - || cx.tcx.is_diagnostic_item(sym::os_str_to_os_string, fn_def_id)); + let from_borrow = cx.tcx.lang_items().get(LangItem::CloneFn) == Some(fn_def_id) + || fn_name == Some(sym::to_owned_method) + || (fn_name == Some(sym::to_string_method) && is_type_lang_item(cx, arg_ty, LangItem::String)); + + let from_deref = !from_borrow && matches!(fn_name, Some(sym::path_to_pathbuf | sym::os_str_to_os_string)); if !from_borrow && !from_deref { continue; @@ -148,8 +147,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { is_call_with_ref_arg(cx, mir, &pred_terminator.kind) && res == cloned && cx.tcx.is_diagnostic_item(sym::deref_method, pred_fn_def_id) - && (is_type_diagnostic_item(cx, pred_arg_ty, sym::PathBuf) - || is_type_diagnostic_item(cx, pred_arg_ty, sym::OsString)) + && let ty::Adt(pred_arg_def, _) = pred_arg_ty.kind() + && let Some(pred_arg_name) = cx.tcx.get_diagnostic_name(pred_arg_def.did()) + && matches!(pred_arg_name, sym::PathBuf | sym::OsString) { (pred_arg, res) } else { diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs index db91c57b1816..1dea8f17c34b 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs @@ -155,6 +155,11 @@ impl LateLintPass<'_> for SemicolonBlock { kind: ExprKind::Block(block, _), .. }) if !block.span.from_expansion() => { + let attrs = cx.tcx.hir_attrs(stmt.hir_id); + if !attrs.is_empty() && !cx.tcx.features().stmt_expr_attributes() { + return; + } + if let Some(tail) = block.expr { self.semicolon_inside_block(cx, block, tail, stmt.span); } diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index e9534bc63a69..8c4a50041e67 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -126,6 +126,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { && !is_from_proc_macro(cx, &first_segment.ident) && !matches!(def_kind, DefKind::Macro(_)) && let Some(last_segment) = path.segments.last() + && let Res::Def(DefKind::Mod, crate_def_id) = first_segment.res + && crate_def_id.is_crate_root() { let (lint, used_mod, replace_with) = match first_segment.ident.name { sym::std => match cx.tcx.crate_name(def_id.krate) { diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 490e6c974ae1..57d5900b045e 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -457,7 +457,8 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { } fn is_one_of_trim_diagnostic_items(cx: &LateContext<'_>, trim_def_id: DefId) -> bool { - cx.tcx.is_diagnostic_item(sym::str_trim, trim_def_id) - || cx.tcx.is_diagnostic_item(sym::str_trim_start, trim_def_id) - || cx.tcx.is_diagnostic_item(sym::str_trim_end, trim_def_id) + matches!( + cx.tcx.get_diagnostic_name(trim_def_id), + Some(sym::str_trim | sym::str_trim_start | sym::str_trim_end) + ) } diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs index 08f36a2ed5d2..543f3c45e146 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -1,8 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use std::borrow::Cow; + +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{HasSession, SpanRangeExt as _}; use rustc_errors::Applicability; -use rustc_hir::{GenericArg, HirId, LetStmt, Node, Path, TyKind}; +use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind}; use rustc_lint::LateContext; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, Ty}; +use rustc_span::Span; use crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS; @@ -38,6 +42,7 @@ fn is_function_block(cx: &LateContext<'_>, expr_hir_id: HirId) -> bool { pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, path: &Path<'tcx>, + arg: &Expr<'tcx>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, expr_hir_id: HirId, @@ -68,14 +73,48 @@ pub(super) fn check<'tcx>( } else if is_function_block(cx, expr_hir_id) { return false; } - span_lint_and_sugg( + let span = last.ident.span.with_hi(path.span.hi()); + span_lint_and_then( cx, MISSING_TRANSMUTE_ANNOTATIONS, - last.ident.span.with_hi(path.span.hi()), + span, "transmute used without annotations", - "consider adding missing annotations", - format!("{}::<{from_ty}, {to_ty}>", last.ident), - Applicability::MaybeIncorrect, + |diag| { + let from_ty_no_name = ty_cannot_be_named(from_ty); + let to_ty_no_name = ty_cannot_be_named(to_ty); + if from_ty_no_name || to_ty_no_name { + let to_name = match (from_ty_no_name, to_ty_no_name) { + (true, false) => maybe_name_by_expr(cx, arg.span, "the origin type"), + (false, true) => "the destination type".into(), + _ => "the source and destination types".into(), + }; + diag.help(format!( + "consider giving {to_name} a name, and adding missing type annotations" + )); + } else { + diag.span_suggestion( + span, + "consider adding missing annotations", + format!("{}::<{from_ty}, {to_ty}>", last.ident), + Applicability::MaybeIncorrect, + ); + } + }, ); true } + +fn ty_cannot_be_named(ty: Ty<'_>) -> bool { + matches!( + ty.kind(), + ty::Alias(ty::AliasTyKind::Opaque | ty::AliasTyKind::Inherent, _) + ) +} + +fn maybe_name_by_expr<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> { + span.with_source_text(sess, |name| { + (name.len() + 9 < default.len()).then_some(format!("`{name}`'s type").into()) + }) + .flatten() + .unwrap_or(default.into()) +} diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index 1c7bb4314ddf..5fda388259a6 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -520,7 +520,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { | transmuting_null::check(cx, e, arg, to_ty) | transmute_null_to_fn::check(cx, e, arg, to_ty) | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv) - | missing_transmute_annotations::check(cx, path, from_ty, to_ty, e.hir_id) + | missing_transmute_annotations::check(cx, path, arg, from_ty, to_ty, e.hir_id) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, self.msrv) | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index f27aaa2fa77a..2257aa1b73c8 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -1,6 +1,6 @@ use super::TRANSMUTE_INT_TO_NON_ZERO; -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::sugg; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; @@ -16,35 +16,24 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, ) -> bool { - let tcx = cx.tcx; - - let (ty::Int(_) | ty::Uint(_), ty::Adt(adt, substs)) = (&from_ty.kind(), to_ty.kind()) else { - return false; - }; - - if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { - return false; + if let ty::Int(_) | ty::Uint(_) = from_ty.kind() + && let ty::Adt(adt, substs) = to_ty.kind() + && cx.tcx.is_diagnostic_item(sym::NonZero, adt.did()) + && let int_ty = substs.type_at(0) + && from_ty == int_ty + { + let arg = Sugg::hir(cx, arg, ".."); + span_lint_and_sugg( + cx, + TRANSMUTE_INT_TO_NON_ZERO, + e.span, + format!("transmute from a `{from_ty}` to a `{}<{int_ty}>`", sym::NonZero), + "consider using", + format!("{}::{}({arg})", sym::NonZero, sym::new_unchecked), + Applicability::Unspecified, + ); + true + } else { + false } - - let int_ty = substs.type_at(0); - if from_ty != int_ty { - return false; - } - - span_lint_and_then( - cx, - TRANSMUTE_INT_TO_NON_ZERO, - e.span, - format!("transmute from a `{from_ty}` to a `{}<{int_ty}>`", sym::NonZero), - |diag| { - let arg = sugg::Sugg::hir(cx, arg, ".."); - diag.span_suggestion( - e.span, - "consider using", - format!("{}::{}({arg})", sym::NonZero, sym::new_unchecked), - Applicability::Unspecified, - ); - }, - ); - true } diff --git a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs index d691f1878b11..c4fd0fbf87a9 100644 --- a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs +++ b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs @@ -11,7 +11,8 @@ use super::RC_BUFFER; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { let app = Applicability::Unspecified; - if cx.tcx.is_diagnostic_item(sym::Rc, def_id) { + let name = cx.tcx.get_diagnostic_name(def_id); + if name == Some(sym::Rc) { if let Some(alternate) = match_buffer_type(cx, qpath) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( @@ -56,7 +57,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ ); return true; } - } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) { + } else if name == Some(sym::Arc) { if let Some(alternate) = match_buffer_type(cx, qpath) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs index de3456a8ba5f..0ba51daf027d 100644 --- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs +++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs @@ -13,14 +13,11 @@ use super::{REDUNDANT_ALLOCATION, utils}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: &QPath<'tcx>, def_id: DefId) -> bool { let mut applicability = Applicability::MaybeIncorrect; - let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() { - "Box" - } else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) { - "Rc" - } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) { - "Arc" - } else { - return false; + let outer_sym = match cx.tcx.get_diagnostic_name(def_id) { + _ if Some(def_id) == cx.tcx.lang_items().owned_box() => "Box", + Some(sym::Rc) => "Rc", + Some(sym::Arc) => "Arc", + _ => return false, }; if let Some(span) = utils::match_borrows_parameter(cx, qpath) { diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs index 48b532968cb5..38716519e23b 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; -use clippy_utils::sym; +use clippy_utils::{is_unit_expr, sym}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -16,10 +16,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { sym::assert_ne_macro | sym::debug_assert_ne_macro => "fail", _ => return, }; - let Some((left, _, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { + let Some((lhs, rhs, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return; }; - if !cx.typeck_results().expr_ty(left).is_unit() { + if is_unit_expr(lhs) || is_unit_expr(rhs) { + return; + } + if !cx.typeck_results().expr_ty(lhs).is_unit() { return; } span_lint( diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs index 7d996775a58c..28f4884fa311 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -41,7 +41,8 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings { && let ty::Ref(_, inner_str, _) = cx.typeck_results().expr_ty_adjusted(expr).kind() && inner_str.is_str() { - if cx.tcx.is_diagnostic_item(sym::string_new, fun_def_id) { + let fun_name = cx.tcx.get_diagnostic_name(fun_def_id); + if fun_name == Some(sym::string_new) { span_lint_and_sugg( cx, UNNECESSARY_OWNED_EMPTY_STRINGS, @@ -51,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings { "\"\"".to_owned(), Applicability::MachineApplicable, ); - } else if cx.tcx.is_diagnostic_item(sym::from_fn, fun_def_id) + } else if fun_name == Some(sym::from_fn) && let [arg] = args && let ExprKind::Lit(spanned) = &arg.kind && let LitKind::Str(symbol, _) = spanned.node diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index 54a7efc090ad..849c0b438a5a 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -107,12 +107,10 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { // Get the wrapper and inner types, if can't, abort. let (return_type_label, lang_item, inner_type) = if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id.expect_owner()).kind() { - if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) { - ("Option", OptionSome, subst.type_at(0)) - } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) { - ("Result", ResultOk, subst.type_at(0)) - } else { - return; + match cx.tcx.get_diagnostic_name(adt_def.did()) { + Some(sym::Option) => ("Option", OptionSome, subst.type_at(0)), + Some(sym::Result) => ("Result", ResultOk, subst.type_at(0)), + _ => return, } } else { return; diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 8b278d98a30e..f3410c98973f 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -326,7 +326,11 @@ fn extend_with_struct_pat( if idx_1 == idx { // In the case of `k`, we merely require identical field names // so that we will transform into `ident_k: p1_k | p2_k`. - let pos = fps2.iter().position(|fp2| eq_id(fp1.ident, fp2.ident)); + let pos = fps2.iter().position(|fp2| { + // Avoid `Foo { bar } | Foo { bar }` => `Foo { bar | bar }` + !(fp1.is_shorthand && fp2.is_shorthand) + && eq_id(fp1.ident, fp2.ident) + }); pos_in_2.set(pos); pos.is_some() } else { diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index f3cd3f1bb286..af3ad4566c46 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -89,7 +89,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { { // We don't want to lint inside io::Read or io::Write implementations, as the author has more // information about their trait implementation than our lint, see https://github.com/rust-lang/rust-clippy/issues/4836 - if cx.tcx.is_diagnostic_item(sym::IoRead, trait_id) || cx.tcx.is_diagnostic_item(sym::IoWrite, trait_id) { + if let Some(trait_name) = cx.tcx.get_diagnostic_name(trait_id) + && matches!(trait_name, sym::IoRead | sym::IoWrite) + { return; } diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index 3811f0fe6b55..d503bd3379b0 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -6,13 +6,13 @@ use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, Node, PolyTraitRef, Term, - Ty, TyKind, + AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, PolyTraitRef, Term, Ty, + TyKind, }; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::edition::Edition; -use rustc_span::{BytePos, Span, sym}; +use rustc_span::{BytePos, Pos as _, Span, sym}; declare_clippy_lint! { /// ### What it does @@ -49,19 +49,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit { decl: &'tcx FnDecl<'tcx>, body: &'tcx Body<'tcx>, span: Span, - def_id: LocalDefId, + _def_id: LocalDefId, ) { if let FnRetTy::Return(hir_ty) = decl.output && is_unit_ty(hir_ty) && !hir_ty.span.from_expansion() && get_def(span) == get_def(hir_ty.span) { - // implicit types in closure signatures are forbidden when `for<...>` is present - if let FnKind::Closure = kind - && let Node::Expr(expr) = cx.tcx.hir_node_by_def_id(def_id) - && let ExprKind::Closure(closure) = expr.kind - && !closure.bound_generic_params.is_empty() - { + // The explicit `-> ()` in the closure signature might be necessary for multiple reasons: + // - Implicit types in closure signatures are forbidden when `for<...>` is present + // - If the closure body ends with a function call, and that function's return type is generic, the + // `-> ()` could be required for it to be inferred + // + // There could be more reasons to have it, and, in general, we shouldn't discourage the users from + // writing more type annotations than strictly necessary, because it can help readability and + // maintainability + if let FnKind::Closure = kind { return; } @@ -97,16 +100,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit { } fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) { - let segments = &poly.trait_ref.path.segments; - - if segments.len() == 1 - && matches!(segments[0].ident.name, sym::Fn | sym::FnMut | sym::FnOnce) - && let Some(args) = segments[0].args + if let [segment] = &poly.trait_ref.path.segments + && matches!(segment.ident.name, sym::Fn | sym::FnMut | sym::FnOnce) + && let Some(args) = segment.args && args.parenthesized == GenericArgsParentheses::ParenSugar - && let constraints = &args.constraints - && constraints.len() == 1 - && constraints[0].ident.name == sym::Output - && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraints[0].kind + && let [constraint] = &args.constraints + && constraint.ident.name == sym::Output + && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraint.kind && args.span_ext.hi() != poly.span.hi() && !hir_ty.span.from_expansion() && args.span_ext.hi() != hir_ty.span.hi() @@ -160,17 +160,15 @@ fn get_def(span: Span) -> Option { fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span, span: Span) { let (ret_span, appl) = - span.with_hi(ty_span.hi()) - .get_source_text(cx) - .map_or((ty_span, Applicability::MaybeIncorrect), |src| { - position_before_rarrow(&src).map_or((ty_span, Applicability::MaybeIncorrect), |rpos| { - ( - #[expect(clippy::cast_possible_truncation)] - ty_span.with_lo(BytePos(span.lo().0 + rpos as u32)), - Applicability::MachineApplicable, - ) - }) - }); + if let Some(Some(rpos)) = span.with_hi(ty_span.hi()).with_source_text(cx, position_before_rarrow) { + ( + ty_span.with_lo(span.lo() + BytePos::from_usize(rpos)), + Applicability::MachineApplicable, + ) + } else { + (ty_span, Applicability::MaybeIncorrect) + }; + span_lint_and_sugg( cx, UNUSED_UNIT, diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs index 7bec212a23ca..f26647fa3485 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::for_each_expr; -use clippy_utils::{method_chain_args, return_ty}; -use core::ops::ControlFlow; -use rustc_hir as hir; -use rustc_hir::ImplItemKind; +use clippy_utils::{return_ty, sym}; +use rustc_hir::{ + Body, BodyOwnerKind, Expr, ExprKind, FnSig, ImplItem, ImplItemKind, Item, ItemKind, OwnerId, PathSegment, QPath, +}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_middle::ty::Ty; +use rustc_session::impl_lint_pass; +use rustc_span::{Ident, Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -57,62 +56,165 @@ declare_clippy_lint! { "functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`" } -declare_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]); +impl_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]); -impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { - if let ImplItemKind::Fn(ref _signature, _) = impl_item.kind - // first check if it's a method or function - // checking if its return type is `result` or `option` - && (is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result) - || is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Option)) - { - lint_impl_body(cx, impl_item.span, impl_item); +#[derive(Clone, Copy, Eq, PartialEq)] +enum OptionOrResult { + Option, + Result, +} + +impl OptionOrResult { + fn with_article(self) -> &'static str { + match self { + Self::Option => "an `Option`", + Self::Result => "a `Result`", } } } -fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) { - if let ImplItemKind::Fn(_, body_id) = impl_item.kind { - let body = cx.tcx.hir_body(body_id); - let typeck = cx.tcx.typeck(impl_item.owner_id.def_id); - let mut result = Vec::new(); - let _: Option = for_each_expr(cx, body.value, |e| { - // check for `expect` - if let Some(arglists) = method_chain_args(e, &[sym::expect]) { - let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); - if is_type_diagnostic_item(cx, receiver_ty, sym::Option) - || is_type_diagnostic_item(cx, receiver_ty, sym::Result) - { - result.push(e.span); - } - } +struct OptionOrResultFn { + kind: OptionOrResult, + return_ty_span: Option, +} - // check for `unwrap` - if let Some(arglists) = method_chain_args(e, &[sym::unwrap]) { - let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); - if is_type_diagnostic_item(cx, receiver_ty, sym::Option) - || is_type_diagnostic_item(cx, receiver_ty, sym::Result) - { - result.push(e.span); - } - } +#[derive(Default)] +pub struct UnwrapInResult { + fn_stack: Vec>, + current_fn: Option, +} - ControlFlow::Continue(()) +impl UnwrapInResult { + fn enter_item(&mut self, cx: &LateContext<'_>, fn_def_id: OwnerId, sig: &FnSig<'_>) { + self.fn_stack.push(self.current_fn.take()); + self.current_fn = is_option_or_result(cx, return_ty(cx, fn_def_id)).map(|kind| OptionOrResultFn { + kind, + return_ty_span: Some(sig.decl.output.span()), }); + } - // if we've found one, lint - if !result.is_empty() { + fn leave_item(&mut self) { + self.current_fn = self.fn_stack.pop().unwrap(); + } +} + +impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { + if let ImplItemKind::Fn(sig, _) = &impl_item.kind { + self.enter_item(cx, impl_item.owner_id, sig); + } + } + + fn check_impl_item_post(&mut self, _: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'tcx>) { + if let ImplItemKind::Fn(..) = impl_item.kind { + self.leave_item(); + } + } + + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if let ItemKind::Fn { + has_body: true, sig, .. + } = &item.kind + { + self.enter_item(cx, item.owner_id, sig); + } + } + + fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if let ItemKind::Fn { has_body: true, .. } = item.kind { + self.leave_item(); + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if expr.span.from_expansion() { + return; + } + + if let Some(OptionOrResultFn { + kind, + ref mut return_ty_span, + }) = self.current_fn + && let Some((oor, fn_name)) = is_unwrap_or_expect_call(cx, expr) + && oor == kind + { span_lint_and_then( cx, UNWRAP_IN_RESULT, - impl_span, - "used unwrap or expect in a function that returns result or option", - move |diag| { - diag.help("unwrap and expect should not be used in a function that returns result or option"); - diag.span_note(result, "potential non-recoverable error(s)"); + expr.span, + format!("`{fn_name}` used in a function that returns {}", kind.with_article()), + |diag| { + // Issue the note and help only once per function + if let Some(span) = return_ty_span.take() { + diag.span_note(span, "in this function signature"); + let complement = if kind == OptionOrResult::Result { + " or calling the `.map_err()` method" + } else { + "" + }; + diag.help(format!("consider using the `?` operator{complement}")); + } }, ); } } + + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) { + let body_def_id = cx.tcx.hir_body_owner_def_id(body.id()); + if !matches!(cx.tcx.hir_body_owner_kind(body_def_id), BodyOwnerKind::Fn) { + // When entering a body which is not a function, mask the potential surrounding + // function to not apply the lint. + self.fn_stack.push(self.current_fn.take()); + } + } + + fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) { + let body_def_id = cx.tcx.hir_body_owner_def_id(body.id()); + if !matches!(cx.tcx.hir_body_owner_kind(body_def_id), BodyOwnerKind::Fn) { + // Unmask the potential surrounding function. + self.current_fn = self.fn_stack.pop().unwrap(); + } + } +} + +fn is_option_or_result(cx: &LateContext<'_>, ty: Ty<'_>) -> Option { + match ty.ty_adt_def().and_then(|def| cx.tcx.get_diagnostic_name(def.did())) { + Some(sym::Option) => Some(OptionOrResult::Option), + Some(sym::Result) => Some(OptionOrResult::Result), + _ => None, + } +} + +fn is_unwrap_or_expect_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(OptionOrResult, Symbol)> { + if let ExprKind::Call(func, _) = expr.kind + && let ExprKind::Path(QPath::TypeRelative( + hir_ty, + PathSegment { + ident: + Ident { + name: name @ (sym::unwrap | sym::expect), + .. + }, + .. + }, + )) = func.kind + { + is_option_or_result(cx, cx.typeck_results().node_type(hir_ty.hir_id)).map(|oor| (oor, *name)) + } else if let ExprKind::MethodCall( + PathSegment { + ident: Ident { + name: name @ (sym::unwrap | sym::expect), + .. + }, + .. + }, + recv, + _, + _, + ) = expr.kind + { + is_option_or_result(cx, cx.typeck_results().expr_ty_adjusted(recv)).map(|oor| (oor, *name)) + } else { + None + } } diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index e5b20c0e0a13..70ae982a4458 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -386,12 +386,13 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ExprKind::Call(path, [arg]) => { if let ExprKind::Path(ref qpath) = path.kind - && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && !is_ty_alias(qpath) + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && let Some(name) = cx.tcx.get_diagnostic_name(def_id) { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(arg); - if cx.tcx.is_diagnostic_item(sym::try_from_fn, def_id) + if name == sym::try_from_fn && is_type_diagnostic_item(cx, a, sym::Result) && let ty::Adt(_, args) = a.kind() && let Some(a_type) = args.types().next() @@ -406,9 +407,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { None, hint, ); - } - - if cx.tcx.is_diagnostic_item(sym::from_fn, def_id) && same_type_and_consts(a, b) { + } else if name == sym::from_fn && same_type_and_consts(a, b) { let mut app = Applicability::MachineApplicable; let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "", &mut app).maybe_paren(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index 7b6a25123e85..52b30ddce12b 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -1,4 +1,6 @@ use std::collections::BTreeMap; +use std::collections::btree_map::Entry; +use std::mem; use std::ops::ControlFlow; use clippy_config::Conf; @@ -20,15 +22,36 @@ use rustc_span::{DesugaringKind, Span}; pub struct UselessVec { too_large_for_stack: u64, msrv: Msrv, - span_to_lint_map: BTreeMap>, + /// Maps from a `vec![]` source callsite invocation span to the "state" (i.e., whether we can + /// emit a warning there or not). + /// + /// The purpose of this is to buffer lints up until `check_crate_post` so that we can cancel a + /// lint while visiting, because a `vec![]` invocation span can appear multiple times when + /// it is passed as a macro argument, once in a context that doesn't require a `Vec<_>` and + /// another time that does. Consider: + /// ``` + /// macro_rules! m { + /// ($v:expr) => { + /// let a = $v; + /// $v.push(3); + /// } + /// } + /// m!(vec![1, 2]); + /// ``` + /// The macro invocation expands to two `vec![1, 2]` invocations. If we eagerly suggest changing + /// the first `vec![1, 2]` (which is shared with the other expn) to an array which indeed would + /// work, we get a false positive warning on the `$v.push(3)` which really requires `$v` to + /// be a vector. + span_to_state: BTreeMap, allow_in_test: bool, } + impl UselessVec { pub fn new(conf: &'static Conf) -> Self { Self { too_large_for_stack: conf.too_large_for_stack, msrv: conf.msrv, - span_to_lint_map: BTreeMap::new(), + span_to_state: BTreeMap::new(), allow_in_test: conf.allow_useless_vec_in_tests, } } @@ -62,17 +85,28 @@ declare_clippy_lint! { impl_lint_pass!(UselessVec => [USELESS_VEC]); -impl<'tcx> LateLintPass<'tcx> for UselessVec { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) else { - return; - }; - if self.allow_in_test && is_in_test(cx.tcx, expr.hir_id) { - return; - } - // the parent callsite of this `vec!` expression, or span to the borrowed one such as `&vec!` - let callsite = expr.span.parent_callsite().unwrap_or(expr.span); +/// The "state" of a `vec![]` invocation, indicating whether it can or cannot be changed. +enum VecState { + Change { + suggest_ty: SuggestedType, + vec_snippet: String, + expr_hir_id: HirId, + }, + NoChange, +} +enum VecToArray { + /// Expression does not need to be a `Vec<_>` and its type can be changed to an array (or + /// slice). + Possible, + /// Expression must be a `Vec<_>`. Type cannot change. + Impossible, +} + +impl UselessVec { + /// Checks if the surrounding environment requires this expression to actually be of type + /// `Vec<_>`, or if it can be changed to `&[]`/`[]` without causing type errors. + fn expr_usage_requires_vec(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) -> VecToArray { match cx.tcx.parent_hir_node(expr.hir_id) { // search for `let foo = vec![_]` expressions where all uses of `foo` // adjust to slices or call a method that exist on slices (e.g. len) @@ -100,107 +134,123 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { .is_continue(); if only_slice_uses { - self.check_vec_macro(cx, &vec_args, callsite, expr.hir_id, SuggestedType::Array); + VecToArray::Possible } else { - self.span_to_lint_map.insert(callsite, None); + VecToArray::Impossible } }, // if the local pattern has a specified type, do not lint. Node::LetStmt(LetStmt { ty: Some(_), .. }) if higher::VecArgs::hir(cx, expr).is_some() => { - self.span_to_lint_map.insert(callsite, None); + VecToArray::Impossible }, // search for `for _ in vec![...]` Node::Expr(Expr { span, .. }) if span.is_desugaring(DesugaringKind::ForLoop) && self.msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR) => { - let suggest_slice = suggest_type(expr); - self.check_vec_macro(cx, &vec_args, callsite, expr.hir_id, suggest_slice); + VecToArray::Possible }, // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]` _ => { - let suggest_slice = suggest_type(expr); - if adjusts_to_slice(cx, expr) { - self.check_vec_macro(cx, &vec_args, callsite, expr.hir_id, suggest_slice); + VecToArray::Possible } else { - self.span_to_lint_map.insert(callsite, None); + VecToArray::Impossible } }, } } - - fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { - for (span, lint_opt) in &self.span_to_lint_map { - if let Some((hir_id, suggest_slice, snippet, applicability)) = lint_opt { - let help_msg = format!("you can use {} directly", suggest_slice.desc()); - span_lint_hir_and_then(cx, USELESS_VEC, *hir_id, *span, "useless use of `vec!`", |diag| { - // If the `vec!` macro contains comment, better not make the suggestion machine - // applicable as it would remove them. - let applicability = if *applicability != Applicability::Unspecified - && let source_map = cx.tcx.sess.source_map() - && span_contains_comment(source_map, *span) - { - Applicability::Unspecified - } else { - *applicability - }; - diag.span_suggestion(*span, help_msg, snippet, applicability); - }); - } - } - } } -impl UselessVec { - fn check_vec_macro<'tcx>( - &mut self, - cx: &LateContext<'tcx>, - vec_args: &higher::VecArgs<'tcx>, - span: Span, - hir_id: HirId, - suggest_slice: SuggestedType, - ) { - if span.from_expansion() { - return; +impl<'tcx> LateLintPass<'tcx> for UselessVec { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) + // The `vec![]` or `&vec![]` invocation span. + && let vec_span = expr.span.parent_callsite().unwrap_or(expr.span) + && !vec_span.from_expansion() + { + if self.allow_in_test && is_in_test(cx.tcx, expr.hir_id) { + return; + } + + match self.expr_usage_requires_vec(cx, expr) { + VecToArray::Possible => { + let suggest_ty = suggest_type(expr); + + // Size and `Copy` checks don't depend on the enclosing usage of the expression + // and don't need to be inserted into the state map. + let vec_snippet = match vec_args { + higher::VecArgs::Repeat(expr, len) => { + if is_copy(cx, cx.typeck_results().expr_ty(expr)) + && let Some(Constant::Int(length)) = ConstEvalCtxt::new(cx).eval(len) + && let Ok(length) = u64::try_from(length) + && size_of(cx, expr) + .checked_mul(length) + .is_some_and(|size| size <= self.too_large_for_stack) + { + suggest_ty.snippet( + cx, + Some(expr.span.source_callsite()), + Some(len.span.source_callsite()), + ) + } else { + return; + } + }, + higher::VecArgs::Vec(args) => { + if let Ok(length) = u64::try_from(args.len()) + && size_of(cx, expr) + .checked_mul(length) + .is_some_and(|size| size <= self.too_large_for_stack) + { + suggest_ty.snippet( + cx, + args.first().zip(args.last()).map(|(first, last)| { + first.span.source_callsite().to(last.span.source_callsite()) + }), + None, + ) + } else { + return; + } + }, + }; + + if let Entry::Vacant(entry) = self.span_to_state.entry(vec_span) { + entry.insert(VecState::Change { + suggest_ty, + vec_snippet, + expr_hir_id: expr.hir_id, + }); + } + }, + VecToArray::Impossible => { + self.span_to_state.insert(vec_span, VecState::NoChange); + }, + } } + } - let snippet = match *vec_args { - higher::VecArgs::Repeat(elem, len) => { - if let Some(Constant::Int(len_constant)) = ConstEvalCtxt::new(cx).eval(len) { - // vec![ty; N] works when ty is Clone, [ty; N] requires it to be Copy also - if !is_copy(cx, cx.typeck_results().expr_ty(elem)) { - return; - } - - #[expect(clippy::cast_possible_truncation)] - if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack { - return; - } - - suggest_slice.snippet(cx, Some(elem.span), Some(len.span)) - } else { - return; - } - }, - higher::VecArgs::Vec(args) => { - let args_span = if let Some(last) = args.iter().last() { - if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack { - return; - } - Some(args[0].span.source_callsite().to(last.span.source_callsite())) - } else { - None - }; - suggest_slice.snippet(cx, args_span, None) - }, - }; - - self.span_to_lint_map.entry(span).or_insert(Some(( - hir_id, - suggest_slice, - snippet, - Applicability::MachineApplicable, - ))); + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + for (span, state) in mem::take(&mut self.span_to_state) { + if let VecState::Change { + suggest_ty, + vec_snippet, + expr_hir_id, + } = state + { + span_lint_hir_and_then(cx, USELESS_VEC, expr_hir_id, span, "useless use of `vec!`", |diag| { + let help_msg = format!("you can use {} directly", suggest_ty.desc()); + // If the `vec!` macro contains comment, better not make the suggestion machine applicable as it + // would remove them. + let applicability = if span_contains_comment(cx.tcx.sess.source_map(), span) { + Applicability::Unspecified + } else { + Applicability::MachineApplicable + }; + diag.span_suggestion(span, help_msg, vec_snippet, applicability); + }); + } + } } } @@ -221,11 +271,17 @@ impl SuggestedType { } fn snippet(self, cx: &LateContext<'_>, args_span: Option, len_span: Option) -> String { + // Invariant of the lint as implemented: all spans are from the root context (and as a result, + // always trivially crate-local). + assert!(args_span.is_none_or(|s| !s.from_expansion())); + assert!(len_span.is_none_or(|s| !s.from_expansion())); + let maybe_args = args_span - .and_then(|sp| sp.get_source_text(cx)) + .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")) .map_or(String::new(), |x| x.to_owned()); let maybe_len = len_span - .and_then(|sp| sp.get_source_text(cx).map(|s| format!("; {s}"))) + .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")) + .map(|st| format!("; {st}")) .unwrap_or_default(); match self { diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index a15e4e42e71d..c55c5ec2f51a 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -537,7 +537,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { sug_span = Some(sug_span.unwrap_or(arg.expr.span).to(arg.expr.span)); - if let Some((_, index)) = positional_arg_piece_span(piece) { + if let Some((_, index)) = format_arg_piece_span(piece) { replaced_position.push(index); } @@ -569,16 +569,11 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { } } -/// Extract Span and its index from the given `piece`, if it's positional argument. -fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> { +/// Extract Span and its index from the given `piece` +fn format_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> { match piece { FormatArgsPiece::Placeholder(FormatPlaceholder { - argument: - FormatArgPosition { - index: Ok(index), - kind: FormatArgPositionKind::Number, - .. - }, + argument: FormatArgPosition { index: Ok(index), .. }, span: Some(span), .. }) => Some((*span, *index)), diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs index 6ab94a522109..a934d2094e00 100644 --- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs +++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs @@ -1,5 +1,6 @@ use ControlFlow::{Break, Continue}; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{fn_def_id, get_enclosing_block, path_to_local_id}; use rustc_ast::Mutability; use rustc_ast::visit::visit_opt; @@ -58,8 +59,8 @@ declare_lint_pass!(ZombieProcesses => [ZOMBIE_PROCESSES]); impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Call(..) | ExprKind::MethodCall(..) = expr.kind - && let Some(child_adt) = cx.typeck_results().expr_ty(expr).ty_adt_def() - && cx.tcx.is_diagnostic_item(sym::Child, child_adt.did()) + && let child_ty = cx.typeck_results().expr_ty(expr) + && is_type_diagnostic_item(cx, child_ty, sym::Child) { match cx.tcx.parent_hir_node(expr.hir_id) { Node::LetStmt(local) @@ -177,8 +178,8 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { Node::Expr(expr) if let ExprKind::AddrOf(_, Mutability::Not, _) = expr.kind => {}, Node::Expr(expr) if let Some(fn_did) = fn_def_id(self.cx, expr) - && (self.cx.tcx.is_diagnostic_item(sym::child_id, fn_did) - || self.cx.tcx.is_diagnostic_item(sym::child_kill, fn_did)) => {}, + && let Some(fn_name) = self.cx.tcx.get_diagnostic_name(fn_did) + && matches!(fn_name, sym::child_id | sym::child_kill) => {}, // Conservatively assume that all other kinds of nodes call `.wait()` somehow. _ => return Break(MaybeWait(ex.span)), @@ -351,9 +352,14 @@ fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, cause: Caus /// Checks if the given expression exits the process. fn is_exit_expression(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - fn_def_id(cx, expr).is_some_and(|fn_did| { - cx.tcx.is_diagnostic_item(sym::process_exit, fn_did) || cx.tcx.is_diagnostic_item(sym::process_abort, fn_did) - }) + if let Some(fn_did) = fn_def_id(cx, expr) + && let Some(fn_name) = cx.tcx.get_diagnostic_name(fn_did) + && matches!(fn_name, sym::process_exit | sym::process_abort) + { + true + } else { + false + } } #[derive(Debug)] diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index 2dfe28953d0c..e01f563c49e7 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-08-22 +nightly-2025-09-04 ``` diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 40c00568a3bd..ad69e6eb184e 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -21,7 +21,7 @@ pub fn is_useless_with_eq_exprs(kind: BinOpKind) -> bool { } /// Checks if each element in the first slice is contained within the latter as per `eq_fn`. -pub fn unordered_over(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { +pub fn unordered_over(left: &[X], right: &[Y], mut eq_fn: impl FnMut(&X, &Y) -> bool) -> bool { left.len() == right.len() && left.iter().all(|l| right.iter().any(|r| eq_fn(l, r))) } diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 4e0b00df9508..bda28a663fb0 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -287,23 +287,22 @@ impl<'a> VecArgs<'a> { && let ExprKind::Path(ref qpath) = fun.kind && is_expn_of(fun.span, sym::vec).is_some() && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() + && let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id) { - return if cx.tcx.is_diagnostic_item(sym::vec_from_elem, fun_def_id) && args.len() == 2 { - // `vec![elem; size]` case - Some(VecArgs::Repeat(&args[0], &args[1])) - } else if cx.tcx.is_diagnostic_item(sym::slice_into_vec, fun_def_id) && args.len() == 1 { - // `vec![a, b, c]` case - if let ExprKind::Call(_, [arg]) = &args[0].kind - && let ExprKind::Array(args) = arg.kind + return match (name, args) { + (sym::vec_from_elem, [elem, size]) => { + // `vec![elem; size]` case + Some(VecArgs::Repeat(elem, size)) + }, + (sym::slice_into_vec, [slice]) + if let ExprKind::Call(_, [arg]) = slice.kind + && let ExprKind::Array(args) = arg.kind => { + // `vec![a, b, c]` case Some(VecArgs::Vec(args)) - } else { - None - } - } else if cx.tcx.is_diagnostic_item(sym::vec_new, fun_def_id) && args.is_empty() { - Some(VecArgs::Vec(&[])) - } else { - None + }, + (sym::vec_new, []) => Some(VecArgs::Vec(&[])), + _ => None, }; } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 8160443f4132..b79e15cd7170 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -757,7 +757,7 @@ pub fn both_some_and(l: Option, r: Option, mut pred: impl FnMut(X, Y } /// Checks if two slices are equal as per `eq_fn`. -pub fn over(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { +pub fn over(left: &[X], right: &[Y], mut eq_fn: impl FnMut(&X, &Y) -> bool) -> bool { left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 011c9b2f931a..14b64eb4d54e 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -102,9 +102,9 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{ self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, CoroutineDesugaring, - CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl, - ImplItem, ImplItemKind, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, - Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem, + CoroutineKind, CoroutineSource, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, + HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, + OwnerNode, Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp, def, find_attr, }; use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; @@ -126,6 +126,7 @@ use rustc_span::{InnerSpan, Span}; use source::{SpanRangeExt, walk_span_to_context}; use visitors::{Visitable, for_each_unconsumed_temporary}; +use crate::ast_utils::unordered_over; use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; use crate::higher::Range; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; @@ -308,6 +309,7 @@ pub fn is_lang_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: LangItem) -> cx.tcx.lang_items().get(item) == Some(did) } +/// Checks if `expr` is an empty block or an empty tuple. pub fn is_unit_expr(expr: &Expr<'_>) -> bool { matches!( expr.kind, @@ -640,9 +642,8 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< && let Some(impl_did) = cx.tcx.impl_of_assoc(def_id) && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() { - return std_types_symbols.iter().any(|&symbol| { - cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string() - }); + return Some(adt.did()) == cx.tcx.lang_items().string() + || (cx.tcx.get_diagnostic_name(adt.did())).is_some_and(|adt_name| std_types_symbols.contains(&adt_name)); } false } @@ -1992,7 +1993,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr< (PatKind::Tuple(pats, dotdot), ExprKind::Tup(tup)) if dotdot.as_opt_usize().is_none() && pats.len() == tup.len() => { - zip(pats, tup).all(|(pat, expr)| is_expr_identity_of_pat(cx, pat, expr, by_hir)) + over(pats, tup, |pat, expr| is_expr_identity_of_pat(cx, pat, expr, by_hir)) }, (PatKind::Slice(before, None, after), ExprKind::Array(arr)) if before.len() + after.len() == arr.len() => { zip(before.iter().chain(after), arr).all(|(pat, expr)| is_expr_identity_of_pat(cx, pat, expr, by_hir)) @@ -2004,7 +2005,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr< if let ExprKind::Path(ident) = &ident.kind && qpath_res(&pat_ident, pat.hir_id) == qpath_res(ident, expr.hir_id) // check fields - && zip(field_pats, fields).all(|(pat, expr)| is_expr_identity_of_pat(cx, pat, expr,by_hir)) + && over(field_pats, fields, |pat, expr| is_expr_identity_of_pat(cx, pat, expr,by_hir)) { true } else { @@ -2017,10 +2018,8 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr< // check ident qpath_res(&pat_ident, pat.hir_id) == qpath_res(ident, expr.hir_id) // check fields - && field_pats.iter().all(|field_pat| { - fields.iter().any(|field| { - field_pat.ident == field.ident && is_expr_identity_of_pat(cx, field_pat.pat, field.expr, by_hir) - }) + && unordered_over(field_pats, fields, |field_pat, field| { + field_pat.ident == field.ident && is_expr_identity_of_pat(cx, field_pat.pat, field.expr, by_hir) }) }, _ => false, @@ -2405,6 +2404,24 @@ pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir> expr } +/// Returns a `Vec` of `Expr`s containing `AddrOf` operators (`&`) or deref operators (`*`) of a +/// given expression. +pub fn get_ref_operators<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>) -> Vec<&'hir Expr<'hir>> { + let mut operators = Vec::new(); + peel_hir_expr_while(expr, |expr| match expr.kind { + ExprKind::AddrOf(_, _, e) => { + operators.push(expr); + Some(e) + }, + ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => { + operators.push(expr); + Some(e) + }, + _ => None, + }); + operators +} + pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind && let Res::Def(_, def_id) = path.res @@ -3633,3 +3650,17 @@ pub fn expr_adjustment_requires_coercion(cx: &LateContext<'_>, expr: &Expr<'_>) ) }) } + +/// Checks if the expression is an async block (i.e., `async { ... }`). +pub fn is_expr_async_block(expr: &Expr<'_>) -> bool { + matches!( + expr.kind, + ExprKind::Closure(Closure { + kind: hir::ClosureKind::Coroutine(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + CoroutineSource::Block + )), + .. + }) + ) +} diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index fafc1d07e51e..8e302f9d2ad1 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -387,10 +387,7 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { /// Checks if the type is a reference equals to a diagnostic item pub fn is_type_ref_to_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool { match ty.kind() { - ty::Ref(_, ref_ty, _) => match ref_ty.kind() { - ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did()), - _ => false, - }, + ty::Ref(_, ref_ty, _) => is_type_diagnostic_item(cx, *ref_ty, diag_item), _ => false, } } @@ -1378,9 +1375,7 @@ pub fn has_non_owning_mutable_access<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<' /// Check if `ty` is slice-like, i.e., `&[T]`, `[T; N]`, or `Vec`. pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_slice() - || ty.is_array() - || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did())) + ty.is_slice() || ty.is_array() || is_type_diagnostic_item(cx, ty, sym::Vec) } pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option { diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 76d43feee12e..6eccbcdb1228 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -144,11 +144,9 @@ impl<'tcx> Visitor<'tcx> for BindingUsageFinder<'_, 'tcx> { /// Checks if the given expression is a macro call to `todo!()` or `unimplemented!()`. pub fn is_todo_unimplemented_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - root_macro_call_first_node(cx, expr).is_some_and(|macro_call| { - [sym::todo_macro, sym::unimplemented_macro] - .iter() - .any(|&sym| cx.tcx.is_diagnostic_item(sym, macro_call.def_id)) - }) + root_macro_call_first_node(cx, expr) + .and_then(|macro_call| cx.tcx.get_diagnostic_name(macro_call.def_id)) + .is_some_and(|macro_name| matches!(macro_name, sym::todo_macro | sym::unimplemented_macro)) } /// Checks if the given expression is a stub, i.e., a `todo!()` or `unimplemented!()` expression, diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index 5497e77e8ad1..ec2f24a0a6d8 100644 --- a/src/tools/clippy/rust-toolchain.toml +++ b/src/tools/clippy/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-08-22" +channel = "nightly-2025-09-04" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index c4076cbaa77b..6bddcbfd94ce 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -330,7 +330,8 @@ pub fn main() { // Do not run Clippy for Cargo's info queries so that invalid CLIPPY_ARGS are not cached // https://github.com/rust-lang/cargo/issues/14385 - let info_query = has_arg(&orig_args, "-vV") || has_arg(&orig_args, "--print"); + let info_query = has_arg(&orig_args, "-vV") + || arg_value(&orig_args, "--print", |val| val != "crate-root-lint-levels").is_some(); let clippy_enabled = !cap_lints_allow && relevant_package && !info_query; if clippy_enabled { diff --git a/src/tools/clippy/tests/config-consistency.rs b/src/tools/clippy/tests/config-consistency.rs new file mode 100644 index 000000000000..9e7ca26c7d40 --- /dev/null +++ b/src/tools/clippy/tests/config-consistency.rs @@ -0,0 +1,30 @@ +#![feature(rustc_private)] + +// This test checks that all lints defined in `clippy_config::conf` in `#[lints]` +// attributes exist as Clippy lints. +// +// This test is a no-op if run as part of the compiler test suite +// and will always succeed. + +use std::collections::HashSet; + +#[test] +fn config_consistency() { + if option_env!("RUSTC_TEST_SUITE").is_some() { + return; + } + + let lint_names: HashSet = clippy_lints::declared_lints::LINTS + .iter() + .map(|lint_info| lint_info.lint.name.strip_prefix("clippy::").unwrap().to_lowercase()) + .collect(); + for conf in clippy_config::get_configuration_metadata() { + for lint in conf.lints { + assert!( + lint_names.contains(*lint), + "Configuration option {} references lint `{lint}` which does not exist", + conf.name + ); + } + } +} diff --git a/src/tools/clippy/tests/no-profile-in-cargo-toml.rs b/src/tools/clippy/tests/no-profile-in-cargo-toml.rs new file mode 100644 index 000000000000..2ad9bfb75dee --- /dev/null +++ b/src/tools/clippy/tests/no-profile-in-cargo-toml.rs @@ -0,0 +1,34 @@ +// Check that we do not have `profile.*` sections in our `Cargo.toml` files, +// as this causes warnings when run from the compiler repository which includes +// Clippy in a workspace. +// +// Those sections can be put into `.cargo/config.toml` which will be read +// when commands are issued from the top-level Clippy directory, outside of +// a workspace. + +use std::fs::File; +use std::io::{self, BufRead as _}; +use walkdir::WalkDir; + +#[test] +fn no_profile_in_cargo_toml() { + // This check could parse `Cargo.toml` using a TOML deserializer, but in practice + // profile sections would be added at the beginning of a line as `[profile.*]`, so + // keep it fast and simple. + for entry in WalkDir::new(".") + .into_iter() + .filter_map(Result::ok) + .filter(|e| e.file_name().to_str() == Some("Cargo.toml")) + { + for line in io::BufReader::new(File::open(entry.path()).unwrap()) + .lines() + .map(Result::unwrap) + { + if line.starts_with("[profile.") { + eprintln!("Profile section `{line}` found in file `{}`.", entry.path().display()); + eprintln!("Use `.cargo/config.toml` for profiles specific to the standalone Clippy repository."); + panic!("Profile section found in `Cargo.toml`"); + } + } + } +} diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr index f03a745963e0..e9d53c64dd9b 100644 --- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr +++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr @@ -4,7 +4,7 @@ error: use of a disallowed method `rustc_lint::context::LintContext::span_lint` LL | cx.span_lint(lint, span, |lint| { | ^^^^^^^^^ | - = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead + = note: this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead note: the lint level is defined here --> tests/ui-internal/disallow_span_lint.rs:2:9 | @@ -17,7 +17,7 @@ error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_ LL | tcx.node_span_lint(lint, hir_id, span, |lint| { | ^^^^^^^^^^^^^^ | - = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead + = note: this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui-toml/excessive_precision/clippy.toml b/src/tools/clippy/tests/ui-toml/excessive_precision/clippy.toml new file mode 100644 index 000000000000..c7fc230dcb31 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/excessive_precision/clippy.toml @@ -0,0 +1 @@ +const-literal-digits-threshold = 20 diff --git a/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.fixed b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.fixed new file mode 100644 index 000000000000..577bbff2957f --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.fixed @@ -0,0 +1,38 @@ +#![warn(clippy::excessive_precision)] +#![allow( + dead_code, + overflowing_literals, + unused_variables, + clippy::print_literal, + clippy::useless_vec +)] + +fn main() { + // Overly specified constants + let _: f32 = 1.012_345_7; + //~^ excessive_precision + let _: f64 = 1.012_345_678_901_234_6; + //~^ excessive_precision + const _: f32 = 1.012345678901234567890; + const _: f64 = 1.012345678901234567890; + + static STATIC1: f32 = 1.012345678901234567890; + static STATIC2: f64 = 1.012345678901234567890; + + static mut STATIC_MUT1: f32 = 1.012345678901234567890; + static mut STATIC_MUT2: f64 = 1.012345678901234567890; +} + +trait ExcessivelyPreciseTrait { + // Overly specified constants + const GOOD1: f32 = 1.012345678901234567890; + const GOOD2: f64 = 1.012345678901234567890; +} + +struct ExcessivelyPreciseStruct; + +impl ExcessivelyPreciseStruct { + // Overly specified constants + const GOOD1: f32 = 1.012345678901234567890; + const GOOD2: f64 = 1.012345678901234567890; +} diff --git a/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.rs b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.rs new file mode 100644 index 000000000000..121448ed540d --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.rs @@ -0,0 +1,38 @@ +#![warn(clippy::excessive_precision)] +#![allow( + dead_code, + overflowing_literals, + unused_variables, + clippy::print_literal, + clippy::useless_vec +)] + +fn main() { + // Overly specified constants + let _: f32 = 1.012345678901234567890; + //~^ excessive_precision + let _: f64 = 1.012345678901234567890; + //~^ excessive_precision + const _: f32 = 1.012345678901234567890; + const _: f64 = 1.012345678901234567890; + + static STATIC1: f32 = 1.012345678901234567890; + static STATIC2: f64 = 1.012345678901234567890; + + static mut STATIC_MUT1: f32 = 1.012345678901234567890; + static mut STATIC_MUT2: f64 = 1.012345678901234567890; +} + +trait ExcessivelyPreciseTrait { + // Overly specified constants + const GOOD1: f32 = 1.012345678901234567890; + const GOOD2: f64 = 1.012345678901234567890; +} + +struct ExcessivelyPreciseStruct; + +impl ExcessivelyPreciseStruct { + // Overly specified constants + const GOOD1: f32 = 1.012345678901234567890; + const GOOD2: f64 = 1.012345678901234567890; +} diff --git a/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.stderr b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.stderr new file mode 100644 index 000000000000..65d33eddef17 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/excessive_precision/excessive_precision.stderr @@ -0,0 +1,38 @@ +error: float has excessive precision + --> tests/ui-toml/excessive_precision/excessive_precision.rs:12:18 + | +LL | let _: f32 = 1.012345678901234567890; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: consider making it a `const` item + --> tests/ui-toml/excessive_precision/excessive_precision.rs:12:5 + | +LL | let _: f32 = 1.012345678901234567890; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::excessive-precision` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::excessive_precision)]` +help: consider changing the type or truncating it to + | +LL - let _: f32 = 1.012345678901234567890; +LL + let _: f32 = 1.012_345_7; + | + +error: float has excessive precision + --> tests/ui-toml/excessive_precision/excessive_precision.rs:14:18 + | +LL | let _: f64 = 1.012345678901234567890; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: consider making it a `const` item + --> tests/ui-toml/excessive_precision/excessive_precision.rs:14:5 + | +LL | let _: f64 = 1.012345678901234567890; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider changing the type or truncating it to + | +LL - let _: f64 = 1.012345678901234567890; +LL + let _: f64 = 1.012_345_678_901_234_6; + | + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 6ee77ebd8ece..20aeb4bb8498 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -35,6 +35,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect check-inconsistent-struct-field-initializers check-private-items cognitive-complexity-threshold + const-literal-digits-threshold disallowed-macros disallowed-methods disallowed-names @@ -129,6 +130,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect check-inconsistent-struct-field-initializers check-private-items cognitive-complexity-threshold + const-literal-digits-threshold disallowed-macros disallowed-methods disallowed-names @@ -223,6 +225,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni check-inconsistent-struct-field-initializers check-private-items cognitive-complexity-threshold + const-literal-digits-threshold disallowed-macros disallowed-methods disallowed-names diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed index 09c1a8d0ed1d..b2b7318c113f 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed @@ -82,9 +82,18 @@ fn main() { assert!(r.is_err()); } -#[allow(dead_code)] fn issue9450() { let res: Result = Ok(1); res.unwrap_err(); //~^ assertions_on_result_states } + +fn issue9916(res: Result) { + let a = 0; + match a { + 0 => {}, + 1 => { res.unwrap(); }, + //~^ assertions_on_result_states + _ => todo!(), + } +} diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.rs b/src/tools/clippy/tests/ui/assertions_on_result_states.rs index c63c2502b537..33f1485326b3 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.rs +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.rs @@ -82,9 +82,18 @@ fn main() { assert!(r.is_err()); } -#[allow(dead_code)] fn issue9450() { let res: Result = Ok(1); assert!(res.is_err()) //~^ assertions_on_result_states } + +fn issue9916(res: Result) { + let a = 0; + match a { + 0 => {}, + 1 => assert!(res.is_ok()), + //~^ assertions_on_result_states + _ => todo!(), + } +} diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr index 3bf811588c69..826f049555ca 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr @@ -38,10 +38,16 @@ LL | assert!(r.is_err()); | ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()` error: called `assert!` with `Result::is_err` - --> tests/ui/assertions_on_result_states.rs:88:5 + --> tests/ui/assertions_on_result_states.rs:87:5 | LL | assert!(res.is_err()) | ^^^^^^^^^^^^^^^^^^^^^ help: replace with: `res.unwrap_err();` -error: aborting due to 7 previous errors +error: called `assert!` with `Result::is_ok` + --> tests/ui/assertions_on_result_states.rs:95:14 + | +LL | 1 => assert!(res.is_ok()), + | ^^^^^^^^^^^^^^^^^^^^ help: replace with: `{ res.unwrap(); }` + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed index 3754b9dfe744..2046d089d6a6 100644 --- a/src/tools/clippy/tests/ui/assign_ops.fixed +++ b/src/tools/clippy/tests/ui/assign_ops.fixed @@ -1,8 +1,9 @@ #![allow(clippy::useless_vec)] #![warn(clippy::assign_op_pattern)] -#![feature(const_trait_impl, const_ops)] +#![feature(const_ops)] +#![feature(const_trait_impl)] -use core::num::Wrapping; +use std::num::Wrapping; use std::ops::{Mul, MulAssign}; fn main() { @@ -82,6 +83,18 @@ mod issue14871 { pub trait Number: Copy + Add + AddAssign { const ZERO: Self; const ONE: Self; + + fn non_constant(value: usize) -> Self { + let mut res = Self::ZERO; + let mut count = 0; + while count < value { + res += Self::ONE; + //~^ assign_op_pattern + count += 1; + //~^ assign_op_pattern + } + res + } } #[rustfmt::skip] // rustfmt doesn't understand the order of pub const on traits (yet) @@ -91,7 +104,7 @@ mod issue14871 { impl const NumberConstants for T where - T: Number + [const] core::ops::Add, + T: Number + [const] std::ops::Add, { fn constant(value: usize) -> Self { let mut res = Self::ZERO; @@ -99,8 +112,28 @@ mod issue14871 { while count < value { res = res + Self::ONE; count += 1; + //~^ assign_op_pattern } res } } + + pub struct S; + + impl const std::ops::Add for S { + type Output = S; + fn add(self, _rhs: S) -> S { + S + } + } + + impl const std::ops::AddAssign for S { + fn add_assign(&mut self, rhs: S) {} + } + + const fn do_add() { + let mut s = S; + s += S; + //~^ assign_op_pattern + } } diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs index 0b878d4f490b..f83a40f55473 100644 --- a/src/tools/clippy/tests/ui/assign_ops.rs +++ b/src/tools/clippy/tests/ui/assign_ops.rs @@ -1,8 +1,9 @@ #![allow(clippy::useless_vec)] #![warn(clippy::assign_op_pattern)] -#![feature(const_trait_impl, const_ops)] +#![feature(const_ops)] +#![feature(const_trait_impl)] -use core::num::Wrapping; +use std::num::Wrapping; use std::ops::{Mul, MulAssign}; fn main() { @@ -82,6 +83,18 @@ mod issue14871 { pub trait Number: Copy + Add + AddAssign { const ZERO: Self; const ONE: Self; + + fn non_constant(value: usize) -> Self { + let mut res = Self::ZERO; + let mut count = 0; + while count < value { + res = res + Self::ONE; + //~^ assign_op_pattern + count = count + 1; + //~^ assign_op_pattern + } + res + } } #[rustfmt::skip] // rustfmt doesn't understand the order of pub const on traits (yet) @@ -91,16 +104,36 @@ mod issue14871 { impl const NumberConstants for T where - T: Number + [const] core::ops::Add, + T: Number + [const] std::ops::Add, { fn constant(value: usize) -> Self { let mut res = Self::ZERO; let mut count = 0; while count < value { res = res + Self::ONE; - count += 1; + count = count + 1; + //~^ assign_op_pattern } res } } + + pub struct S; + + impl const std::ops::Add for S { + type Output = S; + fn add(self, _rhs: S) -> S { + S + } + } + + impl const std::ops::AddAssign for S { + fn add_assign(&mut self, rhs: S) {} + } + + const fn do_add() { + let mut s = S; + s = s + S; + //~^ assign_op_pattern + } } diff --git a/src/tools/clippy/tests/ui/assign_ops.stderr b/src/tools/clippy/tests/ui/assign_ops.stderr index c5e698b3ee11..a4fca04893c4 100644 --- a/src/tools/clippy/tests/ui/assign_ops.stderr +++ b/src/tools/clippy/tests/ui/assign_ops.stderr @@ -1,5 +1,5 @@ error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:10:5 + --> tests/ui/assign_ops.rs:11:5 | LL | a = a + 1; | ^^^^^^^^^ help: replace it with: `a += 1` @@ -8,70 +8,94 @@ LL | a = a + 1; = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:12:5 + --> tests/ui/assign_ops.rs:13:5 | LL | a = 1 + a; | ^^^^^^^^^ help: replace it with: `a += 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:14:5 + --> tests/ui/assign_ops.rs:15:5 | LL | a = a - 1; | ^^^^^^^^^ help: replace it with: `a -= 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:16:5 + --> tests/ui/assign_ops.rs:17:5 | LL | a = a * 99; | ^^^^^^^^^^ help: replace it with: `a *= 99` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:18:5 + --> tests/ui/assign_ops.rs:19:5 | LL | a = 42 * a; | ^^^^^^^^^^ help: replace it with: `a *= 42` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:20:5 + --> tests/ui/assign_ops.rs:21:5 | LL | a = a / 2; | ^^^^^^^^^ help: replace it with: `a /= 2` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:22:5 + --> tests/ui/assign_ops.rs:23:5 | LL | a = a % 5; | ^^^^^^^^^ help: replace it with: `a %= 5` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:24:5 + --> tests/ui/assign_ops.rs:25:5 | LL | a = a & 1; | ^^^^^^^^^ help: replace it with: `a &= 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:31:5 + --> tests/ui/assign_ops.rs:32:5 | LL | s = s + "bla"; | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:36:5 + --> tests/ui/assign_ops.rs:37:5 | LL | a = a + Wrapping(1u32); | ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a += Wrapping(1u32)` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:39:5 + --> tests/ui/assign_ops.rs:40:5 | LL | v[0] = v[0] + v[1]; | ^^^^^^^^^^^^^^^^^^ help: replace it with: `v[0] += v[1]` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:52:5 + --> tests/ui/assign_ops.rs:53:5 | LL | buf = buf + cows.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()` -error: aborting due to 12 previous errors +error: manual implementation of an assign operation + --> tests/ui/assign_ops.rs:91:17 + | +LL | res = res + Self::ONE; + | ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `res += Self::ONE` + +error: manual implementation of an assign operation + --> tests/ui/assign_ops.rs:93:17 + | +LL | count = count + 1; + | ^^^^^^^^^^^^^^^^^ help: replace it with: `count += 1` + +error: manual implementation of an assign operation + --> tests/ui/assign_ops.rs:114:17 + | +LL | count = count + 1; + | ^^^^^^^^^^^^^^^^^ help: replace it with: `count += 1` + +error: manual implementation of an assign operation + --> tests/ui/assign_ops.rs:136:9 + | +LL | s = s + S; + | ^^^^^^^^^ help: replace it with: `s += S` + +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/async_yields_async.fixed b/src/tools/clippy/tests/ui/async_yields_async.fixed index 93c573d30863..bd1b31f74ee9 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.fixed +++ b/src/tools/clippy/tests/ui/async_yields_async.fixed @@ -80,3 +80,42 @@ fn check_expect_suppression() { } }; } + +#[allow(clippy::let_underscore_future)] +fn issue15552() { + async fn bar(i: i32) {} + + macro_rules! call_bar { + () => { + async { bar(5).await } + }; + ($e:expr) => { + bar($e) + }; + } + let x = async { call_bar!(5).await }; + //~^ async_yields_async + let y = async { call_bar!().await }; + //~^ async_yields_async + //~| async_yields_async + + use std::future::{Future, Ready}; + use std::ops::Add; + use std::pin::Pin; + use std::task::{Context, Poll}; + struct CustomFutureType; + impl Add for CustomFutureType { + type Output = Self; + fn add(self, other: Self) -> Self { + self + } + } + impl Future for CustomFutureType { + type Output = (); + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + Poll::Ready(()) + } + } + let _ = async { (CustomFutureType + CustomFutureType).await }; + //~^ async_yields_async +} diff --git a/src/tools/clippy/tests/ui/async_yields_async.rs b/src/tools/clippy/tests/ui/async_yields_async.rs index 166d522e1c04..605d2734157c 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.rs +++ b/src/tools/clippy/tests/ui/async_yields_async.rs @@ -80,3 +80,42 @@ fn check_expect_suppression() { } }; } + +#[allow(clippy::let_underscore_future)] +fn issue15552() { + async fn bar(i: i32) {} + + macro_rules! call_bar { + () => { + async { bar(5) } + }; + ($e:expr) => { + bar($e) + }; + } + let x = async { call_bar!(5) }; + //~^ async_yields_async + let y = async { call_bar!() }; + //~^ async_yields_async + //~| async_yields_async + + use std::future::{Future, Ready}; + use std::ops::Add; + use std::pin::Pin; + use std::task::{Context, Poll}; + struct CustomFutureType; + impl Add for CustomFutureType { + type Output = Self; + fn add(self, other: Self) -> Self { + self + } + } + impl Future for CustomFutureType { + type Output = (); + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + Poll::Ready(()) + } + } + let _ = async { CustomFutureType + CustomFutureType }; + //~^ async_yields_async +} diff --git a/src/tools/clippy/tests/ui/async_yields_async.stderr b/src/tools/clippy/tests/ui/async_yields_async.stderr index 17a35076fa3f..3041cf657893 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.stderr +++ b/src/tools/clippy/tests/ui/async_yields_async.stderr @@ -89,5 +89,50 @@ LL | | CustomFutureType LL | | }; | |_____- outer async construct -error: aborting due to 6 previous errors +error: an async construct yields a type which is itself awaitable + --> tests/ui/async_yields_async.rs:96:21 + | +LL | let x = async { call_bar!(5) }; + | --^^^^^^^^^^^^-- + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `call_bar!(5).await` + | outer async construct + +error: an async construct yields a type which is itself awaitable + --> tests/ui/async_yields_async.rs:98:21 + | +LL | let y = async { call_bar!() }; + | --^^^^^^^^^^^-- + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `call_bar!().await` + | outer async construct + +error: an async construct yields a type which is itself awaitable + --> tests/ui/async_yields_async.rs:90:21 + | +LL | async { bar(5) } + | --^^^^^^-- + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `bar(5).await` + | outer async construct +... +LL | let y = async { call_bar!() }; + | ----------- in this macro invocation + | + = note: this error originates in the macro `call_bar` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: an async construct yields a type which is itself awaitable + --> tests/ui/async_yields_async.rs:119:21 + | +LL | let _ = async { CustomFutureType + CustomFutureType }; + | --^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `(CustomFutureType + CustomFutureType).await` + | outer async construct + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/bool_comparison.fixed b/src/tools/clippy/tests/ui/bool_comparison.fixed index 166abbe549c3..b0b60104c0b9 100644 --- a/src/tools/clippy/tests/ui/bool_comparison.fixed +++ b/src/tools/clippy/tests/ui/bool_comparison.fixed @@ -1,97 +1,41 @@ #![allow(non_local_definitions, clippy::needless_if)] #![warn(clippy::bool_comparison)] -#![allow(clippy::non_canonical_partial_ord_impl, clippy::nonminimal_bool)] +#![allow(clippy::non_canonical_partial_ord_impl)] fn main() { let x = true; - if x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if !x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if !x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if !x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if !x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if !x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if !x { - //~^ bool_comparison - "yes" - } else { - "no" - }; + let _ = if x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if !x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if !x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if !x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if !x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if !x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if !x { "yes" } else { "no" }; + //~^ bool_comparison + let y = true; - if !x & y { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x & !y { - //~^ bool_comparison - "yes" - } else { - "no" - }; + let _ = if !x & y { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x & !y { "yes" } else { "no" }; + //~^ bool_comparison } -#[allow(dead_code)] fn issue3703() { struct Foo; impl PartialEq for Foo { @@ -127,26 +71,6 @@ fn issue3703() { if false < Foo {} } -#[allow(dead_code)] -fn issue4983() { - let a = true; - let b = false; - - if a != b {}; - //~^ bool_comparison - if a != b {}; - //~^ bool_comparison - if a == b {}; - if !a == !b {}; - - if b != a {}; - //~^ bool_comparison - if b != a {}; - //~^ bool_comparison - if b == a {}; - if !b == !a {}; -} - macro_rules! m { ($func:ident) => { $func() @@ -157,7 +81,6 @@ fn func() -> bool { true } -#[allow(dead_code)] fn issue3973() { // ok, don't lint on `cfg` invocation if false == cfg!(feature = "debugging") {} @@ -196,6 +119,34 @@ fn issue9907() { //~^ bool_comparison // This is not part of the issue, but an unexpected found when fixing the issue, // the provided span was inside of macro rather than the macro callsite. - let _ = ((1 < 2) != m!(func)) as usize; + let _ = ((1 < 2) & !m!(func)) as usize; //~^ bool_comparison } + +#[allow(clippy::nonminimal_bool)] +fn issue15367() { + let a = true; + let b = false; + + // these cases are handled by `nonminimal_bool`, so don't double-lint + if a == !b {}; + if !a == b {}; + if b == !a {}; + if !b == a {}; +} + +fn issue15497() { + fn func() -> bool { + true + } + + fn foo(x: bool) -> bool { + x & !m!(func) + //~^ bool_comparison + } + + fn bar(x: bool) -> bool { + !x & m!(func) + //~^ bool_comparison + } +} diff --git a/src/tools/clippy/tests/ui/bool_comparison.rs b/src/tools/clippy/tests/ui/bool_comparison.rs index 7265c2b4c5a6..1b1108d6ce50 100644 --- a/src/tools/clippy/tests/ui/bool_comparison.rs +++ b/src/tools/clippy/tests/ui/bool_comparison.rs @@ -1,97 +1,41 @@ #![allow(non_local_definitions, clippy::needless_if)] #![warn(clippy::bool_comparison)] -#![allow(clippy::non_canonical_partial_ord_impl, clippy::nonminimal_bool)] +#![allow(clippy::non_canonical_partial_ord_impl)] fn main() { let x = true; - if x == true { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x == false { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if true == x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if false == x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x != true { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x != false { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if true != x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if false != x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x < true { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if false < x { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x > false { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if true > x { - //~^ bool_comparison - "yes" - } else { - "no" - }; + let _ = if x == true { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x == false { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if true == x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if false == x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x != true { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x != false { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if true != x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if false != x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x < true { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if false < x { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x > false { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if true > x { "yes" } else { "no" }; + //~^ bool_comparison + let y = true; - if x < y { - //~^ bool_comparison - "yes" - } else { - "no" - }; - if x > y { - //~^ bool_comparison - "yes" - } else { - "no" - }; + let _ = if x < y { "yes" } else { "no" }; + //~^ bool_comparison + let _ = if x > y { "yes" } else { "no" }; + //~^ bool_comparison } -#[allow(dead_code)] fn issue3703() { struct Foo; impl PartialEq for Foo { @@ -127,26 +71,6 @@ fn issue3703() { if false < Foo {} } -#[allow(dead_code)] -fn issue4983() { - let a = true; - let b = false; - - if a == !b {}; - //~^ bool_comparison - if !a == b {}; - //~^ bool_comparison - if a == b {}; - if !a == !b {}; - - if b == !a {}; - //~^ bool_comparison - if !b == a {}; - //~^ bool_comparison - if b == a {}; - if !b == !a {}; -} - macro_rules! m { ($func:ident) => { $func() @@ -157,7 +81,6 @@ fn func() -> bool { true } -#[allow(dead_code)] fn issue3973() { // ok, don't lint on `cfg` invocation if false == cfg!(feature = "debugging") {} @@ -196,6 +119,34 @@ fn issue9907() { //~^ bool_comparison // This is not part of the issue, but an unexpected found when fixing the issue, // the provided span was inside of macro rather than the macro callsite. - let _ = ((1 < 2) == !m!(func)) as usize; + let _ = ((1 < 2) > m!(func)) as usize; //~^ bool_comparison } + +#[allow(clippy::nonminimal_bool)] +fn issue15367() { + let a = true; + let b = false; + + // these cases are handled by `nonminimal_bool`, so don't double-lint + if a == !b {}; + if !a == b {}; + if b == !a {}; + if !b == a {}; +} + +fn issue15497() { + fn func() -> bool { + true + } + + fn foo(x: bool) -> bool { + x > m!(func) + //~^ bool_comparison + } + + fn bar(x: bool) -> bool { + x < m!(func) + //~^ bool_comparison + } +} diff --git a/src/tools/clippy/tests/ui/bool_comparison.stderr b/src/tools/clippy/tests/ui/bool_comparison.stderr index ddbb9ff78edb..98881a2d20fd 100644 --- a/src/tools/clippy/tests/ui/bool_comparison.stderr +++ b/src/tools/clippy/tests/ui/bool_comparison.stderr @@ -1,155 +1,143 @@ error: equality checks against true are unnecessary - --> tests/ui/bool_comparison.rs:7:8 + --> tests/ui/bool_comparison.rs:7:16 | -LL | if x == true { - | ^^^^^^^^^ help: try simplifying it as shown: `x` +LL | let _ = if x == true { "yes" } else { "no" }; + | ^^^^^^^^^ help: try: `x` | = note: `-D clippy::bool-comparison` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:13:8 + --> tests/ui/bool_comparison.rs:9:16 | -LL | if x == false { - | ^^^^^^^^^^ help: try simplifying it as shown: `!x` +LL | let _ = if x == false { "yes" } else { "no" }; + | ^^^^^^^^^^ help: try: `!x` error: equality checks against true are unnecessary - --> tests/ui/bool_comparison.rs:19:8 + --> tests/ui/bool_comparison.rs:11:16 | -LL | if true == x { - | ^^^^^^^^^ help: try simplifying it as shown: `x` +LL | let _ = if true == x { "yes" } else { "no" }; + | ^^^^^^^^^ help: try: `x` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:25:8 + --> tests/ui/bool_comparison.rs:13:16 | -LL | if false == x { - | ^^^^^^^^^^ help: try simplifying it as shown: `!x` +LL | let _ = if false == x { "yes" } else { "no" }; + | ^^^^^^^^^^ help: try: `!x` error: inequality checks against true can be replaced by a negation - --> tests/ui/bool_comparison.rs:31:8 + --> tests/ui/bool_comparison.rs:15:16 | -LL | if x != true { - | ^^^^^^^^^ help: try simplifying it as shown: `!x` +LL | let _ = if x != true { "yes" } else { "no" }; + | ^^^^^^^^^ help: try: `!x` error: inequality checks against false are unnecessary - --> tests/ui/bool_comparison.rs:37:8 + --> tests/ui/bool_comparison.rs:17:16 | -LL | if x != false { - | ^^^^^^^^^^ help: try simplifying it as shown: `x` +LL | let _ = if x != false { "yes" } else { "no" }; + | ^^^^^^^^^^ help: try: `x` error: inequality checks against true can be replaced by a negation - --> tests/ui/bool_comparison.rs:43:8 + --> tests/ui/bool_comparison.rs:19:16 | -LL | if true != x { - | ^^^^^^^^^ help: try simplifying it as shown: `!x` +LL | let _ = if true != x { "yes" } else { "no" }; + | ^^^^^^^^^ help: try: `!x` error: inequality checks against false are unnecessary - --> tests/ui/bool_comparison.rs:49:8 + --> tests/ui/bool_comparison.rs:21:16 | -LL | if false != x { - | ^^^^^^^^^^ help: try simplifying it as shown: `x` +LL | let _ = if false != x { "yes" } else { "no" }; + | ^^^^^^^^^^ help: try: `x` error: less than comparison against true can be replaced by a negation - --> tests/ui/bool_comparison.rs:55:8 + --> tests/ui/bool_comparison.rs:23:16 | -LL | if x < true { - | ^^^^^^^^ help: try simplifying it as shown: `!x` +LL | let _ = if x < true { "yes" } else { "no" }; + | ^^^^^^^^ help: try: `!x` error: greater than checks against false are unnecessary - --> tests/ui/bool_comparison.rs:61:8 + --> tests/ui/bool_comparison.rs:25:16 | -LL | if false < x { - | ^^^^^^^^^ help: try simplifying it as shown: `x` +LL | let _ = if false < x { "yes" } else { "no" }; + | ^^^^^^^^^ help: try: `x` error: greater than checks against false are unnecessary - --> tests/ui/bool_comparison.rs:67:8 + --> tests/ui/bool_comparison.rs:27:16 | -LL | if x > false { - | ^^^^^^^^^ help: try simplifying it as shown: `x` +LL | let _ = if x > false { "yes" } else { "no" }; + | ^^^^^^^^^ help: try: `x` error: less than comparison against true can be replaced by a negation - --> tests/ui/bool_comparison.rs:73:8 + --> tests/ui/bool_comparison.rs:29:16 | -LL | if true > x { - | ^^^^^^^^ help: try simplifying it as shown: `!x` +LL | let _ = if true > x { "yes" } else { "no" }; + | ^^^^^^^^ help: try: `!x` error: order comparisons between booleans can be simplified - --> tests/ui/bool_comparison.rs:80:8 + --> tests/ui/bool_comparison.rs:33:16 | -LL | if x < y { - | ^^^^^ help: try simplifying it as shown: `!x & y` +LL | let _ = if x < y { "yes" } else { "no" }; + | ^^^^^ help: try: `!x & y` error: order comparisons between booleans can be simplified - --> tests/ui/bool_comparison.rs:86:8 + --> tests/ui/bool_comparison.rs:35:16 | -LL | if x > y { - | ^^^^^ help: try simplifying it as shown: `x & !y` - -error: this comparison might be written more concisely - --> tests/ui/bool_comparison.rs:135:8 - | -LL | if a == !b {}; - | ^^^^^^^ help: try simplifying it as shown: `a != b` - -error: this comparison might be written more concisely - --> tests/ui/bool_comparison.rs:137:8 - | -LL | if !a == b {}; - | ^^^^^^^ help: try simplifying it as shown: `a != b` - -error: this comparison might be written more concisely - --> tests/ui/bool_comparison.rs:142:8 - | -LL | if b == !a {}; - | ^^^^^^^ help: try simplifying it as shown: `b != a` - -error: this comparison might be written more concisely - --> tests/ui/bool_comparison.rs:144:8 - | -LL | if !b == a {}; - | ^^^^^^^ help: try simplifying it as shown: `b != a` +LL | let _ = if x > y { "yes" } else { "no" }; + | ^^^^^ help: try: `x & !y` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:169:8 + --> tests/ui/bool_comparison.rs:92:8 | LL | if false == m!(func) {} - | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` + | ^^^^^^^^^^^^^^^^^ help: try: `!m!(func)` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:171:8 + --> tests/ui/bool_comparison.rs:94:8 | LL | if m!(func) == false {} - | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` + | ^^^^^^^^^^^^^^^^^ help: try: `!m!(func)` error: equality checks against true are unnecessary - --> tests/ui/bool_comparison.rs:173:8 + --> tests/ui/bool_comparison.rs:96:8 | LL | if true == m!(func) {} - | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)` + | ^^^^^^^^^^^^^^^^ help: try: `m!(func)` error: equality checks against true are unnecessary - --> tests/ui/bool_comparison.rs:175:8 + --> tests/ui/bool_comparison.rs:98:8 | LL | if m!(func) == true {} - | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)` + | ^^^^^^^^^^^^^^^^ help: try: `m!(func)` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:193:14 + --> tests/ui/bool_comparison.rs:116:14 | LL | let _ = ((1 < 2) == false) as usize; - | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `1 >= 2` + | ^^^^^^^^^^^^^^^^ help: try: `1 >= 2` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:195:14 + --> tests/ui/bool_comparison.rs:118:14 | LL | let _ = (false == m!(func)) as usize; - | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` + | ^^^^^^^^^^^^^^^^^ help: try: `!m!(func)` -error: this comparison might be written more concisely - --> tests/ui/bool_comparison.rs:199:14 +error: order comparisons between booleans can be simplified + --> tests/ui/bool_comparison.rs:122:14 | -LL | let _ = ((1 < 2) == !m!(func)) as usize; - | ^^^^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `(1 < 2) != m!(func)` +LL | let _ = ((1 < 2) > m!(func)) as usize; + | ^^^^^^^^^^^^^^^^^^ help: try: `(1 < 2) & !m!(func)` -error: aborting due to 25 previous errors +error: order comparisons between booleans can be simplified + --> tests/ui/bool_comparison.rs:144:9 + | +LL | x > m!(func) + | ^^^^^^^^^^^^ help: try: `x & !m!(func)` + +error: order comparisons between booleans can be simplified + --> tests/ui/bool_comparison.rs:149:9 + | +LL | x < m!(func) + | ^^^^^^^^^^^^ help: try: `!x & m!(func)` + +error: aborting due to 23 previous errors diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed index bddcb0ebf64e..3c1cf8845957 100644 --- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed @@ -1,30 +1,53 @@ #![warn(clippy::cast_slice_from_raw_parts)] -#[allow(unused_imports, unused_unsafe)] +const fn require_raw_slice_ptr(_: *const [T]) {} + fn main() { let mut vec = vec![0u8; 1]; let ptr: *const u8 = vec.as_ptr(); let mptr = vec.as_mut_ptr(); - let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) }; + let _: *const [u8] = unsafe { std::ptr::slice_from_raw_parts(ptr, 1) }; //~^ cast_slice_from_raw_parts - let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) }; + let _: *const [u8] = unsafe { std::ptr::slice_from_raw_parts_mut(mptr, 1) }; //~^ cast_slice_from_raw_parts - let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, 1); //~^ cast_slice_from_raw_parts { use core::slice; - let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, 1); //~^ cast_slice_from_raw_parts use slice as one; - let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, 1); //~^ cast_slice_from_raw_parts } { use std::slice; - let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, 1); //~^ cast_slice_from_raw_parts use slice as one; - let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, 1); //~^ cast_slice_from_raw_parts } + + // implicit cast + { + let _: *const [u8] = unsafe { std::ptr::slice_from_raw_parts(ptr, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { std::ptr::slice_from_raw_parts_mut(mptr, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { std::ptr::slice_from_raw_parts(ptr, 1) }); + //~^ cast_slice_from_raw_parts + } + + // implicit cast in const context + const { + const PTR: *const u8 = std::ptr::null(); + const MPTR: *mut u8 = std::ptr::null_mut(); + let _: *const [u8] = unsafe { std::ptr::slice_from_raw_parts(PTR, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { std::ptr::slice_from_raw_parts_mut(MPTR, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { std::ptr::slice_from_raw_parts(PTR, 1) }); + //~^ cast_slice_from_raw_parts + }; } diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs index 0a1eb276d5e9..8f57b1f96192 100644 --- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs @@ -1,6 +1,7 @@ #![warn(clippy::cast_slice_from_raw_parts)] -#[allow(unused_imports, unused_unsafe)] +const fn require_raw_slice_ptr(_: *const [T]) {} + fn main() { let mut vec = vec![0u8; 1]; let ptr: *const u8 = vec.as_ptr(); @@ -27,4 +28,26 @@ fn main() { let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; //~^ cast_slice_from_raw_parts } + + // implicit cast + { + let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(ptr, 1) }); + //~^ cast_slice_from_raw_parts + } + + // implicit cast in const context + const { + const PTR: *const u8 = std::ptr::null(); + const MPTR: *mut u8 = std::ptr::null_mut(); + let _: *const [u8] = unsafe { std::slice::from_raw_parts(PTR, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(MPTR, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(PTR, 1) }); + //~^ cast_slice_from_raw_parts + }; } diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr index 60794a988db7..328dbafbafe7 100644 --- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr @@ -1,47 +1,83 @@ error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:8:35 + --> tests/ui/cast_raw_slice_pointer_cast.rs:9:35 | LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)` | = note: `-D clippy::cast-slice-from-raw-parts` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_slice_from_raw_parts)]` error: casting the result of `from_raw_parts_mut` to *mut [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:10:35 + --> tests/ui/cast_raw_slice_pointer_cast.rs:11:35 | LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts_mut(mptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:12:26 + --> tests/ui/cast_raw_slice_pointer_cast.rs:13:26 | LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:16:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:17:30 | LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:19:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:20:30 | LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:24:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:25:30 | LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:27:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:28:30 | LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::ptr::slice_from_raw_parts(ptr, 1)` -error: aborting due to 7 previous errors +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:34:39 + | +LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(ptr, 1)` + +error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:36:37 + | +LL | let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts_mut(mptr, 1)` + +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:38:40 + | +LL | require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(ptr, 1) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(ptr, 1)` + +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:46:39 + | +LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(PTR, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(PTR, 1)` + +error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:48:37 + | +LL | let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(MPTR, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts_mut(MPTR, 1)` + +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:50:40 + | +LL | require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(PTR, 1) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(PTR, 1)` + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.fixed b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.fixed new file mode 100644 index 000000000000..f71fb8d863c6 --- /dev/null +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.fixed @@ -0,0 +1,55 @@ +#![warn(clippy::cast_slice_from_raw_parts)] +#![no_std] +#![crate_type = "lib"] + +const fn require_raw_slice_ptr(_: *const [T]) {} + +fn main() { + let mut arr = [0u8; 1]; + let ptr: *const u8 = arr.as_ptr(); + let mptr = arr.as_mut_ptr(); + let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) }; + //~^ cast_slice_from_raw_parts + let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) }; + //~^ cast_slice_from_raw_parts + let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + //~^ cast_slice_from_raw_parts + { + use core::slice; + let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + //~^ cast_slice_from_raw_parts + use slice as one; + let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + //~^ cast_slice_from_raw_parts + } + { + use core::slice; + let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + //~^ cast_slice_from_raw_parts + use slice as one; + let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + //~^ cast_slice_from_raw_parts + } + + // implicit cast + { + let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { core::ptr::slice_from_raw_parts(ptr, 1) }); + //~^ cast_slice_from_raw_parts + } + + // implicit cast in const context + const { + const PTR: *const u8 = core::ptr::null(); + const MPTR: *mut u8 = core::ptr::null_mut(); + let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(PTR, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(MPTR, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { core::ptr::slice_from_raw_parts(PTR, 1) }); + //~^ cast_slice_from_raw_parts + }; +} diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.rs b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.rs new file mode 100644 index 000000000000..743e44c97dc1 --- /dev/null +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.rs @@ -0,0 +1,55 @@ +#![warn(clippy::cast_slice_from_raw_parts)] +#![no_std] +#![crate_type = "lib"] + +const fn require_raw_slice_ptr(_: *const [T]) {} + +fn main() { + let mut arr = [0u8; 1]; + let ptr: *const u8 = arr.as_ptr(); + let mptr = arr.as_mut_ptr(); + let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) as *const [u8] }; + //~^ cast_slice_from_raw_parts + let _: *const [u8] = unsafe { core::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] }; + //~^ cast_slice_from_raw_parts + let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) } as *const [u8]; + //~^ cast_slice_from_raw_parts + { + use core::slice; + let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; + //~^ cast_slice_from_raw_parts + use slice as one; + let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; + //~^ cast_slice_from_raw_parts + } + { + use core::slice; + let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; + //~^ cast_slice_from_raw_parts + use slice as one; + let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; + //~^ cast_slice_from_raw_parts + } + + // implicit cast + { + let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { core::slice::from_raw_parts_mut(mptr, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { core::slice::from_raw_parts(ptr, 1) }); + //~^ cast_slice_from_raw_parts + } + + // implicit cast in const context + const { + const PTR: *const u8 = core::ptr::null(); + const MPTR: *mut u8 = core::ptr::null_mut(); + let _: *const [u8] = unsafe { core::slice::from_raw_parts(PTR, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { core::slice::from_raw_parts_mut(MPTR, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { core::slice::from_raw_parts(PTR, 1) }); + //~^ cast_slice_from_raw_parts + }; +} diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.stderr b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.stderr new file mode 100644 index 000000000000..5488fbcfa1ce --- /dev/null +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast_no_std.stderr @@ -0,0 +1,83 @@ +error: casting the result of `from_raw_parts` to *const [u8] + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:11:35 + | +LL | let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) as *const [u8] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + | + = note: `-D clippy::cast-slice-from-raw-parts` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::cast_slice_from_raw_parts)]` + +error: casting the result of `from_raw_parts_mut` to *mut [u8] + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:13:35 + | +LL | let _: *const [u8] = unsafe { core::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)` + +error: casting the result of `from_raw_parts` to *const [u8] + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:15:26 + | +LL | let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) } as *const [u8]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: casting the result of `from_raw_parts` to *const [u8] + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:19:30 + | +LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: casting the result of `from_raw_parts` to *const [u8] + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:22:30 + | +LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: casting the result of `from_raw_parts` to *const [u8] + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:27:30 + | +LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: casting the result of `from_raw_parts` to *const [u8] + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:30:30 + | +LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:36:39 + | +LL | let _: *const [u8] = unsafe { core::slice::from_raw_parts(ptr, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]` + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:38:37 + | +LL | let _: *mut [u8] = unsafe { core::slice::from_raw_parts_mut(mptr, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)` + +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:40:40 + | +LL | require_raw_slice_ptr(unsafe { core::slice::from_raw_parts(ptr, 1) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:48:39 + | +LL | let _: *const [u8] = unsafe { core::slice::from_raw_parts(PTR, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(PTR, 1)` + +error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]` + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:50:37 + | +LL | let _: *mut [u8] = unsafe { core::slice::from_raw_parts_mut(MPTR, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts_mut(MPTR, 1)` + +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast_no_std.rs:52:40 + | +LL | require_raw_slice_ptr(unsafe { core::slice::from_raw_parts(PTR, 1) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(PTR, 1)` + +error: aborting due to 13 previous errors + diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs index 71b82040ff62..8931a3aa09c6 100644 --- a/src/tools/clippy/tests/ui/collapsible_match.rs +++ b/src/tools/clippy/tests/ui/collapsible_match.rs @@ -316,6 +316,47 @@ fn lint_emitted_at_right_node(opt: Option>) { }; } +pub fn issue_14155() { + let mut arr = ["a", "b", "c"]; + if let Some(last) = arr.last() { + match *last { + //~^ collapsible_match + "a" | "b" => { + unimplemented!() + }, + _ => (), + } + } + + if let Some(last) = arr.last() { + match &last { + //~^ collapsible_match + &&"a" | &&"b" => { + unimplemented!() + }, + _ => (), + } + } + + if let Some(mut last) = arr.last_mut() { + match &mut last { + //~^ collapsible_match + &mut &mut "a" | &mut &mut "b" => { + unimplemented!() + }, + _ => (), + } + } + + const NULL_PTR: *const &'static str = std::ptr::null(); + if let Some(last) = arr.last() { + match &raw const *last { + NULL_PTR => unimplemented!(), + _ => (), + } + } +} + fn make() -> T { unimplemented!() } diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr index c290d84ec297..14b1c1b187e4 100644 --- a/src/tools/clippy/tests/ui/collapsible_match.stderr +++ b/src/tools/clippy/tests/ui/collapsible_match.stderr @@ -250,5 +250,74 @@ LL | if let Issue9647::A { a: Some(a), .. } = x { LL | if let Some(u) = a { | ^^^^^^^ with this pattern -error: aborting due to 13 previous errors +error: this `match` can be collapsed into the outer `if let` + --> tests/ui/collapsible_match.rs:322:9 + | +LL | / match *last { +LL | | +LL | | "a" | "b" => { +LL | | unimplemented!() +LL | | }, +LL | | _ => (), +LL | | } + | |_________^ + | +help: the outer pattern can be modified to include the inner pattern + --> tests/ui/collapsible_match.rs:321:17 + | +LL | if let Some(last) = arr.last() { + | ^^^^ ---------- use: `arr.last().copied()` + | | + | replace this binding +... +LL | "a" | "b" => { + | ^^^^^^^^^ with this pattern + +error: this `match` can be collapsed into the outer `if let` + --> tests/ui/collapsible_match.rs:332:9 + | +LL | / match &last { +LL | | +LL | | &&"a" | &&"b" => { +LL | | unimplemented!() +LL | | }, +LL | | _ => (), +LL | | } + | |_________^ + | +help: the outer pattern can be modified to include the inner pattern + --> tests/ui/collapsible_match.rs:331:17 + | +LL | if let Some(last) = arr.last() { + | ^^^^ ---------- use: `arr.last().as_ref()` + | | + | replace this binding +... +LL | &&"a" | &&"b" => { + | ^^^^^^^^^^^^^ with this pattern + +error: this `match` can be collapsed into the outer `if let` + --> tests/ui/collapsible_match.rs:342:9 + | +LL | / match &mut last { +LL | | +LL | | &mut &mut "a" | &mut &mut "b" => { +LL | | unimplemented!() +LL | | }, +LL | | _ => (), +LL | | } + | |_________^ + | +help: the outer pattern can be modified to include the inner pattern + --> tests/ui/collapsible_match.rs:341:17 + | +LL | if let Some(mut last) = arr.last_mut() { + | ^^^^^^^^ -------------- use: `arr.last_mut().as_mut()` + | | + | replace this binding +... +LL | &mut &mut "a" | &mut &mut "b" => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ with this pattern + +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/collapsible_match2.stderr b/src/tools/clippy/tests/ui/collapsible_match2.stderr index 7b2730637528..259706709990 100644 --- a/src/tools/clippy/tests/ui/collapsible_match2.stderr +++ b/src/tools/clippy/tests/ui/collapsible_match2.stderr @@ -77,6 +77,8 @@ LL | | }, help: the outer pattern can be modified to include the inner pattern --> tests/ui/collapsible_match2.rs:54:14 | +LL | match Some(&[1]) { + | ---------- use: `Some(&[1]).copied()` LL | Some(s) => match *s { | ^ replace this binding LL | diff --git a/src/tools/clippy/tests/ui/derivable_impls.fixed b/src/tools/clippy/tests/ui/derivable_impls.fixed index 65bfded38835..9f9e4e253c3c 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.fixed +++ b/src/tools/clippy/tests/ui/derivable_impls.fixed @@ -1,4 +1,6 @@ #![allow(dead_code)] +#![feature(const_trait_impl)] +#![feature(const_default)] use std::collections::HashMap; @@ -326,4 +328,40 @@ mod issue11368 { } } +mod issue15493 { + #[derive(Copy, Clone)] + #[repr(transparent)] + struct Foo(u64); + + impl const Default for Foo { + fn default() -> Self { + Self(0) + } + } + + #[derive(Copy, Clone)] + enum Bar { + A, + B, + } + + impl const Default for Bar { + fn default() -> Self { + Bar::A + } + } +} + +mod issue15536 { + #[derive(Copy, Clone)] + #[derive(Default)] + enum Bar { + #[default] + A, + B, + } + + +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/derivable_impls.rs b/src/tools/clippy/tests/ui/derivable_impls.rs index 4826c5497b4a..74a793b9a70e 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.rs +++ b/src/tools/clippy/tests/ui/derivable_impls.rs @@ -1,4 +1,6 @@ #![allow(dead_code)] +#![feature(const_trait_impl)] +#![feature(const_default)] use std::collections::HashMap; @@ -396,4 +398,43 @@ mod issue11368 { } } +mod issue15493 { + #[derive(Copy, Clone)] + #[repr(transparent)] + struct Foo(u64); + + impl const Default for Foo { + fn default() -> Self { + Self(0) + } + } + + #[derive(Copy, Clone)] + enum Bar { + A, + B, + } + + impl const Default for Bar { + fn default() -> Self { + Bar::A + } + } +} + +mod issue15536 { + #[derive(Copy, Clone)] + enum Bar { + A, + B, + } + + impl Default for Bar { + //~^ derivable_impls + fn default() -> Self { + Self::A + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/derivable_impls.stderr b/src/tools/clippy/tests/ui/derivable_impls.stderr index 0f73ad55a85e..cd46414cb4a8 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.stderr +++ b/src/tools/clippy/tests/ui/derivable_impls.stderr @@ -1,5 +1,5 @@ error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:20:1 + --> tests/ui/derivable_impls.rs:22:1 | LL | / impl std::default::Default for FooDefault<'_> { LL | | @@ -18,7 +18,7 @@ LL ~ struct FooDefault<'a> { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:42:1 + --> tests/ui/derivable_impls.rs:44:1 | LL | / impl std::default::Default for TupleDefault { LL | | @@ -35,7 +35,7 @@ LL ~ struct TupleDefault(bool, i32, u64); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:95:1 + --> tests/ui/derivable_impls.rs:97:1 | LL | / impl Default for StrDefault<'_> { LL | | @@ -52,7 +52,7 @@ LL ~ struct StrDefault<'a>(&'a str); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:122:1 + --> tests/ui/derivable_impls.rs:124:1 | LL | / impl Default for Y { LL | | @@ -69,7 +69,7 @@ LL ~ struct Y(u32); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:162:1 + --> tests/ui/derivable_impls.rs:164:1 | LL | / impl Default for WithoutSelfCurly { LL | | @@ -86,7 +86,7 @@ LL ~ struct WithoutSelfCurly { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:171:1 + --> tests/ui/derivable_impls.rs:173:1 | LL | / impl Default for WithoutSelfParan { LL | | @@ -103,7 +103,7 @@ LL ~ struct WithoutSelfParan(bool); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:194:1 + --> tests/ui/derivable_impls.rs:196:1 | LL | / impl Default for DirectDefaultDefaultCall { LL | | @@ -119,7 +119,7 @@ LL ~ pub struct DirectDefaultDefaultCall { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:206:1 + --> tests/ui/derivable_impls.rs:208:1 | LL | / impl Default for EquivalentToDefaultDefaultCallVec { LL | | @@ -135,7 +135,7 @@ LL ~ pub struct EquivalentToDefaultDefaultCallVec { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:234:1 + --> tests/ui/derivable_impls.rs:236:1 | LL | / impl Default for EquivalentToDefaultDefaultCallLocal { LL | | @@ -151,7 +151,7 @@ LL ~ pub struct EquivalentToDefaultDefaultCallLocal { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:274:1 + --> tests/ui/derivable_impls.rs:276:1 | LL | / impl Default for RepeatDefault1 { LL | | @@ -168,7 +168,7 @@ LL ~ pub struct RepeatDefault1 { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:309:1 + --> tests/ui/derivable_impls.rs:311:1 | LL | / impl Default for SimpleEnum { LL | | @@ -187,5 +187,28 @@ LL ~ #[default] LL ~ Bar, | -error: aborting due to 11 previous errors +error: this `impl` can be derived + --> tests/ui/derivable_impls.rs:432:5 + | +LL | / impl Default for Bar { +LL | | +LL | | fn default() -> Self { +LL | | Self::A +LL | | } +LL | | } + | |_____^ + | +help: replace the manual implementation with a derive attribute and mark the default variant + | +LL ~ #[derive(Default)] +LL ~ enum Bar { +LL ~ #[default] +LL ~ A, +LL | B, +LL | } +LL | +LL ~ + | + +error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/derivable_impls_derive_const.fixed b/src/tools/clippy/tests/ui/derivable_impls_derive_const.fixed new file mode 100644 index 000000000000..f0d8d2d24092 --- /dev/null +++ b/src/tools/clippy/tests/ui/derivable_impls_derive_const.fixed @@ -0,0 +1,25 @@ +#![allow(dead_code)] +#![feature(const_trait_impl)] +#![feature(const_default)] +#![feature(derive_const)] + +mod issue15493 { + #[derive(Copy, Clone)] + #[repr(transparent)] + #[derive_const(Default)] + struct Foo(u64); + + + + #[derive(Copy, Clone)] + #[derive_const(Default)] + enum Bar { + #[default] + A, + B, + } + + +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/derivable_impls_derive_const.rs b/src/tools/clippy/tests/ui/derivable_impls_derive_const.rs new file mode 100644 index 000000000000..7d70db1c097d --- /dev/null +++ b/src/tools/clippy/tests/ui/derivable_impls_derive_const.rs @@ -0,0 +1,32 @@ +#![allow(dead_code)] +#![feature(const_trait_impl)] +#![feature(const_default)] +#![feature(derive_const)] + +mod issue15493 { + #[derive(Copy, Clone)] + #[repr(transparent)] + struct Foo(u64); + + impl const Default for Foo { + //~^ derivable_impls + fn default() -> Self { + Self(0) + } + } + + #[derive(Copy, Clone)] + enum Bar { + A, + B, + } + + impl const Default for Bar { + //~^ derivable_impls + fn default() -> Self { + Bar::A + } + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/derivable_impls_derive_const.stderr b/src/tools/clippy/tests/ui/derivable_impls_derive_const.stderr new file mode 100644 index 000000000000..196bac185dda --- /dev/null +++ b/src/tools/clippy/tests/ui/derivable_impls_derive_const.stderr @@ -0,0 +1,46 @@ +error: this `impl` can be derived + --> tests/ui/derivable_impls_derive_const.rs:11:5 + | +LL | / impl const Default for Foo { +LL | | +LL | | fn default() -> Self { +LL | | Self(0) +LL | | } +LL | | } + | |_____^ + | + = note: `-D clippy::derivable-impls` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::derivable_impls)]` +help: replace the manual implementation with a derive attribute + | +LL ~ #[derive_const(Default)] +LL ~ struct Foo(u64); +LL | +LL ~ + | + +error: this `impl` can be derived + --> tests/ui/derivable_impls_derive_const.rs:24:5 + | +LL | / impl const Default for Bar { +LL | | +LL | | fn default() -> Self { +LL | | Bar::A +LL | | } +LL | | } + | |_____^ + | +help: replace the manual implementation with a derive attribute and mark the default variant + | +LL ~ #[derive_const(Default)] +LL ~ enum Bar { +LL ~ #[default] +LL ~ A, +LL | B, +LL | } +LL | +LL ~ + | + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed index 423a73734daa..46695dc929ab 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -73,6 +73,7 @@ fn test_units() { /// GPLv2 GPLv3 /// GitHub GitLab /// IPv4 IPv6 +/// InfiniBand RoCE /// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript /// PowerPC WebAssembly /// NaN NaNs diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index 8deffb4210e4..4082fa5b56f4 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -73,6 +73,7 @@ fn test_units() { /// GPLv2 GPLv3 /// GitHub GitLab /// IPv4 IPv6 +/// InfiniBand RoCE /// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript /// PowerPC WebAssembly /// NaN NaNs diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr index 98c26e6bec2e..2a94a8f31658 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr @@ -145,7 +145,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:90:5 + --> tests/ui/doc/doc-fixable.rs:91:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:108:5 + --> tests/ui/doc/doc-fixable.rs:109:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:117:8 + --> tests/ui/doc/doc-fixable.rs:118:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + /// ## `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:121:7 + --> tests/ui/doc/doc-fixable.rs:122:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + /// # `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:124:22 + --> tests/ui/doc/doc-fixable.rs:125:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL + /// Not a title #897 `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:126:5 + --> tests/ui/doc/doc-fixable.rs:127:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:134:5 + --> tests/ui/doc/doc-fixable.rs:135:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:148:5 + --> tests/ui/doc/doc-fixable.rs:149:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:160:43 + --> tests/ui/doc/doc-fixable.rs:161:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -253,7 +253,7 @@ LL + /** E.g., serialization of an empty list: `FooBar` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:165:5 + --> tests/ui/doc/doc-fixable.rs:166:5 | LL | And BarQuz too. | ^^^^^^ @@ -265,7 +265,7 @@ LL + And `BarQuz` too. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:166:1 + --> tests/ui/doc/doc-fixable.rs:167:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL + `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:174:43 + --> tests/ui/doc/doc-fixable.rs:175:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -289,7 +289,7 @@ LL + /** E.g., serialization of an empty list: `FooBar` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:179:5 + --> tests/ui/doc/doc-fixable.rs:180:5 | LL | And BarQuz too. | ^^^^^^ @@ -301,7 +301,7 @@ LL + And `BarQuz` too. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:180:1 + --> tests/ui/doc/doc-fixable.rs:181:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL + `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:194:5 + --> tests/ui/doc/doc-fixable.rs:195:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:214:22 + --> tests/ui/doc/doc-fixable.rs:215:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL + /// An iterator over `mycrate::Collection`'s values. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:239:34 + --> tests/ui/doc/doc-fixable.rs:240:34 | LL | /// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint | ^^^^^^^^^^^^^^^ @@ -349,7 +349,7 @@ LL + /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:263:22 + --> tests/ui/doc/doc-fixable.rs:264:22 | LL | /// There is no try (do() or do_not()). | ^^^^ @@ -361,7 +361,7 @@ LL + /// There is no try (`do()` or do_not()). | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:263:30 + --> tests/ui/doc/doc-fixable.rs:264:30 | LL | /// There is no try (do() or do_not()). | ^^^^^^^^ @@ -373,7 +373,7 @@ LL + /// There is no try (do() or `do_not()`). | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:268:5 + --> tests/ui/doc/doc-fixable.rs:269:5 | LL | /// ABes | ^^^^ @@ -385,7 +385,7 @@ LL + /// `ABes` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:275:9 + --> tests/ui/doc/doc-fixable.rs:276:9 | LL | /// foo() | ^^^^^ @@ -397,7 +397,7 @@ LL + /// `foo()` | error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> tests/ui/doc/doc-fixable.rs:280:5 + --> tests/ui/doc/doc-fixable.rs:281:5 | LL | /// https://github.com/rust-lang/rust-clippy/pull/12836 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `` diff --git a/src/tools/clippy/tests/ui/entry_unfixable.stderr b/src/tools/clippy/tests/ui/entry_unfixable.stderr index 0197d2ab4cf9..f92f472512f6 100644 --- a/src/tools/clippy/tests/ui/entry_unfixable.stderr +++ b/src/tools/clippy/tests/ui/entry_unfixable.stderr @@ -10,6 +10,7 @@ LL | | false LL | | } | |_____________^ | + = help: consider using the `Entry` API: https://doc.rust-lang.org/std/collections/struct.HashMap.html#entry-api = note: `-D clippy::map-entry` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::map_entry)]` @@ -24,6 +25,8 @@ LL | | } else { LL | | hm.insert(key, true); LL | | } | |_____^ + | + = help: consider using the `Entry` API: https://doc.rust-lang.org/std/collections/struct.HashMap.html#entry-api error: usage of `contains_key` followed by `insert` on a `HashMap` --> tests/ui/entry_unfixable.rs:80:13 @@ -36,6 +39,8 @@ LL | | let interner = INTERNER.lock().unwrap(); LL | | return Err(interner.resolve(name).unwrap().to_owned()); LL | | } | |_____________^ + | + = help: consider using the `Entry` API: https://doc.rust-lang.org/std/collections/struct.HashMap.html#entry-api error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed index 3d2b41b8fb81..6944a979c05e 100644 --- a/src/tools/clippy/tests/ui/eta.fixed +++ b/src/tools/clippy/tests/ui/eta.fixed @@ -565,6 +565,51 @@ fn issue_14789() { ); } +fn issue_15072() { + use std::ops::Deref; + + struct Foo; + impl Deref for Foo { + type Target = fn() -> &'static str; + + fn deref(&self) -> &Self::Target { + fn hello() -> &'static str { + "Hello, world!" + } + &(hello as fn() -> &'static str) + } + } + + fn accepts_fn(f: impl Fn() -> &'static str) { + println!("{}", f()); + } + + fn some_fn() -> &'static str { + todo!() + } + + let f = &Foo; + accepts_fn(**f); + //~^ redundant_closure + + let g = &some_fn; + accepts_fn(g); + //~^ redundant_closure + + struct Bar(Foo); + impl Deref for Bar { + type Target = Foo; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + let b = &Bar(Foo); + accepts_fn(***b); + //~^ redundant_closure +} + fn issue8817() { fn f(_: u32) -> u32 { todo!() diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs index 79d1103410d9..5bcc1cb26fd7 100644 --- a/src/tools/clippy/tests/ui/eta.rs +++ b/src/tools/clippy/tests/ui/eta.rs @@ -565,6 +565,51 @@ fn issue_14789() { ); } +fn issue_15072() { + use std::ops::Deref; + + struct Foo; + impl Deref for Foo { + type Target = fn() -> &'static str; + + fn deref(&self) -> &Self::Target { + fn hello() -> &'static str { + "Hello, world!" + } + &(hello as fn() -> &'static str) + } + } + + fn accepts_fn(f: impl Fn() -> &'static str) { + println!("{}", f()); + } + + fn some_fn() -> &'static str { + todo!() + } + + let f = &Foo; + accepts_fn(|| f()); + //~^ redundant_closure + + let g = &some_fn; + accepts_fn(|| g()); + //~^ redundant_closure + + struct Bar(Foo); + impl Deref for Bar { + type Target = Foo; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + let b = &Bar(Foo); + accepts_fn(|| b()); + //~^ redundant_closure +} + fn issue8817() { fn f(_: u32) -> u32 { todo!() diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr index aa32ed1a38ef..0b401cdea987 100644 --- a/src/tools/clippy/tests/ui/eta.stderr +++ b/src/tools/clippy/tests/ui/eta.stderr @@ -215,28 +215,46 @@ LL | let _field = bind.or_else(|| get_default()).unwrap(); | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default` error: redundant closure - --> tests/ui/eta.rs:588:14 + --> tests/ui/eta.rs:592:16 + | +LL | accepts_fn(|| f()); + | ^^^^^^ help: replace the closure with the function itself: `**f` + +error: redundant closure + --> tests/ui/eta.rs:596:16 + | +LL | accepts_fn(|| g()); + | ^^^^^^ help: replace the closure with the function itself: `g` + +error: redundant closure + --> tests/ui/eta.rs:609:16 + | +LL | accepts_fn(|| b()); + | ^^^^^^ help: replace the closure with the function itself: `***b` + +error: redundant closure + --> tests/ui/eta.rs:633:14 | LL | .map(|n| MyError::A(n)) | ^^^^^^^^^^^^^^^^^ help: replace the closure with the tuple variant itself: `MyError::A` error: redundant closure - --> tests/ui/eta.rs:585:14 + --> tests/ui/eta.rs:630:14 | LL | .map(|n| S(n)) | ^^^^^^^^ help: replace the closure with the tuple struct itself: `S` error: redundant closure - --> tests/ui/eta.rs:582:14 + --> tests/ui/eta.rs:627:14 | LL | .map(|n| g(n)) | ^^^^^^^^ help: replace the closure with the function itself: `g` error: redundant closure - --> tests/ui/eta.rs:579:14 + --> tests/ui/eta.rs:624:14 | LL | .map(|n| f(n)) | ^^^^^^^^ help: replace the closure with the function itself: `f` -error: aborting due to 39 previous errors +error: aborting due to 42 previous errors diff --git a/src/tools/clippy/tests/ui/excessive_precision.fixed b/src/tools/clippy/tests/ui/excessive_precision.fixed index 8a8c2e1939c8..8158d4b332ac 100644 --- a/src/tools/clippy/tests/ui/excessive_precision.fixed +++ b/src/tools/clippy/tests/ui/excessive_precision.fixed @@ -4,9 +4,16 @@ overflowing_literals, unused_variables, clippy::print_literal, - clippy::useless_vec + clippy::useless_vec, + clippy::approx_constant )] +macro_rules! make_pi { + ($i:ident : $t:ty) => { + const $i: $t = 3.14159265358979323846264338327950288419716939937510582097494459230781640628; + }; +} + fn main() { // Consts const GOOD32: f32 = 0.123_456; @@ -101,4 +108,40 @@ fn main() { const _: f64 = 3.0; //~^ excessive_precision const _: f64 = 3.0000000000000000; + + // Overly specified constants + let _: f32 = 1.012_345_7; + //~^ excessive_precision + let _: f64 = 1.012_345_678_901_234_6; + //~^ excessive_precision + const _: f32 = 1.01234567890123456789012345678901234567890; + const _: f64 = 1.01234567890123456789012345678901234567890; + + static STATIC1: f32 = 1.01234567890123456789012345678901234567890; + static STATIC2: f64 = 1.01234567890123456789012345678901234567890; + + static mut STATIC_MUT1: f32 = 1.01234567890123456789012345678901234567890; + static mut STATIC_MUT2: f64 = 1.01234567890123456789012345678901234567890; + + // From issue #13855 + let gamma = 0.577_215_664_901_532_9; + //~^ excessive_precision + const GAMMA: f64 = 0.5772156649015328606065120900824024310421; + + make_pi!(P32: f32); + make_pi!(P64: f64); +} + +trait ExcessivelyPreciseTrait { + // Overly specified constants + const GOOD1: f32 = 1.01234567890123456789012345678901234567890; + const GOOD2: f64 = 1.01234567890123456789012345678901234567890; +} + +struct ExcessivelyPreciseStruct; + +impl ExcessivelyPreciseStruct { + // Overly specified constants + const GOOD1: f32 = 1.01234567890123456789012345678901234567890; + const GOOD2: f64 = 1.01234567890123456789012345678901234567890; } diff --git a/src/tools/clippy/tests/ui/excessive_precision.rs b/src/tools/clippy/tests/ui/excessive_precision.rs index 5dcf55cb9273..7ee6247ee5ac 100644 --- a/src/tools/clippy/tests/ui/excessive_precision.rs +++ b/src/tools/clippy/tests/ui/excessive_precision.rs @@ -4,9 +4,16 @@ overflowing_literals, unused_variables, clippy::print_literal, - clippy::useless_vec + clippy::useless_vec, + clippy::approx_constant )] +macro_rules! make_pi { + ($i:ident : $t:ty) => { + const $i: $t = 3.14159265358979323846264338327950288419716939937510582097494459230781640628; + }; +} + fn main() { // Consts const GOOD32: f32 = 0.123_456; @@ -101,4 +108,40 @@ fn main() { const _: f64 = 3.0000000000000000e+00; //~^ excessive_precision const _: f64 = 3.0000000000000000; + + // Overly specified constants + let _: f32 = 1.01234567890123456789012345678901234567890; + //~^ excessive_precision + let _: f64 = 1.01234567890123456789012345678901234567890; + //~^ excessive_precision + const _: f32 = 1.01234567890123456789012345678901234567890; + const _: f64 = 1.01234567890123456789012345678901234567890; + + static STATIC1: f32 = 1.01234567890123456789012345678901234567890; + static STATIC2: f64 = 1.01234567890123456789012345678901234567890; + + static mut STATIC_MUT1: f32 = 1.01234567890123456789012345678901234567890; + static mut STATIC_MUT2: f64 = 1.01234567890123456789012345678901234567890; + + // From issue #13855 + let gamma = 0.5772156649015328606065120900824024310421; + //~^ excessive_precision + const GAMMA: f64 = 0.5772156649015328606065120900824024310421; + + make_pi!(P32: f32); + make_pi!(P64: f64); +} + +trait ExcessivelyPreciseTrait { + // Overly specified constants + const GOOD1: f32 = 1.01234567890123456789012345678901234567890; + const GOOD2: f64 = 1.01234567890123456789012345678901234567890; +} + +struct ExcessivelyPreciseStruct; + +impl ExcessivelyPreciseStruct { + // Overly specified constants + const GOOD1: f32 = 1.01234567890123456789012345678901234567890; + const GOOD2: f64 = 1.01234567890123456789012345678901234567890; } diff --git a/src/tools/clippy/tests/ui/excessive_precision.stderr b/src/tools/clippy/tests/ui/excessive_precision.stderr index f5eeadf0c8cb..40806d67487f 100644 --- a/src/tools/clippy/tests/ui/excessive_precision.stderr +++ b/src/tools/clippy/tests/ui/excessive_precision.stderr @@ -1,5 +1,5 @@ error: float has excessive precision - --> tests/ui/excessive_precision.rs:20:26 + --> tests/ui/excessive_precision.rs:27:26 | LL | const BAD32_1: f32 = 0.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + const BAD32_1: f32 = 0.123_456_79_f32; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:22:26 + --> tests/ui/excessive_precision.rs:29:26 | LL | const BAD32_2: f32 = 0.123_456_789; | ^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + const BAD32_2: f32 = 0.123_456_79; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:24:26 + --> tests/ui/excessive_precision.rs:31:26 | LL | const BAD32_3: f32 = 0.100_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + const BAD32_3: f32 = 0.1; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:26:29 + --> tests/ui/excessive_precision.rs:33:29 | LL | const BAD32_EDGE: f32 = 1.000_000_9; | ^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + const BAD32_EDGE: f32 = 1.000_001; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:31:26 + --> tests/ui/excessive_precision.rs:38:26 | LL | const BAD64_3: f64 = 0.100_000_000_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + const BAD64_3: f64 = 0.1; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:35:22 + --> tests/ui/excessive_precision.rs:42:22 | LL | println!("{:?}", 8.888_888_888_888_888_888_888); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + println!("{:?}", 8.888_888_888_888_89); | error: float has excessive precision - --> tests/ui/excessive_precision.rs:47:22 + --> tests/ui/excessive_precision.rs:54:22 | LL | let bad32: f32 = 1.123_456_789; | ^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + let bad32: f32 = 1.123_456_8; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:49:26 + --> tests/ui/excessive_precision.rs:56:26 | LL | let bad32_suf: f32 = 1.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + let bad32_suf: f32 = 1.123_456_8_f32; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:51:21 + --> tests/ui/excessive_precision.rs:58:21 | LL | let bad32_inf = 1.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + let bad32_inf = 1.123_456_8_f32; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:62:36 + --> tests/ui/excessive_precision.rs:69:36 | LL | let bad_vec32: Vec = vec![0.123_456_789]; | ^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + let bad_vec32: Vec = vec![0.123_456_79]; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:64:36 + --> tests/ui/excessive_precision.rs:71:36 | LL | let bad_vec64: Vec = vec![0.123_456_789_123_456_789]; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + let bad_vec64: Vec = vec![0.123_456_789_123_456_78]; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:69:24 + --> tests/ui/excessive_precision.rs:76:24 | LL | let bad_e32: f32 = 1.123_456_788_888e-10; | ^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + let bad_e32: f32 = 1.123_456_8e-10; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:73:27 + --> tests/ui/excessive_precision.rs:80:27 | LL | let bad_bige32: f32 = 1.123_456_788_888E-10; | ^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + let bad_bige32: f32 = 1.123_456_8E-10; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:86:13 + --> tests/ui/excessive_precision.rs:93:13 | LL | let _ = 2.225_073_858_507_201_1e-308_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + let _ = 2.225_073_858_507_201e-308_f64; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:90:13 + --> tests/ui/excessive_precision.rs:97:13 | LL | let _ = 1.000_000_000_000_001e-324_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + let _ = 0_f64; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:101:20 + --> tests/ui/excessive_precision.rs:108:20 | LL | const _: f64 = 3.0000000000000000e+00; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -192,5 +192,56 @@ LL - const _: f64 = 3.0000000000000000e+00; LL + const _: f64 = 3.0; | -error: aborting due to 16 previous errors +error: float has excessive precision + --> tests/ui/excessive_precision.rs:113:18 + | +LL | let _: f32 = 1.01234567890123456789012345678901234567890; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: consider making it a `const` item + --> tests/ui/excessive_precision.rs:113:5 + | +LL | let _: f32 = 1.01234567890123456789012345678901234567890; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider changing the type or truncating it to + | +LL - let _: f32 = 1.01234567890123456789012345678901234567890; +LL + let _: f32 = 1.012_345_7; + | + +error: float has excessive precision + --> tests/ui/excessive_precision.rs:115:18 + | +LL | let _: f64 = 1.01234567890123456789012345678901234567890; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: consider making it a `const` item + --> tests/ui/excessive_precision.rs:115:5 + | +LL | let _: f64 = 1.01234567890123456789012345678901234567890; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider changing the type or truncating it to + | +LL - let _: f64 = 1.01234567890123456789012345678901234567890; +LL + let _: f64 = 1.012_345_678_901_234_6; + | + +error: float has excessive precision + --> tests/ui/excessive_precision.rs:127:17 + | +LL | let gamma = 0.5772156649015328606065120900824024310421; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: consider making it a `const` item + --> tests/ui/excessive_precision.rs:127:5 + | +LL | let gamma = 0.5772156649015328606065120900824024310421; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider changing the type or truncating it to + | +LL - let gamma = 0.5772156649015328606065120900824024310421; +LL + let gamma = 0.577_215_664_901_532_9; + | + +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.rs b/src/tools/clippy/tests/ui/float_equality_without_abs.rs index a1548db6710d..e1dd79026839 100644 --- a/src/tools/clippy/tests/ui/float_equality_without_abs.rs +++ b/src/tools/clippy/tests/ui/float_equality_without_abs.rs @@ -1,8 +1,8 @@ +#![feature(f128)] +#![feature(f16)] #![warn(clippy::float_equality_without_abs)] //@no-rustfix: suggestions cause type ambiguity -// FIXME(f16_f128): add tests for these types when abs is available - pub fn is_roughly_equal(a: f32, b: f32) -> bool { (a - b) < f32::EPSILON //~^ float_equality_without_abs @@ -44,10 +44,20 @@ pub fn main() { let _ = f32::EPSILON > 1.0 - 2.0; //~^ float_equality_without_abs + let _ = (a as f16 - b as f16) < f16::EPSILON; + //~^ float_equality_without_abs + + let _ = (a as f128 - b as f128) < f128::EPSILON; + //~^ float_equality_without_abs + // those are correct + let _ = (a as f16 - b as f16).abs() < f16::EPSILON; let _ = (a - b).abs() < f32::EPSILON; let _ = (a as f64 - b as f64).abs() < f64::EPSILON; + let _ = (a as f128 - b as f128).abs() < f128::EPSILON; + let _ = f16::EPSILON > (a as f16 - b as f16).abs(); let _ = f32::EPSILON > (a - b).abs(); let _ = f64::EPSILON > (a as f64 - b as f64).abs(); + let _ = f128::EPSILON > (a as f128 - b as f128).abs(); } diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr index d4c89ce72ba9..55a150dead5a 100644 --- a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr +++ b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr @@ -89,5 +89,21 @@ LL | let _ = f32::EPSILON > 1.0 - 2.0; | | | help: add `.abs()`: `(1.0 - 2.0).abs()` -error: aborting due to 11 previous errors +error: float equality check without `.abs()` + --> tests/ui/float_equality_without_abs.rs:47:13 + | +LL | let _ = (a as f16 - b as f16) < f16::EPSILON; + | ---------------------^^^^^^^^^^^^^^^ + | | + | help: add `.abs()`: `(a as f16 - b as f16).abs()` + +error: float equality check without `.abs()` + --> tests/ui/float_equality_without_abs.rs:50:13 + | +LL | let _ = (a as f128 - b as f128) < f128::EPSILON; + | -----------------------^^^^^^^^^^^^^^^^ + | | + | help: add `.abs()`: `(a as f128 - b as f128).abs()` + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed index d14a805b6667..0fd130609aee 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed @@ -165,3 +165,44 @@ mod issue15257 { do_something((i % 2 == 0).then_some(closure_fn)); } } + +fn issue15005() { + struct Counter { + count: u32, + } + + impl Counter { + fn new() -> Counter { + Counter { count: 0 } + } + } + + impl Iterator for Counter { + type Item = u32; + + fn next(&mut self) -> Option { + //~v if_then_some_else_none + (self.count < 5).then(|| { self.count += 1; self.count }) + } + } +} + +fn statements_from_macro() { + macro_rules! mac { + () => { + println!("foo"); + println!("bar"); + }; + } + //~v if_then_some_else_none + let _ = true.then(|| { mac!(); 42 }); +} + +fn dont_lint_inside_macros() { + macro_rules! mac { + ($cond:expr, $res:expr) => { + if $cond { Some($res) } else { None } + }; + } + let _: Option = mac!(true, 42); +} diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs index bb0072f31573..640828aa9bf6 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.rs +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs @@ -211,3 +211,54 @@ mod issue15257 { }); } } + +fn issue15005() { + struct Counter { + count: u32, + } + + impl Counter { + fn new() -> Counter { + Counter { count: 0 } + } + } + + impl Iterator for Counter { + type Item = u32; + + fn next(&mut self) -> Option { + //~v if_then_some_else_none + if self.count < 5 { + self.count += 1; + Some(self.count) + } else { + None + } + } + } +} + +fn statements_from_macro() { + macro_rules! mac { + () => { + println!("foo"); + println!("bar"); + }; + } + //~v if_then_some_else_none + let _ = if true { + mac!(); + Some(42) + } else { + None + }; +} + +fn dont_lint_inside_macros() { + macro_rules! mac { + ($cond:expr, $res:expr) => { + if $cond { Some($res) } else { None } + }; + } + let _: Option = mac!(true, 42); +} diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr index c2e624a0a73b..58651a055942 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr @@ -116,5 +116,28 @@ LL | | None LL | | }); | |_________^ help: try: `(i % 2 == 0).then_some(closure_fn)` -error: aborting due to 11 previous errors +error: this could be simplified with `bool::then` + --> tests/ui/if_then_some_else_none.rs:231:13 + | +LL | / if self.count < 5 { +LL | | self.count += 1; +LL | | Some(self.count) +LL | | } else { +LL | | None +LL | | } + | |_____________^ help: try: `(self.count < 5).then(|| { self.count += 1; self.count })` + +error: this could be simplified with `bool::then` + --> tests/ui/if_then_some_else_none.rs:249:13 + | +LL | let _ = if true { + | _____________^ +LL | | mac!(); +LL | | Some(42) +LL | | } else { +LL | | None +LL | | }; + | |_____^ help: try: `true.then(|| { mac!(); 42 })` + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/infinite_loops.rs b/src/tools/clippy/tests/ui/infinite_loops.rs index 9b8c39331970..7d01a7fb61fc 100644 --- a/src/tools/clippy/tests/ui/infinite_loops.rs +++ b/src/tools/clippy/tests/ui/infinite_loops.rs @@ -521,4 +521,19 @@ mod tokio_spawn_test { } } +mod issue15541 { + async fn good() -> ! { + loop { + std::future::pending().await + } + } + + async fn bad() { + //~v infinite_loop + loop { + std::future::pending().await + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/infinite_loops.stderr b/src/tools/clippy/tests/ui/infinite_loops.stderr index 4c6b6f725f13..319f1e5012b6 100644 --- a/src/tools/clippy/tests/ui/infinite_loops.stderr +++ b/src/tools/clippy/tests/ui/infinite_loops.stderr @@ -333,5 +333,15 @@ LL | | } | = help: if this is not intended, try adding a `break` or `return` condition in the loop -error: aborting due to 23 previous errors +error: infinite loop detected + --> tests/ui/infinite_loops.rs:533:9 + | +LL | / loop { +LL | | std::future::pending().await +LL | | } + | |_________^ + | + = help: if this is not intended, try adding a `break` or `return` condition in the loop + +error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed index 7b0d19068346..406336dbd095 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed @@ -108,6 +108,8 @@ fn generics() { //~^ manual_is_ascii_check take_while(|c: char| c.is_ascii_uppercase()); //~^ manual_is_ascii_check + take_while(|c: char| c.is_ascii_uppercase()); + //~^ manual_is_ascii_check } fn adds_type_reference() { @@ -115,4 +117,6 @@ fn adds_type_reference() { //~^ manual_is_ascii_check let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect(); //~^ manual_is_ascii_check + let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect(); + //~^ manual_is_ascii_check } diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs index e4f7fe9f5838..a624497e75e5 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs @@ -108,6 +108,8 @@ fn generics() { //~^ manual_is_ascii_check take_while(|c: char| ('A'..='Z').contains(&c)); //~^ manual_is_ascii_check + take_while(|c| matches!(c, 'A'..='Z')); + //~^ manual_is_ascii_check } fn adds_type_reference() { @@ -115,4 +117,6 @@ fn adds_type_reference() { //~^ manual_is_ascii_check let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect(); //~^ manual_is_ascii_check + let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| matches!(c, '0'..='9')).collect(); + //~^ manual_is_ascii_check } diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr index 9fd7f457b420..cb2548ea7316 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr @@ -176,7 +176,19 @@ LL | take_while(|c: char| ('A'..='Z').contains(&c)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_ascii_uppercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:114:63 + --> tests/ui/manual_is_ascii_check.rs:111:20 + | +LL | take_while(|c| matches!(c, 'A'..='Z')); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - take_while(|c| matches!(c, 'A'..='Z')); +LL + take_while(|c: char| c.is_ascii_uppercase()); + | + +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:116:63 | LL | let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c| ('0'..='9').contains(c)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -188,7 +200,7 @@ LL + let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c: &&char| c.is_ | error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:116:71 + --> tests/ui/manual_is_ascii_check.rs:118:71 | LL | let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -199,5 +211,17 @@ LL - let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'. LL + let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect(); | -error: aborting due to 29 previous errors +error: manual check for common ascii range + --> tests/ui/manual_is_ascii_check.rs:120:71 + | +LL | let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| matches!(c, '0'..='9')).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| matches!(c, '0'..='9')).collect(); +LL + let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect(); + | + +error: aborting due to 31 previous errors diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed index 6c971ba63384..a10aae8cc121 100644 --- a/src/tools/clippy/tests/ui/map_identity.fixed +++ b/src/tools/clippy/tests/ui/map_identity.fixed @@ -1,3 +1,4 @@ +//@require-annotations-for-level: ERROR #![warn(clippy::map_identity)] #![allow(clippy::needless_return, clippy::disallowed_names)] @@ -72,20 +73,33 @@ fn issue11764() { } fn issue13904() { - // don't lint: `it.next()` would not be legal as `it` is immutable - let it = [1, 2, 3].into_iter(); - let _ = it.map(|x| x).next(); + // lint, but there's a catch: + // when we remove the `.map()`, `it.next()` would require `it` to be mutable + // therefore, include that in the suggestion as well + let mut it = [1, 2, 3].into_iter(); + let _ = it.next(); + //~^ map_identity + //~| HELP: remove the call to `map`, and make `it` mutable + + // lint + let mut index = [1, 2, 3].into_iter(); + let mut subindex = (index.by_ref().take(3), 42); + let _ = subindex.0.next(); + //~^ map_identity + //~| HELP: remove the call to `map`, and make `subindex` mutable // lint #[allow(unused_mut)] let mut it = [1, 2, 3].into_iter(); let _ = it.next(); //~^ map_identity + //~| HELP: remove the call to `map` // lint let it = [1, 2, 3].into_iter(); let _ = { it }.next(); //~^ map_identity + //~| HELP: remove the call to `map` } // same as `issue11764`, but for arrays diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs index 59dcfcda3b6e..fc6e018f9248 100644 --- a/src/tools/clippy/tests/ui/map_identity.rs +++ b/src/tools/clippy/tests/ui/map_identity.rs @@ -1,3 +1,4 @@ +//@require-annotations-for-level: ERROR #![warn(clippy::map_identity)] #![allow(clippy::needless_return, clippy::disallowed_names)] @@ -78,20 +79,33 @@ fn issue11764() { } fn issue13904() { - // don't lint: `it.next()` would not be legal as `it` is immutable + // lint, but there's a catch: + // when we remove the `.map()`, `it.next()` would require `it` to be mutable + // therefore, include that in the suggestion as well let it = [1, 2, 3].into_iter(); let _ = it.map(|x| x).next(); + //~^ map_identity + //~| HELP: remove the call to `map`, and make `it` mutable + + // lint + let mut index = [1, 2, 3].into_iter(); + let subindex = (index.by_ref().take(3), 42); + let _ = subindex.0.map(|n| n).next(); + //~^ map_identity + //~| HELP: remove the call to `map`, and make `subindex` mutable // lint #[allow(unused_mut)] let mut it = [1, 2, 3].into_iter(); let _ = it.map(|x| x).next(); //~^ map_identity + //~| HELP: remove the call to `map` // lint let it = [1, 2, 3].into_iter(); let _ = { it }.map(|x| x).next(); //~^ map_identity + //~| HELP: remove the call to `map` } // same as `issue11764`, but for arrays diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr index a50c0d6b87b5..8d19d62cdc64 100644 --- a/src/tools/clippy/tests/ui/map_identity.stderr +++ b/src/tools/clippy/tests/ui/map_identity.stderr @@ -1,5 +1,5 @@ error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:7:47 + --> tests/ui/map_identity.rs:8:47 | LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); | ^^^^^^^^^^^^^^^^^^ help: remove the call to `map` @@ -8,25 +8,25 @@ LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); = help: to override `-D warnings` add `#[allow(clippy::map_identity)]` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:9:57 + --> tests/ui/map_identity.rs:10:57 | LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); | ^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:9:29 + --> tests/ui/map_identity.rs:10:29 | LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:12:32 + --> tests/ui/map_identity.rs:13:32 | LL | let _: Option = Some(3).map(|x| x); | ^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:14:36 + --> tests/ui/map_identity.rs:15:36 | LL | let _: Result = Ok(-3).map(|x| { | ____________________________________^ @@ -36,19 +36,19 @@ LL | | }); | |______^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:25:36 + --> tests/ui/map_identity.rs:26:36 | LL | let _: Result = Ok(1).map_err(|a| a); | ^^^^^^^^^^^^^^^ help: remove the call to `map_err` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:36:22 + --> tests/ui/map_identity.rs:37:22 | LL | let _ = x.clone().map(|(x, y)| (x, y)); | ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:38:22 + --> tests/ui/map_identity.rs:39:22 | LL | let _ = x.clone().map(|(x, y)| { | ______________________^ @@ -58,76 +58,100 @@ LL | | }); | |______^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:42:22 + --> tests/ui/map_identity.rs:43:22 | LL | let _ = x.clone().map(|(x, y)| return (x, y)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:46:22 + --> tests/ui/map_identity.rs:47:22 | LL | let _ = y.clone().map(|(x, y, (z, (w,)))| (x, y, (z, (w,)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:76:30 + --> tests/ui/map_identity.rs:77:30 | LL | let _ = x.iter().copied().map(|(x, y)| (x, y)); | ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:88:15 + --> tests/ui/map_identity.rs:86:15 + | +LL | let _ = it.map(|x| x).next(); + | ^^^^^^^^^^^ + | +help: remove the call to `map`, and make `it` mutable + | +LL ~ let mut it = [1, 2, 3].into_iter(); +LL ~ let _ = it.next(); + | + +error: unnecessary map of the identity function + --> tests/ui/map_identity.rs:93:23 + | +LL | let _ = subindex.0.map(|n| n).next(); + | ^^^^^^^^^^^ + | +help: remove the call to `map`, and make `subindex` mutable + | +LL ~ let mut subindex = (index.by_ref().take(3), 42); +LL ~ let _ = subindex.0.next(); + | + +error: unnecessary map of the identity function + --> tests/ui/map_identity.rs:100:15 | LL | let _ = it.map(|x| x).next(); | ^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:93:19 + --> tests/ui/map_identity.rs:106:19 | LL | let _ = { it }.map(|x| x).next(); | ^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:105:30 + --> tests/ui/map_identity.rs:119:30 | LL | let _ = x.iter().copied().map(|[x, y]| [x, y]); | ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:131:26 + --> tests/ui/map_identity.rs:145:26 | LL | let _ = x.into_iter().map(|Foo { foo, bar }| Foo { foo, bar }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:135:26 + --> tests/ui/map_identity.rs:149:26 | LL | let _ = x.into_iter().map(|Foo { foo, bar }| foo::Foo { foo, bar }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:143:26 + --> tests/ui/map_identity.rs:157:26 | LL | let _ = x.into_iter().map(|Foo { foo, bar }| Foo { foo: foo, bar: bar }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:147:26 + --> tests/ui/map_identity.rs:161:26 | LL | let _ = x.into_iter().map(|Foo { foo, bar }| Foo { bar, foo }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:157:26 + --> tests/ui/map_identity.rs:171:26 | LL | let _ = x.into_iter().map(|Foo2(foo, bar)| Foo2(foo, bar)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:161:26 + --> tests/ui/map_identity.rs:175:26 | LL | let _ = x.into_iter().map(|Foo2(foo, bar)| foo::Foo2(foo, bar)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` -error: aborting due to 20 previous errors +error: aborting due to 22 previous errors diff --git a/src/tools/clippy/tests/ui/missing_inline.rs b/src/tools/clippy/tests/ui/missing_inline.rs index 223c7447975a..8e937d609512 100644 --- a/src/tools/clippy/tests/ui/missing_inline.rs +++ b/src/tools/clippy/tests/ui/missing_inline.rs @@ -97,3 +97,10 @@ pub mod issue15301 { println!("Just called a Rust function from Rust!"); } } + +pub mod issue15491 { + pub trait Foo { + #[allow(clippy::missing_inline_in_public_items)] + fn foo(&self) {} + } +} diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.rs b/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.rs new file mode 100644 index 000000000000..08ba3b791ee7 --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.rs @@ -0,0 +1,29 @@ +//@no-rustfix + +fn issue14984() { + async fn e() {} + async fn x() -> u32 { + 0 + } + async fn y() -> f32 { + 0.0 + }; + let mut yy = unsafe { std::ptr::read(&y()) }; + yy = unsafe { std::mem::transmute(std::ptr::read(&x())) }; + //~^ missing_transmute_annotations + + let mut zz = 0u8; + zz = unsafe { std::mem::transmute(std::ptr::read(&x())) }; + //~^ missing_transmute_annotations + + yy = unsafe { std::mem::transmute(zz) }; + //~^ missing_transmute_annotations + + fn a() -> impl Sized { + 0u32 + } + + let mut b: f32 = 0.0; + b = unsafe { std::mem::transmute(a()) }; + //~^ missing_transmute_annotations +} diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.stderr b/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.stderr new file mode 100644 index 000000000000..83efdce13f7e --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_transmute_annotations_unfixable.stderr @@ -0,0 +1,36 @@ +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations_unfixable.rs:12:29 + | +LL | yy = unsafe { std::mem::transmute(std::ptr::read(&x())) }; + | ^^^^^^^^^ + | + = help: consider giving the source and destination types a name, and adding missing type annotations + = note: `-D clippy::missing-transmute-annotations` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_transmute_annotations)]` + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations_unfixable.rs:16:29 + | +LL | zz = unsafe { std::mem::transmute(std::ptr::read(&x())) }; + | ^^^^^^^^^ + | + = help: consider giving the origin type a name, and adding missing type annotations + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations_unfixable.rs:19:29 + | +LL | yy = unsafe { std::mem::transmute(zz) }; + | ^^^^^^^^^ + | + = help: consider giving the destination type a name, and adding missing type annotations + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations_unfixable.rs:27:28 + | +LL | b = unsafe { std::mem::transmute(a()) }; + | ^^^^^^^^^ + | + = help: consider giving `a()`'s type a name, and adding missing type annotations + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/mut_reference.fixed b/src/tools/clippy/tests/ui/mut_reference.fixed new file mode 100644 index 000000000000..03d854099e64 --- /dev/null +++ b/src/tools/clippy/tests/ui/mut_reference.fixed @@ -0,0 +1,170 @@ +#![allow(clippy::mut_mut)] + +fn takes_ref(a: &i32) {} +fn takes_refmut(a: &mut i32) {} +fn takes_ref_ref(a: &&i32) {} +fn takes_refmut_ref(a: &mut &i32) {} +fn takes_ref_refmut(a: &&mut i32) {} +fn takes_refmut_refmut(a: &mut &mut i32) {} +fn takes_raw_const(a: *const i32) {} +fn takes_raw_mut(a: *mut i32) {} + +mod issue11268 { + macro_rules! x { + (1 $f:expr) => { + $f(&mut 1); + }; + (2 $f:expr) => { + $f(&mut &1) + }; + (3 $f:expr) => { + $f(&mut &mut 1) + }; + (4 $f:expr) => { + let mut a = 1; + $f(&raw mut a) + }; + } + + fn f() { + x!(1 super::takes_ref); + x!(1 super::takes_refmut); + x!(2 super::takes_refmut_ref); + x!(3 super::takes_ref_refmut); + x!(3 super::takes_refmut_refmut); + x!(4 super::takes_raw_const); + x!(4 super::takes_raw_mut); + } +} + +struct MyStruct; + +impl MyStruct { + fn takes_ref(&self, a: &i32) {} + fn takes_refmut(&self, a: &mut i32) {} + fn takes_ref_ref(&self, a: &&i32) {} + fn takes_refmut_ref(&self, a: &mut &i32) {} + fn takes_ref_refmut(&self, a: &&mut i32) {} + fn takes_refmut_refmut(&self, a: &mut &mut i32) {} + fn takes_raw_const(&self, a: *const i32) {} + fn takes_raw_mut(&self, a: *mut i32) {} +} + +#[warn(clippy::unnecessary_mut_passed)] +fn main() { + // Functions + takes_ref(&42); + //~^ unnecessary_mut_passed + takes_ref_ref(&&42); + //~^ unnecessary_mut_passed + takes_ref_refmut(&&mut 42); + //~^ unnecessary_mut_passed + takes_raw_const(&42); + //~^ unnecessary_mut_passed + + let as_ptr: fn(&i32) = takes_ref; + as_ptr(&42); + //~^ unnecessary_mut_passed + let as_ptr: fn(&&i32) = takes_ref_ref; + as_ptr(&&42); + //~^ unnecessary_mut_passed + let as_ptr: fn(&&mut i32) = takes_ref_refmut; + as_ptr(&&mut 42); + //~^ unnecessary_mut_passed + let as_ptr: fn(*const i32) = takes_raw_const; + as_ptr(&42); + //~^ unnecessary_mut_passed + + // Methods + let my_struct = MyStruct; + my_struct.takes_ref(&42); + //~^ unnecessary_mut_passed + my_struct.takes_ref_ref(&&42); + //~^ unnecessary_mut_passed + my_struct.takes_ref_refmut(&&mut 42); + //~^ unnecessary_mut_passed + my_struct.takes_raw_const(&42); + //~^ unnecessary_mut_passed + + // No error + + // Functions + takes_ref(&42); + let as_ptr: fn(&i32) = takes_ref; + as_ptr(&42); + + takes_refmut(&mut 42); + let as_ptr: fn(&mut i32) = takes_refmut; + as_ptr(&mut 42); + + takes_ref_ref(&&42); + let as_ptr: fn(&&i32) = takes_ref_ref; + as_ptr(&&42); + + takes_refmut_ref(&mut &42); + let as_ptr: fn(&mut &i32) = takes_refmut_ref; + as_ptr(&mut &42); + + takes_ref_refmut(&&mut 42); + let as_ptr: fn(&&mut i32) = takes_ref_refmut; + as_ptr(&&mut 42); + + takes_refmut_refmut(&mut &mut 42); + let as_ptr: fn(&mut &mut i32) = takes_refmut_refmut; + as_ptr(&mut &mut 42); + + takes_raw_const(&42); + let as_ptr: fn(*const i32) = takes_raw_const; + as_ptr(&42); + + takes_raw_mut(&mut 42); + let as_ptr: fn(*mut i32) = takes_raw_mut; + as_ptr(&mut 42); + + let a = &mut 42; + let b = &mut &42; + let c = &mut &mut 42; + takes_ref(a); + takes_ref_ref(b); + takes_ref_refmut(c); + takes_raw_const(a); + + // Methods + my_struct.takes_ref(&42); + my_struct.takes_refmut(&mut 42); + my_struct.takes_ref_ref(&&42); + my_struct.takes_refmut_ref(&mut &42); + my_struct.takes_ref_refmut(&&mut 42); + my_struct.takes_refmut_refmut(&mut &mut 42); + my_struct.takes_raw_const(&42); + my_struct.takes_raw_mut(&mut 42); + my_struct.takes_ref(a); + my_struct.takes_ref_ref(b); + my_struct.takes_ref_refmut(c); + my_struct.takes_raw_const(a); + my_struct.takes_raw_mut(a); +} + +// not supported currently +fn raw_ptrs(my_struct: MyStruct) { + let mut n = 42; + + takes_raw_const(&raw mut n); + + let as_ptr: fn(*const i32) = takes_raw_const; + as_ptr(&raw mut n); + + my_struct.takes_raw_const(&raw mut n); + + // No error + + takes_raw_const(&raw const n); + takes_raw_mut(&raw mut n); + + let a = &raw mut n; + takes_raw_const(a); + + my_struct.takes_raw_const(&raw const n); + my_struct.takes_raw_mut(&raw mut n); + my_struct.takes_raw_const(a); +} diff --git a/src/tools/clippy/tests/ui/mut_reference.rs b/src/tools/clippy/tests/ui/mut_reference.rs index f664c373cdc3..80e3f5069277 100644 --- a/src/tools/clippy/tests/ui/mut_reference.rs +++ b/src/tools/clippy/tests/ui/mut_reference.rs @@ -1,60 +1,170 @@ -#![allow(unused_variables, dead_code)] -//@no-rustfix -fn takes_an_immutable_reference(a: &i32) {} -fn takes_a_mutable_reference(a: &mut i32) {} +#![allow(clippy::mut_mut)] + +fn takes_ref(a: &i32) {} +fn takes_refmut(a: &mut i32) {} +fn takes_ref_ref(a: &&i32) {} +fn takes_refmut_ref(a: &mut &i32) {} +fn takes_ref_refmut(a: &&mut i32) {} +fn takes_refmut_refmut(a: &mut &mut i32) {} +fn takes_raw_const(a: *const i32) {} +fn takes_raw_mut(a: *mut i32) {} mod issue11268 { macro_rules! x { - ($f:expr) => { + (1 $f:expr) => { $f(&mut 1); }; + (2 $f:expr) => { + $f(&mut &1) + }; + (3 $f:expr) => { + $f(&mut &mut 1) + }; + (4 $f:expr) => { + let mut a = 1; + $f(&raw mut a) + }; } fn f() { - x!(super::takes_an_immutable_reference); - x!(super::takes_a_mutable_reference); + x!(1 super::takes_ref); + x!(1 super::takes_refmut); + x!(2 super::takes_refmut_ref); + x!(3 super::takes_ref_refmut); + x!(3 super::takes_refmut_refmut); + x!(4 super::takes_raw_const); + x!(4 super::takes_raw_mut); } } struct MyStruct; impl MyStruct { - fn takes_an_immutable_reference(&self, a: &i32) {} - - fn takes_a_mutable_reference(&self, a: &mut i32) {} + fn takes_ref(&self, a: &i32) {} + fn takes_refmut(&self, a: &mut i32) {} + fn takes_ref_ref(&self, a: &&i32) {} + fn takes_refmut_ref(&self, a: &mut &i32) {} + fn takes_ref_refmut(&self, a: &&mut i32) {} + fn takes_refmut_refmut(&self, a: &mut &mut i32) {} + fn takes_raw_const(&self, a: *const i32) {} + fn takes_raw_mut(&self, a: *mut i32) {} } #[warn(clippy::unnecessary_mut_passed)] fn main() { // Functions - takes_an_immutable_reference(&mut 42); + takes_ref(&mut 42); + //~^ unnecessary_mut_passed + takes_ref_ref(&mut &42); + //~^ unnecessary_mut_passed + takes_ref_refmut(&mut &mut 42); + //~^ unnecessary_mut_passed + takes_raw_const(&mut 42); //~^ unnecessary_mut_passed - let as_ptr: fn(&i32) = takes_an_immutable_reference; + let as_ptr: fn(&i32) = takes_ref; + as_ptr(&mut 42); + //~^ unnecessary_mut_passed + let as_ptr: fn(&&i32) = takes_ref_ref; + as_ptr(&mut &42); + //~^ unnecessary_mut_passed + let as_ptr: fn(&&mut i32) = takes_ref_refmut; + as_ptr(&mut &mut 42); + //~^ unnecessary_mut_passed + let as_ptr: fn(*const i32) = takes_raw_const; as_ptr(&mut 42); //~^ unnecessary_mut_passed // Methods let my_struct = MyStruct; - my_struct.takes_an_immutable_reference(&mut 42); + my_struct.takes_ref(&mut 42); + //~^ unnecessary_mut_passed + my_struct.takes_ref_ref(&mut &42); + //~^ unnecessary_mut_passed + my_struct.takes_ref_refmut(&mut &mut 42); + //~^ unnecessary_mut_passed + my_struct.takes_raw_const(&mut 42); //~^ unnecessary_mut_passed // No error // Functions - takes_an_immutable_reference(&42); - let as_ptr: fn(&i32) = takes_an_immutable_reference; + takes_ref(&42); + let as_ptr: fn(&i32) = takes_ref; as_ptr(&42); - takes_a_mutable_reference(&mut 42); - let as_ptr: fn(&mut i32) = takes_a_mutable_reference; + takes_refmut(&mut 42); + let as_ptr: fn(&mut i32) = takes_refmut; + as_ptr(&mut 42); + + takes_ref_ref(&&42); + let as_ptr: fn(&&i32) = takes_ref_ref; + as_ptr(&&42); + + takes_refmut_ref(&mut &42); + let as_ptr: fn(&mut &i32) = takes_refmut_ref; + as_ptr(&mut &42); + + takes_ref_refmut(&&mut 42); + let as_ptr: fn(&&mut i32) = takes_ref_refmut; + as_ptr(&&mut 42); + + takes_refmut_refmut(&mut &mut 42); + let as_ptr: fn(&mut &mut i32) = takes_refmut_refmut; + as_ptr(&mut &mut 42); + + takes_raw_const(&42); + let as_ptr: fn(*const i32) = takes_raw_const; + as_ptr(&42); + + takes_raw_mut(&mut 42); + let as_ptr: fn(*mut i32) = takes_raw_mut; as_ptr(&mut 42); let a = &mut 42; - takes_an_immutable_reference(a); + let b = &mut &42; + let c = &mut &mut 42; + takes_ref(a); + takes_ref_ref(b); + takes_ref_refmut(c); + takes_raw_const(a); // Methods - my_struct.takes_an_immutable_reference(&42); - my_struct.takes_a_mutable_reference(&mut 42); - my_struct.takes_an_immutable_reference(a); + my_struct.takes_ref(&42); + my_struct.takes_refmut(&mut 42); + my_struct.takes_ref_ref(&&42); + my_struct.takes_refmut_ref(&mut &42); + my_struct.takes_ref_refmut(&&mut 42); + my_struct.takes_refmut_refmut(&mut &mut 42); + my_struct.takes_raw_const(&42); + my_struct.takes_raw_mut(&mut 42); + my_struct.takes_ref(a); + my_struct.takes_ref_ref(b); + my_struct.takes_ref_refmut(c); + my_struct.takes_raw_const(a); + my_struct.takes_raw_mut(a); +} + +// not supported currently +fn raw_ptrs(my_struct: MyStruct) { + let mut n = 42; + + takes_raw_const(&raw mut n); + + let as_ptr: fn(*const i32) = takes_raw_const; + as_ptr(&raw mut n); + + my_struct.takes_raw_const(&raw mut n); + + // No error + + takes_raw_const(&raw const n); + takes_raw_mut(&raw mut n); + + let a = &raw mut n; + takes_raw_const(a); + + my_struct.takes_raw_const(&raw const n); + my_struct.takes_raw_mut(&raw mut n); + my_struct.takes_raw_const(a); } diff --git a/src/tools/clippy/tests/ui/mut_reference.stderr b/src/tools/clippy/tests/ui/mut_reference.stderr index 474221329c25..5ecfaa37416b 100644 --- a/src/tools/clippy/tests/ui/mut_reference.stderr +++ b/src/tools/clippy/tests/ui/mut_reference.stderr @@ -1,23 +1,77 @@ -error: the function `takes_an_immutable_reference` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:30:34 +error: the function `takes_ref` doesn't need a mutable reference + --> tests/ui/mut_reference.rs:56:15 | -LL | takes_an_immutable_reference(&mut 42); - | ^^^^^^^ +LL | takes_ref(&mut 42); + | ^^^^^^^ help: remove this `mut`: `&42` | = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]` +error: the function `takes_ref_ref` doesn't need a mutable reference + --> tests/ui/mut_reference.rs:58:19 + | +LL | takes_ref_ref(&mut &42); + | ^^^^^^^^ help: remove this `mut`: `&&42` + +error: the function `takes_ref_refmut` doesn't need a mutable reference + --> tests/ui/mut_reference.rs:60:22 + | +LL | takes_ref_refmut(&mut &mut 42); + | ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42` + +error: the function `takes_raw_const` doesn't need a mutable reference + --> tests/ui/mut_reference.rs:62:21 + | +LL | takes_raw_const(&mut 42); + | ^^^^^^^ help: remove this `mut`: `&42` + error: the function `as_ptr` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:34:12 + --> tests/ui/mut_reference.rs:66:12 | LL | as_ptr(&mut 42); - | ^^^^^^^ + | ^^^^^^^ help: remove this `mut`: `&42` -error: the method `takes_an_immutable_reference` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:39:44 +error: the function `as_ptr` doesn't need a mutable reference + --> tests/ui/mut_reference.rs:69:12 | -LL | my_struct.takes_an_immutable_reference(&mut 42); - | ^^^^^^^ +LL | as_ptr(&mut &42); + | ^^^^^^^^ help: remove this `mut`: `&&42` -error: aborting due to 3 previous errors +error: the function `as_ptr` doesn't need a mutable reference + --> tests/ui/mut_reference.rs:72:12 + | +LL | as_ptr(&mut &mut 42); + | ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42` + +error: the function `as_ptr` doesn't need a mutable reference + --> tests/ui/mut_reference.rs:75:12 + | +LL | as_ptr(&mut 42); + | ^^^^^^^ help: remove this `mut`: `&42` + +error: the method `takes_ref` doesn't need a mutable reference + --> tests/ui/mut_reference.rs:80:25 + | +LL | my_struct.takes_ref(&mut 42); + | ^^^^^^^ help: remove this `mut`: `&42` + +error: the method `takes_ref_ref` doesn't need a mutable reference + --> tests/ui/mut_reference.rs:82:29 + | +LL | my_struct.takes_ref_ref(&mut &42); + | ^^^^^^^^ help: remove this `mut`: `&&42` + +error: the method `takes_ref_refmut` doesn't need a mutable reference + --> tests/ui/mut_reference.rs:84:32 + | +LL | my_struct.takes_ref_refmut(&mut &mut 42); + | ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42` + +error: the method `takes_raw_const` doesn't need a mutable reference + --> tests/ui/mut_reference.rs:86:31 + | +LL | my_struct.takes_raw_const(&mut 42); + | ^^^^^^^ help: remove this `mut`: `&42` + +error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr index 3f117ee5a502..9404d07ba0e0 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr @@ -135,7 +135,7 @@ error: equality checks against true are unnecessary --> tests/ui/needless_bool/fixable.rs:157:8 | LL | if x == true {}; - | ^^^^^^^^^ help: try simplifying it as shown: `x` + | ^^^^^^^^^ help: try: `x` | = note: `-D clippy::bool-comparison` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` @@ -144,19 +144,19 @@ error: equality checks against false can be replaced by a negation --> tests/ui/needless_bool/fixable.rs:162:8 | LL | if x == false {}; - | ^^^^^^^^^^ help: try simplifying it as shown: `!x` + | ^^^^^^^^^^ help: try: `!x` error: equality checks against true are unnecessary --> tests/ui/needless_bool/fixable.rs:173:8 | LL | if x == true {}; - | ^^^^^^^^^ help: try simplifying it as shown: `x` + | ^^^^^^^^^ help: try: `x` error: equality checks against false can be replaced by a negation --> tests/ui/needless_bool/fixable.rs:175:8 | LL | if x == false {}; - | ^^^^^^^^^^ help: try simplifying it as shown: `!x` + | ^^^^^^^^^^ help: try: `!x` error: this if-then-else expression returns a bool literal --> tests/ui/needless_bool/fixable.rs:185:12 diff --git a/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs b/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs index 159cbe49828f..24ce5786b910 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs +++ b/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs @@ -1,6 +1,6 @@ //@no-rustfix: overlapping suggestions #![warn(clippy::needless_for_each)] -#![allow(clippy::needless_return, clippy::uninlined_format_args)] +#![allow(clippy::needless_return)] fn main() { let v: Vec = Vec::new(); @@ -11,7 +11,22 @@ fn main() { if *v == 10 { return; } else { - println!("{}", v); + println!("{v}"); } }); } + +fn issue9912() { + let mut i = 0; + // Changing this to a `for` loop would break type inference + [].iter().for_each(move |_: &i32| { + //~^ needless_for_each + i += 1; + }); + + // Changing this would actually be okay, but we still suggest `MaybeIncorrect`ly + [1i32].iter().for_each(move |_: &i32| { + //~^ needless_for_each + i += 1; + }); +} diff --git a/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr index 3a3a240c5a3a..6bc56db68a0e 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr +++ b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr @@ -19,7 +19,7 @@ LL + LL + if *v == 10 { LL + return; LL + } else { -LL + println!("{}", v); +LL + println!("{v}"); LL + } LL + } | @@ -29,5 +29,39 @@ LL - return; LL + continue; | -error: aborting due to 1 previous error +error: needless use of `for_each` + --> tests/ui/needless_for_each_unfixable.rs:22:5 + | +LL | / [].iter().for_each(move |_: &i32| { +LL | | +LL | | i += 1; +LL | | }); + | |_______^ + | +help: try + | +LL ~ for _ in [].iter() { +LL + +LL + i += 1; +LL + } + | + +error: needless use of `for_each` + --> tests/ui/needless_for_each_unfixable.rs:28:5 + | +LL | / [1i32].iter().for_each(move |_: &i32| { +LL | | +LL | | i += 1; +LL | | }); + | |_______^ + | +help: try + | +LL ~ for _ in [1i32].iter() { +LL + +LL + i += 1; +LL + } + | + +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/needless_range_loop.rs b/src/tools/clippy/tests/ui/needless_range_loop.rs index 70cf9fa7369f..ea4591d8b71a 100644 --- a/src/tools/clippy/tests/ui/needless_range_loop.rs +++ b/src/tools/clippy/tests/ui/needless_range_loop.rs @@ -210,3 +210,35 @@ fn needless_loop() { black_box([1, 2, 3, 4, 5, 6, 7, 8][i]); } } + +fn issue_15068() { + let a = vec![vec![0u8; MAX_LEN]; MAX_LEN]; + let b = vec![0u8; MAX_LEN]; + + for i in 0..MAX_LEN { + // no error + let _ = a[0][i]; + let _ = b[i]; + } + + for i in 0..MAX_LEN { + // no error + let _ = a[i][0]; + let _ = b[i]; + } + + for i in 0..MAX_LEN { + // no error + let _ = a[i][b[i] as usize]; + } + + for i in 0..MAX_LEN { + //~^ needless_range_loop + let _ = a[i][i]; + } + + for i in 0..MAX_LEN { + //~^ needless_range_loop + let _ = a[0][i]; + } +} diff --git a/src/tools/clippy/tests/ui/needless_range_loop.stderr b/src/tools/clippy/tests/ui/needless_range_loop.stderr index 23c085f9d3b2..33a519d8a80d 100644 --- a/src/tools/clippy/tests/ui/needless_range_loop.stderr +++ b/src/tools/clippy/tests/ui/needless_range_loop.stderr @@ -168,5 +168,29 @@ LL - for i in 0..vec.len() { LL + for (i, ) in vec.iter_mut().enumerate() { | -error: aborting due to 14 previous errors +error: the loop variable `i` is used to index `a` + --> tests/ui/needless_range_loop.rs:235:14 + | +LL | for i in 0..MAX_LEN { + | ^^^^^^^^^^ + | +help: consider using an iterator and enumerate() + | +LL - for i in 0..MAX_LEN { +LL + for (i, ) in a.iter().enumerate().take(MAX_LEN) { + | + +error: the loop variable `i` is only used to index `a` + --> tests/ui/needless_range_loop.rs:240:14 + | +LL | for i in 0..MAX_LEN { + | ^^^^^^^^^^ + | +help: consider using an iterator + | +LL - for i in 0..MAX_LEN { +LL + for in a.iter().take(MAX_LEN) { + | + +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs index cacce9a7d1cb..f03f74dfafe2 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool.rs +++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs @@ -182,14 +182,12 @@ fn issue_5794() { if !b == true {} //~^ nonminimal_bool //~| bool_comparison - //~| bool_comparison if !b != true {} //~^ nonminimal_bool //~| bool_comparison if true == !b {} //~^ nonminimal_bool //~| bool_comparison - //~| bool_comparison if true != !b {} //~^ nonminimal_bool //~| bool_comparison diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr index c20412974b20..6a20b9216da5 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr +++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr @@ -154,98 +154,86 @@ error: this boolean expression can be simplified LL | if !b == true {} | ^^^^^^^^^^ help: try: `b != true` -error: this comparison might be written more concisely - --> tests/ui/nonminimal_bool.rs:182:8 - | -LL | if !b == true {} - | ^^^^^^^^^^ help: try simplifying it as shown: `b != true` - | - = note: `-D clippy::bool-comparison` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` - error: equality checks against true are unnecessary --> tests/ui/nonminimal_bool.rs:182:8 | LL | if !b == true {} - | ^^^^^^^^^^ help: try simplifying it as shown: `!b` + | ^^^^^^^^^^ help: try: `!b` + | + = note: `-D clippy::bool-comparison` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:186:8 + --> tests/ui/nonminimal_bool.rs:185:8 | LL | if !b != true {} | ^^^^^^^^^^ help: try: `b == true` error: inequality checks against true can be replaced by a negation - --> tests/ui/nonminimal_bool.rs:186:8 + --> tests/ui/nonminimal_bool.rs:185:8 | LL | if !b != true {} - | ^^^^^^^^^^ help: try simplifying it as shown: `b` + | ^^^^^^^^^^ help: try: `b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:189:8 + --> tests/ui/nonminimal_bool.rs:188:8 | LL | if true == !b {} | ^^^^^^^^^^ help: try: `true != b` -error: this comparison might be written more concisely - --> tests/ui/nonminimal_bool.rs:189:8 - | -LL | if true == !b {} - | ^^^^^^^^^^ help: try simplifying it as shown: `true != b` - error: equality checks against true are unnecessary - --> tests/ui/nonminimal_bool.rs:189:8 + --> tests/ui/nonminimal_bool.rs:188:8 | LL | if true == !b {} - | ^^^^^^^^^^ help: try simplifying it as shown: `!b` + | ^^^^^^^^^^ help: try: `!b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:193:8 + --> tests/ui/nonminimal_bool.rs:191:8 | LL | if true != !b {} | ^^^^^^^^^^ help: try: `true == b` error: inequality checks against true can be replaced by a negation - --> tests/ui/nonminimal_bool.rs:193:8 + --> tests/ui/nonminimal_bool.rs:191:8 | LL | if true != !b {} - | ^^^^^^^^^^ help: try simplifying it as shown: `b` + | ^^^^^^^^^^ help: try: `b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:196:8 + --> tests/ui/nonminimal_bool.rs:194:8 | LL | if !b == !c {} | ^^^^^^^^ help: try: `b == c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:198:8 + --> tests/ui/nonminimal_bool.rs:196:8 | LL | if !b != !c {} | ^^^^^^^^ help: try: `b != c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:214:8 + --> tests/ui/nonminimal_bool.rs:212:8 | LL | if !(a < 2.0 && !b) { | ^^^^^^^^^^^^^^^^ help: try: `a >= 2.0 || b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:233:12 + --> tests/ui/nonminimal_bool.rs:231:12 | LL | if !(matches!(ty, TyKind::Ref(_, _, _)) && !is_mutable(&expr)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!matches!(ty, TyKind::Ref(_, _, _)) || is_mutable(&expr)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:253:8 + --> tests/ui/nonminimal_bool.rs:251:8 | LL | if !S != true {} | ^^^^^^^^^^ help: try: `S == true` error: inequality checks against true can be replaced by a negation - --> tests/ui/nonminimal_bool.rs:253:8 + --> tests/ui/nonminimal_bool.rs:251:8 | LL | if !S != true {} - | ^^^^^^^^^^ help: try simplifying it as shown: `!!S` + | ^^^^^^^^^^ help: try: `!!S` -error: aborting due to 33 previous errors +error: aborting due to 31 previous errors diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed index 55c1b8f110ce..340be7c7e932 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed @@ -102,4 +102,13 @@ fn option_map_unit_fn() { //~^ option_map_unit_fn } +fn issue15568() { + unsafe fn f(_: u32) {} + let x = Some(3); + if let Some(x) = x { unsafe { f(x) } } + //~^ option_map_unit_fn + if let Some(x) = x { unsafe { f(x) } } + //~^ option_map_unit_fn +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs index 5ed47e4c60b5..d902c87379b7 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs @@ -102,4 +102,13 @@ fn option_map_unit_fn() { //~^ option_map_unit_fn } +fn issue15568() { + unsafe fn f(_: u32) {} + let x = Some(3); + x.map(|x| unsafe { f(x) }); + //~^ option_map_unit_fn + x.map(|x| unsafe { { f(x) } }); + //~^ option_map_unit_fn +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr index 3f7abae34eea..2405aa9a7ccf 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr @@ -153,5 +153,21 @@ LL | option().map(|value| println!("{:?}", value)); | | | help: try: `if let Some(value) = option() { println!("{:?}", value) }` -error: aborting due to 19 previous errors +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` + --> tests/ui/option_map_unit_fn_fixable.rs:108:5 + | +LL | x.map(|x| unsafe { f(x) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: try: `if let Some(x) = x { unsafe { f(x) } }` + +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` + --> tests/ui/option_map_unit_fn_fixable.rs:110:5 + | +LL | x.map(|x| unsafe { { f(x) } }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: try: `if let Some(x) = x { unsafe { f(x) } }` + +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.fixed b/src/tools/clippy/tests/ui/or_then_unwrap.fixed index ba9beef57afa..9660b82fe7d6 100644 --- a/src/tools/clippy/tests/ui/or_then_unwrap.fixed +++ b/src/tools/clippy/tests/ui/or_then_unwrap.fixed @@ -28,6 +28,12 @@ fn main() { // //~^^ or_then_unwrap + // Call with macro should preserve the macro call rather than expand it + let option: Option> = None; + let _ = option.unwrap_or(vec!["fallback"]); // should trigger lint + // + //~^^ or_then_unwrap + // as part of a method chain let option: Option<&str> = None; let _ = option.map(|v| v).unwrap_or("fallback").to_string().chars(); // should trigger lint diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.rs b/src/tools/clippy/tests/ui/or_then_unwrap.rs index fac90249a243..c38733521164 100644 --- a/src/tools/clippy/tests/ui/or_then_unwrap.rs +++ b/src/tools/clippy/tests/ui/or_then_unwrap.rs @@ -28,6 +28,12 @@ fn main() { // //~^^ or_then_unwrap + // Call with macro should preserve the macro call rather than expand it + let option: Option> = None; + let _ = option.or(Some(vec!["fallback"])).unwrap(); // should trigger lint + // + //~^^ or_then_unwrap + // as part of a method chain let option: Option<&str> = None; let _ = option.map(|v| v).or(Some("fallback")).unwrap().to_string().chars(); // should trigger lint diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.stderr b/src/tools/clippy/tests/ui/or_then_unwrap.stderr index 1160498c6053..3e66b15edbd6 100644 --- a/src/tools/clippy/tests/ui/or_then_unwrap.stderr +++ b/src/tools/clippy/tests/ui/or_then_unwrap.stderr @@ -14,10 +14,16 @@ LL | let _ = result.or::<&str>(Ok("fallback")).unwrap(); // should trigger l | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")` error: found `.or(Some(…)).unwrap()` - --> tests/ui/or_then_unwrap.rs:33:31 + --> tests/ui/or_then_unwrap.rs:33:20 + | +LL | let _ = option.or(Some(vec!["fallback"])).unwrap(); // should trigger lint + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or(vec!["fallback"])` + +error: found `.or(Some(…)).unwrap()` + --> tests/ui/or_then_unwrap.rs:39:31 | LL | let _ = option.map(|v| v).or(Some("fallback")).unwrap().to_string().chars(); // should trigger lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/panicking_macros.rs b/src/tools/clippy/tests/ui/panicking_macros.rs index 65854d7eb4bf..b044be7d54ac 100644 --- a/src/tools/clippy/tests/ui/panicking_macros.rs +++ b/src/tools/clippy/tests/ui/panicking_macros.rs @@ -31,6 +31,20 @@ fn panic() { let b = a + 2; } +const fn panic_const() { + let a = 2; + panic!(); + //~^ panic + + panic!("message"); + //~^ panic + + panic!("{} {}", "panic with", "multiple arguments"); + //~^ panic + + let b = a + 2; +} + fn todo() { let a = 2; todo!(); @@ -114,6 +128,7 @@ fn debug_assert_msg() { fn main() { panic(); + panic_const(); todo(); unimplemented(); unreachable(); diff --git a/src/tools/clippy/tests/ui/panicking_macros.stderr b/src/tools/clippy/tests/ui/panicking_macros.stderr index 03e459e4ec6e..7b767ae0f65b 100644 --- a/src/tools/clippy/tests/ui/panicking_macros.stderr +++ b/src/tools/clippy/tests/ui/panicking_macros.stderr @@ -19,9 +19,27 @@ error: `panic` should not be present in production code LL | panic!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `todo` should not be present in production code +error: `panic` should not be present in production code --> tests/ui/panicking_macros.rs:36:5 | +LL | panic!(); + | ^^^^^^^^ + +error: `panic` should not be present in production code + --> tests/ui/panicking_macros.rs:39:5 + | +LL | panic!("message"); + | ^^^^^^^^^^^^^^^^^ + +error: `panic` should not be present in production code + --> tests/ui/panicking_macros.rs:42:5 + | +LL | panic!("{} {}", "panic with", "multiple arguments"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `todo` should not be present in production code + --> tests/ui/panicking_macros.rs:50:5 + | LL | todo!(); | ^^^^^^^ | @@ -29,19 +47,19 @@ LL | todo!(); = help: to override `-D warnings` add `#[allow(clippy::todo)]` error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:39:5 + --> tests/ui/panicking_macros.rs:53:5 | LL | todo!("message"); | ^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:42:5 + --> tests/ui/panicking_macros.rs:56:5 | LL | todo!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:50:5 + --> tests/ui/panicking_macros.rs:64:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ @@ -50,19 +68,19 @@ LL | unimplemented!(); = help: to override `-D warnings` add `#[allow(clippy::unimplemented)]` error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:53:5 + --> tests/ui/panicking_macros.rs:67:5 | LL | unimplemented!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:56:5 + --> tests/ui/panicking_macros.rs:70:5 | LL | unimplemented!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:64:5 + --> tests/ui/panicking_macros.rs:78:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ @@ -71,40 +89,40 @@ LL | unreachable!(); = help: to override `-D warnings` add `#[allow(clippy::unreachable)]` error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:67:5 + --> tests/ui/panicking_macros.rs:81:5 | LL | unreachable!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:70:5 + --> tests/ui/panicking_macros.rs:84:5 | LL | unreachable!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:78:5 + --> tests/ui/panicking_macros.rs:92:5 | LL | panic!(); | ^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:81:5 + --> tests/ui/panicking_macros.rs:95:5 | LL | todo!(); | ^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:84:5 + --> tests/ui/panicking_macros.rs:98:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:87:5 + --> tests/ui/panicking_macros.rs:101:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ -error: aborting due to 16 previous errors +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/print_literal.fixed b/src/tools/clippy/tests/ui/print_literal.fixed index ebfe19c700ee..26139f9b6710 100644 --- a/src/tools/clippy/tests/ui/print_literal.fixed +++ b/src/tools/clippy/tests/ui/print_literal.fixed @@ -105,3 +105,16 @@ fn issue_14930() { println!("Hello x is {0:2$.1$}", 0.01, 2, 3); //~^ print_literal } + +fn issue_15576() { + println!("Hello x is {1:.*}", 5, 0.01); + //~^ print_literal + + println!("Hello x is {:.p$}", 0.01, p = 5); + //~^ print_literal + + println!( + "Hello name: x is {1:.*} (which {1} with {0} places)", 5, 0.01 + ); + //~^^ print_literal +} diff --git a/src/tools/clippy/tests/ui/print_literal.rs b/src/tools/clippy/tests/ui/print_literal.rs index 8f3d9be06985..7c4cf028e84c 100644 --- a/src/tools/clippy/tests/ui/print_literal.rs +++ b/src/tools/clippy/tests/ui/print_literal.rs @@ -106,3 +106,17 @@ fn issue_14930() { println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); //~^ print_literal } + +fn issue_15576() { + println!("Hello {} is {2:.*}", "x", 5, 0.01); + //~^ print_literal + + println!("Hello {} is {:.p$}", "x", 0.01, p = 5); + //~^ print_literal + + println!( + "Hello {}: {2} is {3:.*} (which {3} with {1} places)", + "name", 5, "x", 0.01 + ); + //~^^ print_literal +} diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr index 1c378017d151..c136f52800f6 100644 --- a/src/tools/clippy/tests/ui/print_literal.stderr +++ b/src/tools/clippy/tests/ui/print_literal.stderr @@ -277,5 +277,41 @@ LL - println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); LL + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); | -error: aborting due to 22 previous errors +error: literal with an empty format string + --> tests/ui/print_literal.rs:111:36 + | +LL | println!("Hello {} is {2:.*}", "x", 5, 0.01); + | ^^^ + | +help: try + | +LL - println!("Hello {} is {2:.*}", "x", 5, 0.01); +LL + println!("Hello x is {1:.*}", 5, 0.01); + | + +error: literal with an empty format string + --> tests/ui/print_literal.rs:114:36 + | +LL | println!("Hello {} is {:.p$}", "x", 0.01, p = 5); + | ^^^ + | +help: try + | +LL - println!("Hello {} is {:.p$}", "x", 0.01, p = 5); +LL + println!("Hello x is {:.p$}", 0.01, p = 5); + | + +error: literal with an empty format string + --> tests/ui/print_literal.rs:119:9 + | +LL | "name", 5, "x", 0.01 + | ^^^^^^^^^^^^^^ + | +help: try + | +LL - "Hello {}: {2} is {3:.*} (which {3} with {1} places)", +LL + "Hello name: x is {1:.*} (which {1} with {0} places)", 5, 0.01 + | + +error: aborting due to 25 previous errors diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed index 78e1ceb480a5..4457878b6faf 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed @@ -229,3 +229,9 @@ fn issue15283() { //~^ ptr_as_ptr } } + +fn issue15232() { + let mut b = Box::new(0i32); + let _ptr = std::ptr::addr_of_mut!(*b).cast::<()>(); + //~^ ptr_as_ptr +} diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs index 70732cf0a6c1..9124fc912d2c 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs @@ -229,3 +229,9 @@ fn issue15283() { //~^ ptr_as_ptr } } + +fn issue15232() { + let mut b = Box::new(0i32); + let _ptr = std::ptr::addr_of_mut!(*b) as *mut (); + //~^ ptr_as_ptr +} diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr index c0a2a4b6d204..af21c1e35f52 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr @@ -199,5 +199,11 @@ error: `as` casting between raw pointers without changing their constness LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::()` -error: aborting due to 33 previous errors +error: `as` casting between raw pointers without changing their constness + --> tests/ui/ptr_as_ptr.rs:235:16 + | +LL | let _ptr = std::ptr::addr_of_mut!(*b) as *mut (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `std::ptr::addr_of_mut!(*b).cast::<()>()` + +error: aborting due to 34 previous errors diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed index 79bfae1f7ebb..cf57de53d9f3 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed @@ -106,3 +106,9 @@ fn issue14621() { let _ = std::ptr::addr_of_mut!(local).cast_const(); //~^ ptr_cast_constness } + +fn issue11317() { + let r = &0_u32; + let _ptr: *mut u32 = (r as *const u32).cast_mut(); + //~^ ptr_cast_constness +} diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.rs b/src/tools/clippy/tests/ui/ptr_cast_constness.rs index f6590dabd5b8..ea53a0fa8c50 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.rs +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.rs @@ -106,3 +106,9 @@ fn issue14621() { let _ = std::ptr::addr_of_mut!(local) as *const _; //~^ ptr_cast_constness } + +fn issue11317() { + let r = &0_u32; + let _ptr: *mut u32 = r as *const _ as *mut _; + //~^ ptr_cast_constness +} diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr index 0b1644168ff5..4adb5cc5ad7f 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr @@ -89,5 +89,11 @@ error: `as` casting between raw pointers while changing only its constness LL | let _ = std::ptr::addr_of_mut!(local) as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `std::ptr::addr_of_mut!(local).cast_const()` -error: aborting due to 14 previous errors +error: `as` casting between raw pointers while changing only its constness + --> tests/ui/ptr_cast_constness.rs:112:26 + | +LL | let _ptr: *mut u32 = r as *const _ as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(r as *const u32).cast_mut()` + +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed index 7eb53e733ad5..7308e78aae26 100644 --- a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed +++ b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed @@ -86,3 +86,8 @@ fn main() { unit_fn_block() } + +pub fn issue15388() { + #[rustfmt::skip] + {0; 0}; +} diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.rs b/src/tools/clippy/tests/ui/semicolon_inside_block.rs index 9fa5b117194d..467bf4d779f2 100644 --- a/src/tools/clippy/tests/ui/semicolon_inside_block.rs +++ b/src/tools/clippy/tests/ui/semicolon_inside_block.rs @@ -86,3 +86,8 @@ fn main() { unit_fn_block() } + +pub fn issue15388() { + #[rustfmt::skip] + {0; 0}; +} diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.fixed new file mode 100644 index 000000000000..5b93a91da003 --- /dev/null +++ b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.fixed @@ -0,0 +1,11 @@ +// Test when the feature `stmt_expr_attributes` is enabled + +#![feature(stmt_expr_attributes)] +#![allow(clippy::no_effect)] +#![warn(clippy::semicolon_inside_block)] + +pub fn issue15388() { + #[rustfmt::skip] + {0; 0;} + //~^ semicolon_inside_block +} diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.rs b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.rs new file mode 100644 index 000000000000..aa2c0cb50299 --- /dev/null +++ b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.rs @@ -0,0 +1,11 @@ +// Test when the feature `stmt_expr_attributes` is enabled + +#![feature(stmt_expr_attributes)] +#![allow(clippy::no_effect)] +#![warn(clippy::semicolon_inside_block)] + +pub fn issue15388() { + #[rustfmt::skip] + {0; 0}; + //~^ semicolon_inside_block +} diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.stderr b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.stderr new file mode 100644 index 000000000000..5bb91915a5fd --- /dev/null +++ b/src/tools/clippy/tests/ui/semicolon_inside_block_stmt_expr_attrs.stderr @@ -0,0 +1,16 @@ +error: consider moving the `;` inside the block for consistent formatting + --> tests/ui/semicolon_inside_block_stmt_expr_attrs.rs:9:5 + | +LL | {0; 0}; + | ^^^^^^^ + | + = note: `-D clippy::semicolon-inside-block` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::semicolon_inside_block)]` +help: put the `;` here + | +LL - {0; 0}; +LL + {0; 0;} + | + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed index 603ab0accb0b..c27cec558242 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed +++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed @@ -89,3 +89,10 @@ fn msrv_1_76(_: std::net::IpAddr) {} #[clippy::msrv = "1.77"] fn msrv_1_77(_: core::net::IpAddr) {} //~^ std_instead_of_core + +#[warn(clippy::alloc_instead_of_core)] +fn issue15579() { + use std::alloc; + + let layout = alloc::Layout::new::(); +} diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs index b6d4abad9f8f..7d53f7fc3072 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.rs +++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs @@ -89,3 +89,10 @@ fn msrv_1_76(_: std::net::IpAddr) {} #[clippy::msrv = "1.77"] fn msrv_1_77(_: std::net::IpAddr) {} //~^ std_instead_of_core + +#[warn(clippy::alloc_instead_of_core)] +fn issue15579() { + use std::alloc; + + let layout = alloc::Layout::new::(); +} diff --git a/src/tools/clippy/tests/ui/unit_cmp.rs b/src/tools/clippy/tests/ui/unit_cmp.rs index 93f5b87c3d2a..0a0fe3a1990b 100644 --- a/src/tools/clippy/tests/ui/unit_cmp.rs +++ b/src/tools/clippy/tests/ui/unit_cmp.rs @@ -68,3 +68,20 @@ fn main() { } ); } + +fn issue15559() { + fn foo() {} + assert_eq!( + //~^ unit_cmp + { + 1; + }, + foo() + ); + assert_eq!(foo(), foo()); + //~^ unit_cmp + + // don't lint on explicitly written unit expr + assert_eq!(foo(), ()); + assert_ne!((), ContainsUnit(()).0); +} diff --git a/src/tools/clippy/tests/ui/unit_cmp.stderr b/src/tools/clippy/tests/ui/unit_cmp.stderr index 8f26749fd860..21aa9dce1510 100644 --- a/src/tools/clippy/tests/ui/unit_cmp.stderr +++ b/src/tools/clippy/tests/ui/unit_cmp.stderr @@ -71,5 +71,23 @@ LL | | true; LL | | ); | |_____^ -error: aborting due to 6 previous errors +error: `assert_eq` of unit values detected. This will always succeed + --> tests/ui/unit_cmp.rs:74:5 + | +LL | / assert_eq!( +LL | | +LL | | { +LL | | 1; +LL | | }, +LL | | foo() +LL | | ); + | |_____^ + +error: `assert_eq` of unit values detected. This will always succeed + --> tests/ui/unit_cmp.rs:81:5 + | +LL | assert_eq!(foo(), foo()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.stderr b/src/tools/clippy/tests/ui/unnecessary_clone.stderr index a4fdf09cd5dc..17518e123d12 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_clone.stderr @@ -2,7 +2,7 @@ error: using `.clone()` on a ref-counted pointer --> tests/ui/unnecessary_clone.rs:23:5 | LL | rc.clone(); - | ^^^^^^^^^^ help: try: `Rc::::clone(&rc)` + | ^^^^^^^^^^ help: try: `std::rc::Rc::::clone(&rc)` | = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::clone_on_ref_ptr)]` @@ -11,25 +11,25 @@ error: using `.clone()` on a ref-counted pointer --> tests/ui/unnecessary_clone.rs:28:5 | LL | arc.clone(); - | ^^^^^^^^^^^ help: try: `Arc::::clone(&arc)` + | ^^^^^^^^^^^ help: try: `std::sync::Arc::::clone(&arc)` error: using `.clone()` on a ref-counted pointer --> tests/ui/unnecessary_clone.rs:33:5 | LL | rcweak.clone(); - | ^^^^^^^^^^^^^^ help: try: `Weak::::clone(&rcweak)` + | ^^^^^^^^^^^^^^ help: try: `std::rc::Weak::::clone(&rcweak)` error: using `.clone()` on a ref-counted pointer --> tests/ui/unnecessary_clone.rs:38:5 | LL | arc_weak.clone(); - | ^^^^^^^^^^^^^^^^ help: try: `Weak::::clone(&arc_weak)` + | ^^^^^^^^^^^^^^^^ help: try: `std::sync::Weak::::clone(&arc_weak)` error: using `.clone()` on a ref-counted pointer --> tests/ui/unnecessary_clone.rs:44:33 | LL | let _: Arc = x.clone(); - | ^^^^^^^^^ help: try: `Arc::::clone(&x)` + | ^^^^^^^^^ help: try: `std::sync::Arc::::clone(&x)` error: using `clone` on type `T` which implements the `Copy` trait --> tests/ui/unnecessary_clone.rs:49:5 @@ -56,7 +56,7 @@ error: using `.clone()` on a ref-counted pointer --> tests/ui/unnecessary_clone.rs:108:14 | LL | Some(try_opt!(Some(rc)).clone()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Rc::::clone(&try_opt!(Some(rc)))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::rc::Rc::::clone(&try_opt!(Some(rc)))` error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed index 2081772d06b3..339d4a95084a 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed @@ -9,6 +9,11 @@ )] #![allow(unreachable_patterns, irrefutable_let_patterns, unused)] +struct S { + x: u8, + y: u8, +} + fn main() { // Should be ignored by this lint, as nesting requires more characters. if let &0 | &2 = &0 {} @@ -45,10 +50,6 @@ fn main() { //~^ unnested_or_patterns if let TS(x, ..) | TS(x, 1 | 2) = TS(0, 0) {} //~^ unnested_or_patterns - struct S { - x: u8, - y: u8, - } if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {} //~^ unnested_or_patterns if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} @@ -77,3 +78,19 @@ mod issue9952 { fn or_in_param((x | x | x): i32) {} //~^ unnested_or_patterns } + +fn issue15219() { + struct Foo { + x: u8, + } + + // the original repro + if let Foo { x } | Foo { x } = (Foo { x: 0 }) {} + + // also works with more fields + if let S { x, y } | S { x, y } = (S { x: 0, y: 0 }) {} + + // `y` not triggering the lint doesn't stop the `x` from getting flagged + if let S { y, x: 0 | 1 } = (S { x: 0, y: 1 }) {} + //~^ unnested_or_patterns +} diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.rs b/src/tools/clippy/tests/ui/unnested_or_patterns.rs index 6bf8fce36616..f5c99183b0c5 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns.rs +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.rs @@ -9,6 +9,11 @@ )] #![allow(unreachable_patterns, irrefutable_let_patterns, unused)] +struct S { + x: u8, + y: u8, +} + fn main() { // Should be ignored by this lint, as nesting requires more characters. if let &0 | &2 = &0 {} @@ -45,10 +50,6 @@ fn main() { //~^ unnested_or_patterns if let TS(x, ..) | TS(x, 1) | TS(x, 2) = TS(0, 0) {} //~^ unnested_or_patterns - struct S { - x: u8, - y: u8, - } if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} //~^ unnested_or_patterns if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} @@ -77,3 +78,19 @@ mod issue9952 { fn or_in_param((x | (x | x)): i32) {} //~^ unnested_or_patterns } + +fn issue15219() { + struct Foo { + x: u8, + } + + // the original repro + if let Foo { x } | Foo { x } = (Foo { x: 0 }) {} + + // also works with more fields + if let S { x, y } | S { x, y } = (S { x: 0, y: 0 }) {} + + // `y` not triggering the lint doesn't stop the `x` from getting flagged + if let S { y, x: 0 } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} + //~^ unnested_or_patterns +} diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr index c805dc992b1c..d2b617c322c4 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr @@ -1,5 +1,5 @@ error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:16:12 + --> tests/ui/unnested_or_patterns.rs:21:12 | LL | if let box 0 | box 2 = Box::new(0) {} | ^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + if let box (0 | 2) = Box::new(0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:18:12 + --> tests/ui/unnested_or_patterns.rs:23:12 | LL | if let box ((0 | 1)) | box (2 | 3) | box 4 = Box::new(0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:21:12 + --> tests/ui/unnested_or_patterns.rs:26:12 | LL | if let Some(1) | C0 | Some(2) = None {} | ^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + if let Some(1 | 2) | C0 = None {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:23:12 + --> tests/ui/unnested_or_patterns.rs:28:12 | LL | if let &mut 0 | &mut 2 = &mut 0 {} | ^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + if let &mut (0 | 2) = &mut 0 {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:25:12 + --> tests/ui/unnested_or_patterns.rs:30:12 | LL | if let x @ 0 | x @ 2 = 0 {} | ^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + if let x @ (0 | 2) = 0 {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:27:12 + --> tests/ui/unnested_or_patterns.rs:32:12 | LL | if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + if let (0, 1 | 2 | 3) = (0, 0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:29:12 + --> tests/ui/unnested_or_patterns.rs:34:12 | LL | if let (1, 0) | (2, 0) | (3, 0) = (0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + if let (1 | 2 | 3, 0) = (0, 0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:31:12 + --> tests/ui/unnested_or_patterns.rs:36:12 | LL | if let (x, ..) | (x, 1) | (x, 2) = (0, 1) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + if let (x, ..) | (x, 1 | 2) = (0, 1) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:33:12 + --> tests/ui/unnested_or_patterns.rs:38:12 | LL | if let [0] | [1] = [0] {} | ^^^^^^^^^ @@ -109,7 +109,7 @@ LL + if let [0 | 1] = [0] {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:35:12 + --> tests/ui/unnested_or_patterns.rs:40:12 | LL | if let [x, 0] | [x, 1] = [0, 1] {} | ^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + if let [x, 0 | 1] = [0, 1] {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:37:12 + --> tests/ui/unnested_or_patterns.rs:42:12 | LL | if let [x, 0] | [x, 1] | [x, 2] = [0, 1] {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + if let [x, 0 | 1 | 2] = [0, 1] {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:39:12 + --> tests/ui/unnested_or_patterns.rs:44:12 | LL | if let [x, ..] | [x, 1] | [x, 2] = [0, 1] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + if let [x, ..] | [x, 1 | 2] = [0, 1] {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:42:12 + --> tests/ui/unnested_or_patterns.rs:47:12 | LL | if let TS(0, x) | TS(1, x) = TS(0, 0) {} | ^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + if let TS(0 | 1, x) = TS(0, 0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:44:12 + --> tests/ui/unnested_or_patterns.rs:49:12 | LL | if let TS(1, 0) | TS(2, 0) | TS(3, 0) = TS(0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + if let TS(1 | 2 | 3, 0) = TS(0, 0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:46:12 + --> tests/ui/unnested_or_patterns.rs:51:12 | LL | if let TS(x, ..) | TS(x, 1) | TS(x, 2) = TS(0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + if let TS(x, ..) | TS(x, 1 | 2) = TS(0, 0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:52:12 + --> tests/ui/unnested_or_patterns.rs:53:12 | LL | if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:64:12 + --> tests/ui/unnested_or_patterns.rs:65:12 | LL | if let [1] | [53] = [0] {} | ^^^^^^^^^^ @@ -205,7 +205,7 @@ LL + if let [1 | 53] = [0] {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:70:13 + --> tests/ui/unnested_or_patterns.rs:71:13 | LL | let (0 | (1 | _)) = 0; | ^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL + let (0 | 1 | _) = 0; | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:73:16 + --> tests/ui/unnested_or_patterns.rs:74:16 | LL | if let (0 | (1 | _)) = 0 {} | ^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL + if let (0 | 1 | _) = 0 {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:77:20 + --> tests/ui/unnested_or_patterns.rs:78:20 | LL | fn or_in_param((x | (x | x)): i32) {} | ^^^^^^^^^^^^^ @@ -240,5 +240,17 @@ LL - fn or_in_param((x | (x | x)): i32) {} LL + fn or_in_param((x | x | x): i32) {} | -error: aborting due to 20 previous errors +error: unnested or-patterns + --> tests/ui/unnested_or_patterns.rs:94:12 + | +LL | if let S { y, x: 0 } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL - if let S { y, x: 0 } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} +LL + if let S { y, x: 0 | 1 } = (S { x: 0, y: 1 }) {} + | + +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed index def8ef86e3c5..8e12bd2c8c7b 100644 --- a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed +++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed @@ -127,14 +127,10 @@ mod issue14577 { trait Unit {} impl Unit for () {} - fn run(f: impl FnOnce() -> R) { - f(); - } - #[allow(dependency_on_unit_never_type_fallback)] fn bar() { - run(|| { todo!() }); //~[edition2021]^ unused_unit + panic!() } struct UnitStruct; @@ -150,3 +146,24 @@ mod pr14962 { type UnusedParensButNoUnit = Box; } + +mod issue15035 { + + trait Convert { + fn from(value: T) -> Self; + } + + impl Convert for () { + fn from(_value: u64) -> Self {} + } + + fn handle>(value: u64) -> T { + Convert::from(value) + } + + pub fn f() -> Option { + let result: Result = Err(42); + // the `-> ()` is required for the inference of `handle`'s return type + result.map_err(|err| -> () { handle(err) }).ok() + } +} diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr index 13cc20d4d7ad..9ad3c2df915e 100644 --- a/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr +++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr @@ -119,10 +119,10 @@ LL | fn test3()-> (){} | ^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:136:15 + --> tests/ui/unused_unit.rs:131:13 | -LL | run(|| -> () { todo!() }); - | ^^^^^^ help: remove the `-> ()` +LL | fn bar() -> () { + | ^^^^^^ help: remove the `-> ()` error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed index f908b958b191..688d2fe9afa2 100644 --- a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed +++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed @@ -127,14 +127,10 @@ mod issue14577 { trait Unit {} impl Unit for () {} - fn run(f: impl FnOnce() -> R) { - f(); - } - #[allow(dependency_on_unit_never_type_fallback)] - fn bar() { - run(|| -> () { todo!() }); + fn bar() -> () { //~[edition2021]^ unused_unit + panic!() } struct UnitStruct; @@ -150,3 +146,24 @@ mod pr14962 { type UnusedParensButNoUnit = Box; } + +mod issue15035 { + + trait Convert { + fn from(value: T) -> Self; + } + + impl Convert for () { + fn from(_value: u64) -> Self {} + } + + fn handle>(value: u64) -> T { + Convert::from(value) + } + + pub fn f() -> Option { + let result: Result = Err(42); + // the `-> ()` is required for the inference of `handle`'s return type + result.map_err(|err| -> () { handle(err) }).ok() + } +} diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs index 7298ec40cc28..31e980f2655c 100644 --- a/src/tools/clippy/tests/ui/unused_unit.rs +++ b/src/tools/clippy/tests/ui/unused_unit.rs @@ -127,14 +127,10 @@ mod issue14577 { trait Unit {} impl Unit for () {} - fn run(f: impl FnOnce() -> R) { - f(); - } - #[allow(dependency_on_unit_never_type_fallback)] - fn bar() { - run(|| -> () { todo!() }); + fn bar() -> () { //~[edition2021]^ unused_unit + panic!() } struct UnitStruct; @@ -150,3 +146,24 @@ mod pr14962 { type UnusedParensButNoUnit = Box; } + +mod issue15035 { + + trait Convert { + fn from(value: T) -> Self; + } + + impl Convert for () { + fn from(_value: u64) -> Self {} + } + + fn handle>(value: u64) -> T { + Convert::from(value) + } + + pub fn f() -> Option { + let result: Result = Err(42); + // the `-> ()` is required for the inference of `handle`'s return type + result.map_err(|err| -> () { handle(err) }).ok() + } +} diff --git a/src/tools/clippy/tests/ui/unwrap_in_result.rs b/src/tools/clippy/tests/ui/unwrap_in_result.rs index 4e872c67b423..70c28fe54f37 100644 --- a/src/tools/clippy/tests/ui/unwrap_in_result.rs +++ b/src/tools/clippy/tests/ui/unwrap_in_result.rs @@ -1,4 +1,5 @@ #![warn(clippy::unwrap_in_result)] +#![allow(clippy::ok_expect)] struct A; @@ -20,10 +21,9 @@ impl A { // should be detected fn bad_divisible_by_3(i_str: String) -> Result { - //~^ unwrap_in_result - // checks whether a string represents a number divisible by 3 let i = i_str.parse::().unwrap(); + //~^ unwrap_in_result if i % 3 == 0 { Ok(true) } else { @@ -32,9 +32,8 @@ impl A { } fn example_option_expect(i_str: String) -> Option { + let i = i_str.parse::().ok().expect("not a number"); //~^ unwrap_in_result - - let i = i_str.parse::().expect("not a number"); if i % 3 == 0 { return Some(true); } @@ -42,13 +41,66 @@ impl A { } fn in_closure(a: Option) -> Option { - //~^ unwrap_in_result + // No lint inside a closure let c = || a.unwrap(); - Some(c()) + + // But lint outside + let a = c().then_some(true); + let _ = a.unwrap(); + //~^ unwrap_in_result + + None + } + + const fn in_const_inside_fn() -> bool { + const A: bool = { + const fn inner(b: Option) -> Option { + Some(b.unwrap()) + //~^ unwrap_in_result + } + + // No lint inside `const` + inner(Some(true)).unwrap() + }; + A + } + + fn in_static_inside_fn() -> bool { + static A: bool = { + const fn inner(b: Option) -> Option { + Some(b.unwrap()) + //~^ unwrap_in_result + } + + // No lint inside `static` + inner(Some(true)).unwrap() + }; + A } } -fn main() { - A::bad_divisible_by_3("3".to_string()); - A::good_divisible_by_3("3".to_string()); +macro_rules! mac { + () => { + Option::unwrap(Some(3)) + }; +} + +fn type_relative_unwrap() -> Option<()> { + _ = Option::unwrap(Some(3)); + //~^ unwrap_in_result + + // Do not lint macro output + _ = mac!(); + + None +} + +fn main() -> Result<(), ()> { + A::bad_divisible_by_3("3".to_string()).unwrap(); + //~^ unwrap_in_result + A::good_divisible_by_3("3".to_string()).unwrap(); + //~^ unwrap_in_result + Result::unwrap(A::good_divisible_by_3("3".to_string())); + //~^ unwrap_in_result + Ok(()) } diff --git a/src/tools/clippy/tests/ui/unwrap_in_result.stderr b/src/tools/clippy/tests/ui/unwrap_in_result.stderr index 5e3eab813e07..804b44246dc7 100644 --- a/src/tools/clippy/tests/ui/unwrap_in_result.stderr +++ b/src/tools/clippy/tests/ui/unwrap_in_result.stderr @@ -1,55 +1,107 @@ -error: used unwrap or expect in a function that returns result or option - --> tests/ui/unwrap_in_result.rs:22:5 - | -LL | / fn bad_divisible_by_3(i_str: String) -> Result { -... | -LL | | } - | |_____^ - | - = help: unwrap and expect should not be used in a function that returns result or option -note: potential non-recoverable error(s) - --> tests/ui/unwrap_in_result.rs:26:17 +error: `unwrap` used in a function that returns a `Result` + --> tests/ui/unwrap_in_result.rs:25:17 | LL | let i = i_str.parse::().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: in this function signature + --> tests/ui/unwrap_in_result.rs:23:45 + | +LL | fn bad_divisible_by_3(i_str: String) -> Result { + | ^^^^^^^^^^^^^^^^^^^^ + = help: consider using the `?` operator or calling the `.map_err()` method = note: `-D clippy::unwrap-in-result` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unwrap_in_result)]` -error: used unwrap or expect in a function that returns result or option - --> tests/ui/unwrap_in_result.rs:34:5 +error: `expect` used in a function that returns an `Option` + --> tests/ui/unwrap_in_result.rs:35:17 | -LL | / fn example_option_expect(i_str: String) -> Option { -LL | | -LL | | -LL | | let i = i_str.parse::().expect("not a number"); -... | -LL | | None -LL | | } - | |_____^ +LL | let i = i_str.parse::().ok().expect("not a number"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: unwrap and expect should not be used in a function that returns result or option -note: potential non-recoverable error(s) - --> tests/ui/unwrap_in_result.rs:37:17 +note: in this function signature + --> tests/ui/unwrap_in_result.rs:34:48 | -LL | let i = i_str.parse::().expect("not a number"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn example_option_expect(i_str: String) -> Option { + | ^^^^^^^^^^^^ + = help: consider using the `?` operator -error: used unwrap or expect in a function that returns result or option - --> tests/ui/unwrap_in_result.rs:44:5 +error: `unwrap` used in a function that returns an `Option` + --> tests/ui/unwrap_in_result.rs:49:17 | -LL | / fn in_closure(a: Option) -> Option { -LL | | -LL | | let c = || a.unwrap(); -LL | | Some(c()) -LL | | } - | |_____^ +LL | let _ = a.unwrap(); + | ^^^^^^^^^^ | - = help: unwrap and expect should not be used in a function that returns result or option -note: potential non-recoverable error(s) - --> tests/ui/unwrap_in_result.rs:46:20 +note: in this function signature + --> tests/ui/unwrap_in_result.rs:43:39 | -LL | let c = || a.unwrap(); - | ^^^^^^^^^^ +LL | fn in_closure(a: Option) -> Option { + | ^^^^^^^^^^^^ + = help: consider using the `?` operator -error: aborting due to 3 previous errors +error: `unwrap` used in a function that returns an `Option` + --> tests/ui/unwrap_in_result.rs:58:22 + | +LL | Some(b.unwrap()) + | ^^^^^^^^^^ + | +note: in this function signature + --> tests/ui/unwrap_in_result.rs:57:48 + | +LL | const fn inner(b: Option) -> Option { + | ^^^^^^^^^^^^ + = help: consider using the `?` operator + +error: `unwrap` used in a function that returns an `Option` + --> tests/ui/unwrap_in_result.rs:71:22 + | +LL | Some(b.unwrap()) + | ^^^^^^^^^^ + | +note: in this function signature + --> tests/ui/unwrap_in_result.rs:70:48 + | +LL | const fn inner(b: Option) -> Option { + | ^^^^^^^^^^^^ + = help: consider using the `?` operator + +error: `unwrap` used in a function that returns an `Option` + --> tests/ui/unwrap_in_result.rs:89:9 + | +LL | _ = Option::unwrap(Some(3)); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: in this function signature + --> tests/ui/unwrap_in_result.rs:88:30 + | +LL | fn type_relative_unwrap() -> Option<()> { + | ^^^^^^^^^^ + = help: consider using the `?` operator + +error: `unwrap` used in a function that returns a `Result` + --> tests/ui/unwrap_in_result.rs:99:5 + | +LL | A::bad_divisible_by_3("3".to_string()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: in this function signature + --> tests/ui/unwrap_in_result.rs:98:14 + | +LL | fn main() -> Result<(), ()> { + | ^^^^^^^^^^^^^^ + = help: consider using the `?` operator or calling the `.map_err()` method + +error: `unwrap` used in a function that returns a `Result` + --> tests/ui/unwrap_in_result.rs:101:5 + | +LL | A::good_divisible_by_3("3".to_string()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `unwrap` used in a function that returns a `Result` + --> tests/ui/unwrap_in_result.rs:103:5 + | +LL | Result::unwrap(A::good_divisible_by_3("3".to_string())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/vec.fixed index f360a8afadf6..55742459c92c 100644 --- a/src/tools/clippy/tests/ui/vec.fixed +++ b/src/tools/clippy/tests/ui/vec.fixed @@ -242,3 +242,12 @@ fn issue_12101() { for a in &[1, 2] {} //~^ useless_vec } + +fn issue_14531() { + // The lint used to suggest using an array rather than a reference to a slice. + + fn requires_ref_slice(v: &[()]) {} + let v = &[]; + //~^ useless_vec + requires_ref_slice(v); +} diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs index a779d33557cb..fbf7131323c3 100644 --- a/src/tools/clippy/tests/ui/vec.rs +++ b/src/tools/clippy/tests/ui/vec.rs @@ -242,3 +242,12 @@ fn issue_12101() { for a in &(vec![1, 2]) {} //~^ useless_vec } + +fn issue_14531() { + // The lint used to suggest using an array rather than a reference to a slice. + + fn requires_ref_slice(v: &[()]) {} + let v = &vec![]; + //~^ useless_vec + requires_ref_slice(v); +} diff --git a/src/tools/clippy/tests/ui/vec.stderr b/src/tools/clippy/tests/ui/vec.stderr index 806d6617200f..d16c8a8944a2 100644 --- a/src/tools/clippy/tests/ui/vec.stderr +++ b/src/tools/clippy/tests/ui/vec.stderr @@ -127,5 +127,11 @@ error: useless use of `vec!` LL | for a in &(vec![1, 2]) {} | ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` -error: aborting due to 21 previous errors +error: useless use of `vec!` + --> tests/ui/vec.rs:250:13 + | +LL | let v = &vec![]; + | ^^^^^^^ help: you can use a slice directly: `&[]` + +error: aborting due to 22 previous errors diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index 805baf2af6dd..7b19f8658c08 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -49,11 +49,18 @@ new_pr = true # These labels are set when there are unresolved concerns, removed otherwise labels = ["S-waiting-on-concerns"] +# Show differences when a PR is rebased +[range-diff] + +# Amend a review to include a link to what was changed since the review +[review-changes-since] + [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" users_on_vacation = [ "matthiaskrgr", "Manishearth", + "flip1995", ] [assign.owners] diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 89b1b4f84b6b..62fdee987355 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 5519ef1af1fa..b0dc24798b6c 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, ) { - 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>> }, + + /// 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> { + 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 fa84691a46f4..f647f96a9bf3 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) -> 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) -> 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) -> 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 { + match value { + "off" | "no" | "n" | "false" => Some(false), + "on" | "yes" | "y" | "true" => Some(true), + _ => None, + } +} + pub fn opt_str(maybestr: &Option) -> &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 000000000000..de1aea11ade9 --- /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, +} + +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()); + ::write_fmt(&mut s, args).unwrap(); + } +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 867624cc8fa9..89fb8eb4357b 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, testpaths: &TestPaths, revision: Option<&str>) { +pub fn run( + config: Arc, + 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, 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, 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, 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 44ddcb1d2888..16c251c3c9e2 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 509e7e117039..3363127b3ea3 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( + 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 da1e74b4a56b..0aae7eaa39cd 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 88d022b8bbaa..071c0863b7e9 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 90cff6bab4dc..44eb80300c39 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 55043bf4bc26..944879263834 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 083398f92745..b8da6e2ac528 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 40b0ee0a399d..d683a325c866 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 1f16a672a98e..558e9a58697e 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/tests/fail/intrinsics/funnel_shl.rs b/src/tools/miri/tests/fail/intrinsics/funnel_shl.rs new file mode 100644 index 000000000000..40b61f65ebe8 --- /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 000000000000..fc828021b132 --- /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 000000000000..958226563971 --- /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 000000000000..7361df1b4c7a --- /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/pass/intrinsics/integer.rs b/src/tools/miri/tests/pass/intrinsics/integer.rs index 13e7bd8e1b94..8727b6d3c87e 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/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 31169ec59677..34d9ea92629b 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -720,21 +720,19 @@ impl ExtraCheckArg { if !self.auto { return true; } - let ext = match self.lang { - ExtraCheckLang::Py => ".py", - ExtraCheckLang::Cpp => ".cpp", - ExtraCheckLang::Shell => ".sh", - ExtraCheckLang::Js => ".js", + let exts: &[&str] = match self.lang { + ExtraCheckLang::Py => &[".py"], + ExtraCheckLang::Cpp => &[".cpp"], + ExtraCheckLang::Shell => &[".sh"], + ExtraCheckLang::Js => &[".js", ".ts"], ExtraCheckLang::Spellcheck => { - for dir in SPELLCHECK_DIRS { - if Path::new(filepath).starts_with(dir) { - return true; - } + if SPELLCHECK_DIRS.iter().any(|dir| Path::new(filepath).starts_with(dir)) { + return true; } - return false; + &[] } }; - filepath.ends_with(ext) + exts.iter().any(|ext| filepath.ends_with(ext)) } fn has_supported_kind(&self) -> bool { diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs index 305a0b4d2643..6f25ed616fac 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/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs index 642bf5e75762..ada525b6c803 100644 --- a/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs +++ b/tests/codegen-llvm/sanitizer/address-sanitizer-globals-tracking.rs @@ -19,7 +19,7 @@ //@ only-linux // //@ revisions:ASAN ASAN-FAT-LTO -//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static +//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer // [ASAN] no extra compile-flags //@[ASAN-FAT-LTO] compile-flags: -Cprefer-dynamic=false -Clto=fat diff --git a/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs index 22577e2a3c46..77857ca4ccb9 100644 --- a/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs +++ b/tests/codegen-llvm/sanitizer/cfi/add-canonical-jump-tables-flag.rs @@ -1,7 +1,7 @@ // Verifies that "CFI Canonical Jump Tables" module flag is added. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs index a54a6d84a807..6cf9a72b7488 100644 --- a/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs +++ b/tests/codegen-llvm/sanitizer/cfi/add-cfi-normalize-integers-flag.rs @@ -1,7 +1,7 @@ // Verifies that "cfi-normalize-integers" module flag is added. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers +//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -C unsafe-allow-abi-mismatch=sanitizer,sanitizer-cfi-normalize-integers #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs b/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs index 283b8f261029..0bfdbfba5d2e 100644 --- a/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs +++ b/tests/codegen-llvm/sanitizer/cfi/add-enable-split-lto-unit-flag.rs @@ -1,7 +1,7 @@ // Verifies that "EnableSplitLTOUnit" module flag is added. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs b/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs index df65960dfe0b..2a18e30e2b0d 100644 --- a/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs +++ b/tests/codegen-llvm/sanitizer/cfi/dbg-location-on-cfi-blocks.rs @@ -1,7 +1,7 @@ // Verifies that the parent block's debug information are assigned to the inserted cfi block. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -Cdebuginfo=1 +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -Cdebuginfo=1 -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs index 651afb332286..c49438f43186 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks-attr-sanitize-off.rs @@ -1,7 +1,7 @@ // Verifies that pointer type membership tests for indirect calls are omitted. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] #![feature(sanitize)] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs index ebc66a015df6..9cad88f65182 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-checks.rs @@ -1,7 +1,7 @@ // Verifies that pointer type membership tests for indirect calls are emitted. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs index 9bc2e42db0f6..cd9088f58af4 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-attr-cfi-encoding.rs @@ -1,7 +1,7 @@ // Verifies that user-defined CFI encoding for types are emitted. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] #![feature(cfi_encoding, extern_types)] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs index 9048c6a1f183..cf26c17af1ed 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-const-generics.rs @@ -2,7 +2,7 @@ // for const generics. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] #![feature(type_alias_impl_trait)] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs index 8fec275fd064..279350d20c5f 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs @@ -5,7 +5,7 @@ // future. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs index 7e60aafff680..047b532e994e 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs @@ -2,7 +2,7 @@ // for function types. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs index 36d2e8c9f25a..92b2ab32ea03 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-lifetimes.rs @@ -2,7 +2,7 @@ // for lifetimes/regions. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] #![feature(type_alias_impl_trait)] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs index 9d611777ff0b..5de39dc85c17 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs @@ -2,7 +2,7 @@ // self so they can be used as function pointers. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs index a8ba8db1be3b..f5846713bd53 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs @@ -2,7 +2,7 @@ // for paths. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] #![feature(type_alias_impl_trait)] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs index d37bb740f550..ad4fe11d0872 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-pointer-types.rs @@ -2,7 +2,7 @@ // for pointer types. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs index 7d9e4d058727..93845d051954 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs @@ -2,7 +2,7 @@ // for primitive types. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs index 0f97c70f3f92..025aa902658e 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs @@ -2,7 +2,7 @@ // for repr transparent types. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs index bdee3f47a837..76c8150b7785 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-sequence-types.rs @@ -2,7 +2,7 @@ // for sequence types. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs index 55e816178f8f..4fafdd2f040f 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs @@ -2,7 +2,7 @@ // for trait types. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs index c1f3ca61afeb..91351096ca20 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-user-defined-types.rs @@ -2,7 +2,7 @@ // for user-defined types. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] #![feature(extern_types)] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs index 32637b64b3ea..22d518cca744 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-generalized.rs @@ -1,7 +1,7 @@ // Verifies that generalized type metadata for functions are emitted. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs index 51121b0aef1a..7639ce7b1044 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs @@ -1,7 +1,7 @@ // Verifies that normalized and generalized type metadata for functions are emitted. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Zsanitizer-cfi-generalize-pointers -C unsafe-allow-abi-mismatch=sanitizer,sanitizer-cfi-normalize-integers #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs index 1cfdd23006e3..acd72b0ca3cf 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi-normalized.rs @@ -1,7 +1,7 @@ // Verifies that normalized type metadata for functions are emitted. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -C unsafe-allow-abi-mismatch=sanitizer,sanitizer-cfi-normalize-integers #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs index 56ab1ce4b358..fa5cd471466e 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-itanium-cxx-abi.rs @@ -1,7 +1,7 @@ // Verifies that type metadata for functions are emitted. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs index 0e57ce322d12..82873e935b29 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-trait-objects.rs @@ -1,7 +1,7 @@ // Verifies that type metadata identifiers for trait objects are emitted correctly. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs b/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs index b3cb6dfdd37d..893b01676936 100644 --- a/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs +++ b/tests/codegen-llvm/sanitizer/cfi/external_weak_symbols.rs @@ -2,7 +2,7 @@ // emitted correctly. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "bin"] #![feature(linkage)] diff --git a/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs b/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs index 57004da6f8e0..caa2f258f8f2 100644 --- a/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs +++ b/tests/codegen-llvm/sanitizer/cfi/generalize-pointers.rs @@ -1,7 +1,7 @@ // Verifies that pointer types are generalized. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers -Copt-level=0 +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs b/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs index 770ee4e64e08..16f76adafb82 100644 --- a/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs +++ b/tests/codegen-llvm/sanitizer/cfi/normalize-integers.rs @@ -1,7 +1,7 @@ // Verifies that integer types are normalized. // //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Copt-level=0 +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer,sanitizer-cfi-normalize-integers #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs b/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs index a2d0d63cc175..cd8c2c48ea4f 100644 --- a/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs +++ b/tests/codegen-llvm/sanitizer/dataflow-instrument-functions.rs @@ -1,7 +1,7 @@ // Verifies that functions are instrumented. // //@ needs-sanitizer-dataflow -//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow +//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/memory-track-origins.rs b/tests/codegen-llvm/sanitizer/memory-track-origins.rs index 5eb5b356b051..a72e523c4e19 100644 --- a/tests/codegen-llvm/sanitizer/memory-track-origins.rs +++ b/tests/codegen-llvm/sanitizer/memory-track-origins.rs @@ -4,7 +4,7 @@ //@ needs-sanitizer-memory //@ revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO // -//@ compile-flags: -Zsanitizer=memory -Ctarget-feature=-crt-static +//@ compile-flags: -Zsanitizer=memory -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer // [MSAN-0] no extra compile-flags //@[MSAN-1] compile-flags: -Zsanitizer-memory-track-origins=1 //@[MSAN-2] compile-flags: -Zsanitizer-memory-track-origins diff --git a/tests/codegen-llvm/sanitizer/memtag-attr-check.rs b/tests/codegen-llvm/sanitizer/memtag-attr-check.rs index ffe3a2322a20..fc430f3a5700 100644 --- a/tests/codegen-llvm/sanitizer/memtag-attr-check.rs +++ b/tests/codegen-llvm/sanitizer/memtag-attr-check.rs @@ -2,7 +2,7 @@ // applied when enabling the memtag sanitizer. // //@ needs-sanitizer-memtag -//@ compile-flags: -Zsanitizer=memtag -Ctarget-feature=+mte -Copt-level=0 +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer -Zsanitizer=memtag -Ctarget-feature=+mte -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/safestack-attr-check.rs b/tests/codegen-llvm/sanitizer/safestack-attr-check.rs index 050a60333afa..414dd89a5807 100644 --- a/tests/codegen-llvm/sanitizer/safestack-attr-check.rs +++ b/tests/codegen-llvm/sanitizer/safestack-attr-check.rs @@ -1,7 +1,7 @@ // This tests that the safestack attribute is applied when enabling the safe-stack sanitizer. // //@ needs-sanitizer-safestack -//@ compile-flags: -Zsanitizer=safestack -Copt-level=0 +//@ compile-flags: -Zsanitizer=safestack -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] diff --git a/tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs b/tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs index 69771827c3a7..0f43e6b8393d 100644 --- a/tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs +++ b/tests/codegen-llvm/sanitizer/sanitize-off-inlining.rs @@ -1,9 +1,9 @@ // Verifies that sanitize(xyz = "off") attribute prevents inlining when // given sanitizer is enabled, but has no effect on inlining otherwise. -// //@ needs-sanitizer-address //@ needs-sanitizer-leak //@ revisions: ASAN LSAN +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer //@ compile-flags: -Copt-level=3 -Zmir-opt-level=4 -Ctarget-feature=-crt-static //@[ASAN] compile-flags: -Zsanitizer=address //@[LSAN] compile-flags: -Zsanitizer=leak diff --git a/tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs b/tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs index 94945f2b2e6e..61ad0ba7d90d 100644 --- a/tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs +++ b/tests/codegen-llvm/sanitizer/sanitize-off-kasan-asan.rs @@ -2,7 +2,7 @@ // the address sanitizer. // //@ needs-sanitizer-address -//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -Copt-level=0 +//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -Copt-level=0 -C unsafe-allow-abi-mismatch=sanitizer #![crate_type = "lib"] #![feature(sanitize)] diff --git a/tests/codegen-llvm/sanitizer/sanitizer-recover.rs b/tests/codegen-llvm/sanitizer/sanitizer-recover.rs index 6b6593204818..b8a24e31c30b 100644 --- a/tests/codegen-llvm/sanitizer/sanitizer-recover.rs +++ b/tests/codegen-llvm/sanitizer/sanitizer-recover.rs @@ -5,7 +5,7 @@ //@ needs-sanitizer-memory //@ revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO //@ no-prefer-dynamic -// +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer //@ compile-flags: -Ctarget-feature=-crt-static //@[ASAN] compile-flags: -Zsanitizer=address -Copt-level=0 //@[ASAN-RECOVER] compile-flags: -Zsanitizer=address -Zsanitizer-recover=address -Copt-level=0 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 000000000000..9b06f84be488 --- /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 000000000000..4a499cc0a1e2 --- /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 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 000000000000..825cbd158c0a --- /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 625f81fd428e..166e8d5702fc 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 000000000000..0416b1b75b59 --- /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 000000000000..4d1f5430fc63 --- /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 000000000000..93b372d10cbf --- /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 000000000000..803eb8a61dad --- /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/sanitizer-cdylib-link/rmake.rs b/tests/run-make/sanitizer-cdylib-link/rmake.rs index f9d7fd98789e..8ff58594d109 100644 --- a/tests/run-make/sanitizer-cdylib-link/rmake.rs +++ b/tests/run-make/sanitizer-cdylib-link/rmake.rs @@ -8,6 +8,8 @@ //@ needs-sanitizer-support //@ needs-sanitizer-address +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer + use run_make_support::{run_fail, rustc}; fn main() { diff --git a/tests/run-make/sanitizer-dylib-link/rmake.rs b/tests/run-make/sanitizer-dylib-link/rmake.rs index b43420adc72b..bae3240a2364 100644 --- a/tests/run-make/sanitizer-dylib-link/rmake.rs +++ b/tests/run-make/sanitizer-dylib-link/rmake.rs @@ -7,6 +7,8 @@ //@ needs-sanitizer-support //@ needs-sanitizer-address +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer + use run_make_support::{run_fail, rustc}; fn main() { diff --git a/tests/run-make/sanitizer-staticlib-link/rmake.rs b/tests/run-make/sanitizer-staticlib-link/rmake.rs index e38d15a8a3c4..dda926261890 100644 --- a/tests/run-make/sanitizer-staticlib-link/rmake.rs +++ b/tests/run-make/sanitizer-staticlib-link/rmake.rs @@ -11,6 +11,8 @@ //@ needs-sanitizer-support //@ needs-sanitizer-address +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer + use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run_fail, rustc, static_lib_name}; fn main() { diff --git a/tests/run-make/separate-link-fail/rmake.rs b/tests/run-make/separate-link-fail/rmake.rs index b5d5300de68f..ba24f7773953 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/rustdoc-gui/scrape-examples-ice-links.goml b/tests/rustdoc-gui/scrape-examples-ice-links.goml index 1db220e1a322..0a1596219350 100644 --- a/tests/rustdoc-gui/scrape-examples-ice-links.goml +++ b/tests/rustdoc-gui/scrape-examples-ice-links.goml @@ -4,3 +4,5 @@ wait-for: ".scraped-example-title" assert-attribute: (".scraped-example-title a", {"href": "../src/bar/bar.rs.html#2"}) click: ".scraped-example-title a" wait-for-property: ("h1", {"innerText": "bar/\nbar.rs"}) +// Ensure that the `--html-after-content` option was correctly handled. +assert: "#outer-html" diff --git a/tests/rustdoc-gui/src/scrape_examples_ice/empty.html b/tests/rustdoc-gui/src/scrape_examples_ice/empty.html deleted file mode 100644 index 8b137891791f..000000000000 --- a/tests/rustdoc-gui/src/scrape_examples_ice/empty.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/rustdoc-gui/src/scrape_examples_ice/extra.html b/tests/rustdoc-gui/src/scrape_examples_ice/extra.html new file mode 100644 index 000000000000..e7a420154a66 --- /dev/null +++ b/tests/rustdoc-gui/src/scrape_examples_ice/extra.html @@ -0,0 +1 @@ + diff --git a/tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs b/tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs index b854c7722c9a..7d910c6de7df 100644 --- a/tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs +++ b/tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs @@ -1,5 +1,5 @@ //@ run-flags:-Zrustdoc-scrape-examples -//@ compile-flags: --html-after-content empty.html +//@ compile-flags: --html-after-content extra.html pub struct ObscurelyNamedType1; impl ObscurelyNamedType1 { diff --git a/tests/rustdoc/sanitizer-option.rs b/tests/rustdoc/sanitizer-option.rs index 2adf1be51fd7..7b0038138f09 100644 --- a/tests/rustdoc/sanitizer-option.rs +++ b/tests/rustdoc/sanitizer-option.rs @@ -1,6 +1,6 @@ //@ needs-sanitizer-support //@ needs-sanitizer-address -//@ compile-flags: --test -Z sanitizer=address +//@ compile-flags: --test -Z sanitizer=address -C unsafe-allow-abi-mismatch=sanitizer // // #43031: Verify that rustdoc passes `-Z` options to rustc. Use an extern // function that is provided by the sanitizer runtime, if flag is not passed diff --git a/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs b/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs index b7636d116ec6..aef25d057d4b 100644 --- a/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs +++ b/tests/ui/asm/global-asm-isnt-really-a-mir-body.rs @@ -1,5 +1,7 @@ //@ revisions: emit_mir instrument cfi +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer + // Make sure we don't try to emit MIR for it. //@[emit_mir] compile-flags: --emit=mir diff --git a/tests/ui/codegen/empty-static-libs-issue-108825.rs b/tests/ui/codegen/empty-static-libs-issue-108825.rs index 4c644be0954e..4f8e4420f724 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 0c57eddbe937..cc6a813b747d 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 0c57eddbe937..cc6a813b747d 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 25d6f0461a9a..70ae00af23f5 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 .[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 .[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 .[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 .[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 .[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 a8c7ee93971e..239bca51fc96 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 .: 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╼ │ ╾──╼ } 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 47e1c22cc2c1..3c6d66ac5b67 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 .: 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╼ │ ╾──────╼ } 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 d4039e1952c3..152eeababc51 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 36183e289210..2861f82ec53b 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 .: 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 .: 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 .: 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 .: 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 ..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 = 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 = 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 = 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 = 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 = 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 = 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 = 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, 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 .: encountered uninitialized LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { 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 ..0: encountered uninitialize LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { 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 .[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 ..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 ..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, 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, 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, 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 ..: 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, 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 .[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 .[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 .[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 .[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 .[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 .[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 .[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 c53326534fdc..8e6dc66a40ee 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 .: 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 .: 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 .: 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 .: 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 ..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 = 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 = 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 = 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 = 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 = 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 = 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 = 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, 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 .: encountered uninitialized LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { 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 ..0: encountered uninitialize LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { 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 .[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 ..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 ..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, 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, 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, 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 ..: 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, 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 .[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 .[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 .[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 .[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 .[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 .[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 .[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 ed3b3df70dd5..53665c176a76 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 5cbd6176c92d..1efd93832291 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 .: 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 .: 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 .: 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 .: 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 ..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 86d6f8c52bc7..1e4d425d78ec 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, 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╼ ╾ALLOC1╼ │ ╾──╼╾──╼ } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered ALLOC3, 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╼ ╾ALLOC3╼ │ ╾──╼╾──╼ } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC5, 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╼ ╾ALLOC5╼ │ ╾──╼╾──╼ } @@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC7, 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╼ ╾ALLOC7╼ │ ╾──╼╾──╼ } @@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC9, 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╼ ╾ALLOC9╼ │ ╾──╼╾──╼ } @@ -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╼ ╾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 a9518216dbdb..a068991f3242 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, 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╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ } @@ -15,7 +15,7 @@ error[E0080]: constructing invalid value: encountered ALLOC3, 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╼ ╾ALLOC3╼ │ ╾──────╼╾──────╼ } @@ -26,7 +26,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC5, 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╼ ╾ALLOC5╼ │ ╾──────╼╾──────╼ } @@ -37,7 +37,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC7, 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╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼ } @@ -48,7 +48,7 @@ error[E0080]: constructing invalid value at .0: encountered ALLOC9, 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╼ ╾ALLOC9╼ │ ╾──────╼╾──────╼ } @@ -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╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼ } diff --git a/tests/ui/consts/const-eval/ub-int-array.stderr b/tests/ui/consts/const-eval/ub-int-array.stderr index 10eb7c46c928..065bfd2c304a 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 19ae66cf3c63..91c82efbc5ed 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 = 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 = 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 = 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 = 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 451ebb6eba1a..c45f66c29259 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 = 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 = 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 = 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, 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 b0f475fe9386..aca0b13bb907 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 ecd1c768c287..b434970b6775 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 ...╼ ╾ALLOC1╼ │ ╾──╼╾──╼ } diff --git a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr index 108dfe6b27be..de1e1f8a2bea 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 ...╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ } diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index ab15ba826a5f..c505e5cc8a24 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 .: encountered uninitialized LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { 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 ..0: encountered uninitialize LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { 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 .[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 ..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 ..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, 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, 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, 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, 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, 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, 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 ..: 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, 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, 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 757bcea91c3c..fb2311b9921d 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 757bcea91c3c..fb2311b9921d 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 16dee44d8006..08656776468f 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 302e342bce61..96263998ad42 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 ..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 ..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 ..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 ..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 ..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 8be8b4bc50f5..f9088c318a62 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 .: 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 65a46b62daed..4b034c81a61d 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 2f600e494c46..248db694d525 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 47bb2e5e879b..17b32383912a 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 ..y..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 b4c9a4bd47e2..c4f78e7bf9ea 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 ..y..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 68d1a72b71e6..2c54200c8a2f 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 e53407881671..cf97ed6e4874 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╼ ff ff ff ff │ ╾──╼.... } diff --git a/tests/ui/consts/issue-63952.64bit.stderr b/tests/ui/consts/issue-63952.64bit.stderr index 27e74833fc56..4cea967314c0 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╼ 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 7488f7b7752a..2653ff22f120 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╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ } diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index 137efde44b31..b35076b669e2 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 .: 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.: 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.: 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 ...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 1ef20689985c..d7c668a98121 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 ..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 ..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 06f78e679b19..f3bb49900b59 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 ..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 ..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 0f503df40609..3c405e8d3cd0 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 .[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 .[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 000000000000..c6543e6d3dc9 --- /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>); +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, + f: impl Fn(&DropOrder), +) { + let order = DropOrder(RefCell::new(Vec::new())); + f(&order); + let order = order.0.into_inner(); + let expected: Vec = 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 000000000000..181f9a210003 --- /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 000000000000..de54844bc291 --- /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 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 b58c3a6720d0..14d5de0261d1 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 1fd222e0db17..5805afb3369b 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 0330853d922f..c2c7378f07a2 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/linkage-attr/raw-dylib/windows/invalid-dlltool.rs b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs index 0c78d799bad2..f5f92db3b501 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 4bbad9b30a79..311d8c61589a 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 000000000000..e4f20a11ebb3 --- /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 b0c56003957c..e5f2e65fd91d 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/lto/issue-100772.rs b/tests/ui/lto/issue-100772.rs index 29ec5b9bf964..9468e20894ac 100644 --- a/tests/ui/lto/issue-100772.rs +++ b/tests/ui/lto/issue-100772.rs @@ -1,6 +1,6 @@ //@ build-pass //@ needs-sanitizer-cfi -//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu 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 000000000000..275b68a22e22 --- /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 000000000000..81ea6e6b1bc0 --- /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 000000000000..f209ad644db9 --- /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 000000000000..6be9b801a0d7 --- /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 000000000000..fb6d5f71209a --- /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 6288cc589131..636f70166472 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 e8fad61f3178..b0557220d05a 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 ff75edfe6811..20832897ca5e 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 d76e60478a14..a5d9fd2b1a6e 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 9a40b20346c9..96504720e839 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 5fac622eef26..d2333150961a 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/address.rs b/tests/ui/sanitizer/address.rs index 704d84764c16..1688f46c2d55 100644 --- a/tests/ui/sanitizer/address.rs +++ b/tests/ui/sanitizer/address.rs @@ -2,7 +2,7 @@ //@ needs-sanitizer-address //@ ignore-cross-compile // -//@ compile-flags: -Z sanitizer=address -O -g +//@ compile-flags: -Z sanitizer=address -O -g -C unsafe-allow-abi-mismatch=sanitizer // //@ run-fail-or-crash //@ error-pattern: AddressSanitizer: stack-buffer-overflow diff --git a/tests/ui/sanitizer/asan_odr_windows.rs b/tests/ui/sanitizer/asan_odr_windows.rs index 28c247167615..b638d6eb9694 100644 --- a/tests/ui/sanitizer/asan_odr_windows.rs +++ b/tests/ui/sanitizer/asan_odr_windows.rs @@ -2,7 +2,7 @@ //! See . //@ run-pass -//@ compile-flags:-Zsanitizer=address +//@ compile-flags:-Zsanitizer=address -C unsafe-allow-abi-mismatch=sanitizer //@ aux-build: asan_odr_win-2.rs //@ only-windows-msvc //@ needs-sanitizer-support diff --git a/tests/ui/sanitizer/badfree.rs b/tests/ui/sanitizer/badfree.rs index 6b3aea7239c2..b1b02649dccd 100644 --- a/tests/ui/sanitizer/badfree.rs +++ b/tests/ui/sanitizer/badfree.rs @@ -2,7 +2,7 @@ //@ needs-sanitizer-address //@ ignore-cross-compile // -//@ compile-flags: -Z sanitizer=address -O +//@ compile-flags: -Z sanitizer=address -O -C unsafe-allow-abi-mismatch=sanitizer // //@ run-fail-or-crash //@ regex-error-pattern: AddressSanitizer: (SEGV|attempting free on address which was not malloc) diff --git a/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs index fad57198dfbe..5de5e99f6d0c 100644 --- a/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs +++ b/tests/ui/sanitizer/cfi/assoc-ty-lifetime-issue-123053.rs @@ -2,7 +2,7 @@ // trait object type to fail, causing an ICE. // //@ needs-sanitizer-cfi -//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer //@ edition: 2021 //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu diff --git a/tests/ui/sanitizer/cfi/async-closures.rs b/tests/ui/sanitizer/cfi/async-closures.rs index 9b0992630002..621a0882c91b 100644 --- a/tests/ui/sanitizer/cfi/async-closures.rs +++ b/tests/ui/sanitizer/cfi/async-closures.rs @@ -7,7 +7,7 @@ //@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi -//@ compile-flags: -C target-feature=-crt-static +//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi diff --git a/tests/ui/sanitizer/cfi/can-reveal-opaques.rs b/tests/ui/sanitizer/cfi/can-reveal-opaques.rs index a881c6b92b28..310ce04c5524 100644 --- a/tests/ui/sanitizer/cfi/can-reveal-opaques.rs +++ b/tests/ui/sanitizer/cfi/can-reveal-opaques.rs @@ -1,5 +1,5 @@ //@ needs-sanitizer-cfi -//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu //@ ignore-backends: gcc diff --git a/tests/ui/sanitizer/cfi/closures.rs b/tests/ui/sanitizer/cfi/closures.rs index fc9718faa286..7493dba4928b 100644 --- a/tests/ui/sanitizer/cfi/closures.rs +++ b/tests/ui/sanitizer/cfi/closures.rs @@ -6,7 +6,7 @@ //@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi -//@ compile-flags: -C target-feature=-crt-static +//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi diff --git a/tests/ui/sanitizer/cfi/complex-receiver.rs b/tests/ui/sanitizer/cfi/complex-receiver.rs index aac44c33227f..adacc0d6c5df 100644 --- a/tests/ui/sanitizer/cfi/complex-receiver.rs +++ b/tests/ui/sanitizer/cfi/complex-receiver.rs @@ -8,7 +8,7 @@ //@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi -//@ compile-flags: -C target-feature=-crt-static +//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi diff --git a/tests/ui/sanitizer/cfi/coroutine.rs b/tests/ui/sanitizer/cfi/coroutine.rs index 084a521f597f..d85615b597de 100644 --- a/tests/ui/sanitizer/cfi/coroutine.rs +++ b/tests/ui/sanitizer/cfi/coroutine.rs @@ -8,6 +8,7 @@ //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi //@ compile-flags: -C target-feature=-crt-static +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi diff --git a/tests/ui/sanitizer/cfi/drop-in-place.rs b/tests/ui/sanitizer/cfi/drop-in-place.rs index 160338a5b54a..fe59d5463124 100644 --- a/tests/ui/sanitizer/cfi/drop-in-place.rs +++ b/tests/ui/sanitizer/cfi/drop-in-place.rs @@ -5,6 +5,7 @@ //@ ignore-backends: gcc //@ needs-sanitizer-cfi //@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer //@ run-pass struct EmptyDrop; diff --git a/tests/ui/sanitizer/cfi/drop-no-principal.rs b/tests/ui/sanitizer/cfi/drop-no-principal.rs index e3a46fe9d759..4fb905eb51d0 100644 --- a/tests/ui/sanitizer/cfi/drop-no-principal.rs +++ b/tests/ui/sanitizer/cfi/drop-no-principal.rs @@ -4,7 +4,7 @@ // FIXME(#122848) Remove only-linux once OSX CFI binaries works //@ only-linux //@ ignore-backends: gcc -//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi +//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer //@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0 // FIXME(#118761) Should be run-pass once the labels on drop are compatible. // This test is being landed ahead of that to test that the compiler doesn't ICE while labeling the diff --git a/tests/ui/sanitizer/cfi/fn-ptr.rs b/tests/ui/sanitizer/cfi/fn-ptr.rs index d3209c62ddf9..bdb8c7ceb328 100644 --- a/tests/ui/sanitizer/cfi/fn-ptr.rs +++ b/tests/ui/sanitizer/cfi/fn-ptr.rs @@ -7,6 +7,7 @@ //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi //@ compile-flags: -C target-feature=-crt-static +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer //@ [cfi] compile-flags: -C opt-level=0 -C codegen-units=1 -C lto //@ [cfi] compile-flags: -C prefer-dynamic=off //@ [cfi] compile-flags: -Z sanitizer=cfi diff --git a/tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs b/tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs index d46002c69fda..44cdcb250e70 100644 --- a/tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs +++ b/tests/ui/sanitizer/cfi/generalize-pointers-attr-cfg.rs @@ -4,6 +4,7 @@ //@ needs-sanitizer-cfi //@ check-pass //@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer #![feature(cfg_sanitizer_cfi)] diff --git a/tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs b/tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs index 24c2c2c13da7..ce4e31eb69b5 100644 --- a/tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs +++ b/tests/ui/sanitizer/cfi/normalize-integers-attr-cfg.rs @@ -3,7 +3,7 @@ // //@ needs-sanitizer-cfi //@ check-pass -//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers +//@ compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -C unsafe-allow-abi-mismatch=sanitizer,sanitizer-cfi-normalize-integers #![feature(cfg_sanitizer_cfi)] diff --git a/tests/ui/sanitizer/cfi/self-ref.rs b/tests/ui/sanitizer/cfi/self-ref.rs index b93d49296b63..827610a26106 100644 --- a/tests/ui/sanitizer/cfi/self-ref.rs +++ b/tests/ui/sanitizer/cfi/self-ref.rs @@ -6,7 +6,7 @@ //@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi -//@ compile-flags: -C target-feature=-crt-static +//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi diff --git a/tests/ui/sanitizer/cfi/sized-associated-ty.rs b/tests/ui/sanitizer/cfi/sized-associated-ty.rs index eefc3e2e9db9..da8c385c6fc8 100644 --- a/tests/ui/sanitizer/cfi/sized-associated-ty.rs +++ b/tests/ui/sanitizer/cfi/sized-associated-ty.rs @@ -7,7 +7,7 @@ //@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi -//@ compile-flags: -C target-feature=-crt-static +//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi diff --git a/tests/ui/sanitizer/cfi/supertraits.rs b/tests/ui/sanitizer/cfi/supertraits.rs index f5a984b9583d..b2782dff5d55 100644 --- a/tests/ui/sanitizer/cfi/supertraits.rs +++ b/tests/ui/sanitizer/cfi/supertraits.rs @@ -6,7 +6,7 @@ //@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi -//@ compile-flags: -C target-feature=-crt-static +//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi diff --git a/tests/ui/sanitizer/cfi/transparent-has-regions.rs b/tests/ui/sanitizer/cfi/transparent-has-regions.rs index b70e1ea17912..b82850133c10 100644 --- a/tests/ui/sanitizer/cfi/transparent-has-regions.rs +++ b/tests/ui/sanitizer/cfi/transparent-has-regions.rs @@ -1,5 +1,5 @@ //@ needs-sanitizer-cfi -//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu //@ build-pass diff --git a/tests/ui/sanitizer/cfi/virtual-auto.rs b/tests/ui/sanitizer/cfi/virtual-auto.rs index e6f2ebd4b2cd..d3a715c079aa 100644 --- a/tests/ui/sanitizer/cfi/virtual-auto.rs +++ b/tests/ui/sanitizer/cfi/virtual-auto.rs @@ -6,7 +6,7 @@ //@ ignore-backends: gcc //@ [cfi] needs-sanitizer-cfi //@ [kcfi] needs-sanitizer-kcfi -//@ compile-flags: -C target-feature=-crt-static +//@ compile-flags: -C target-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi diff --git a/tests/ui/sanitizer/dataflow.rs b/tests/ui/sanitizer/dataflow.rs index 658a9e480866..d99a1a6ac247 100644 --- a/tests/ui/sanitizer/dataflow.rs +++ b/tests/ui/sanitizer/dataflow.rs @@ -4,7 +4,7 @@ //@ needs-sanitizer-support //@ needs-sanitizer-dataflow //@ run-pass -//@ compile-flags: -Zsanitizer=dataflow -Zsanitizer-dataflow-abilist={{src-base}}/sanitizer/dataflow-abilist.txt +//@ compile-flags: -Zsanitizer=dataflow -Zsanitizer-dataflow-abilist={{src-base}}/sanitizer/dataflow-abilist.txt -C unsafe-allow-abi-mismatch=sanitizer use std::mem::size_of; use std::os::raw::{c_int, c_long, c_void}; diff --git a/tests/ui/sanitizer/hwaddress.rs b/tests/ui/sanitizer/hwaddress.rs index e5939eb734b6..05fcab17506b 100644 --- a/tests/ui/sanitizer/hwaddress.rs +++ b/tests/ui/sanitizer/hwaddress.rs @@ -5,7 +5,7 @@ //@ ignore-aarch64-unknown-linux-gnu // // FIXME(#83989): codegen-units=1 triggers linker errors on aarch64-gnu -//@ compile-flags: -Z sanitizer=hwaddress -O -g -C codegen-units=16 +//@ compile-flags: -Z sanitizer=hwaddress -O -g -C codegen-units=16 -C unsafe-allow-abi-mismatch=sanitizer // //@ run-fail //@ error-pattern: HWAddressSanitizer: tag-mismatch diff --git a/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs b/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs index 7d0c73c2841e..be81c7bd0cac 100644 --- a/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs +++ b/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs @@ -2,7 +2,7 @@ // encode_ty and caused the compiler to ICE. // //@ needs-sanitizer-cfi -//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -C unsafe-allow-abi-mismatch=sanitizer //@ edition: 2021 //@ no-prefer-dynamic //@ only-x86_64-unknown-linux-gnu diff --git a/tests/ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs b/tests/ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs index b1b7487fa2a4..f7af2842ad61 100644 --- a/tests/ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs +++ b/tests/ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs @@ -2,7 +2,7 @@ // was expecting array type lengths to be evaluated, this was causing an ICE. // //@ build-pass -//@ compile-flags: -Ccodegen-units=1 -Clto -Zsanitizer=cfi -Ctarget-feature=-crt-static +//@ compile-flags: -Ccodegen-units=1 -Clto -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer //@ needs-sanitizer-cfi #![crate_type = "lib"] diff --git a/tests/ui/sanitizer/issue-72154-address-lifetime-markers.rs b/tests/ui/sanitizer/issue-72154-address-lifetime-markers.rs index aa0c19db9a12..edeb1b0bf946 100644 --- a/tests/ui/sanitizer/issue-72154-address-lifetime-markers.rs +++ b/tests/ui/sanitizer/issue-72154-address-lifetime-markers.rs @@ -7,7 +7,7 @@ //@ needs-sanitizer-address //@ ignore-cross-compile // -//@ compile-flags: -Copt-level=0 -Zsanitizer=address +//@ compile-flags: -Copt-level=0 -Zsanitizer=address -C unsafe-allow-abi-mismatch=sanitizer //@ run-pass pub struct Wrap { diff --git a/tests/ui/sanitizer/kcfi-mangling.rs b/tests/ui/sanitizer/kcfi-mangling.rs index ba36dc184ec7..371f34ba72af 100644 --- a/tests/ui/sanitizer/kcfi-mangling.rs +++ b/tests/ui/sanitizer/kcfi-mangling.rs @@ -2,7 +2,7 @@ //@ needs-sanitizer-kcfi //@ no-prefer-dynamic -//@ compile-flags: -C panic=abort -Zsanitizer=kcfi -C symbol-mangling-version=v0 +//@ compile-flags: -C panic=abort -Zsanitizer=kcfi -C symbol-mangling-version=v0 -C unsafe-allow-abi-mismatch=sanitizer //@ build-pass //@ ignore-backends: gcc diff --git a/tests/ui/sanitizer/leak.rs b/tests/ui/sanitizer/leak.rs index 65915ec24b72..4ce3f7ab1b95 100644 --- a/tests/ui/sanitizer/leak.rs +++ b/tests/ui/sanitizer/leak.rs @@ -1,7 +1,7 @@ //@ needs-sanitizer-support //@ needs-sanitizer-leak // -//@ compile-flags: -Z sanitizer=leak -O +//@ compile-flags: -Z sanitizer=leak -O -C unsafe-allow-abi-mismatch=sanitizer // //@ run-fail //@ error-pattern: LeakSanitizer: detected memory leaks diff --git a/tests/ui/sanitizer/memory-eager.rs b/tests/ui/sanitizer/memory-eager.rs index 709299f87d49..9498336abb7d 100644 --- a/tests/ui/sanitizer/memory-eager.rs +++ b/tests/ui/sanitizer/memory-eager.rs @@ -1,6 +1,8 @@ //@ needs-sanitizer-support //@ needs-sanitizer-memory // +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer +// //@ revisions: unoptimized optimized // //@ [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O diff --git a/tests/ui/sanitizer/memory-passing.rs b/tests/ui/sanitizer/memory-passing.rs index 96a4cd909c7c..6ac41b178fe7 100644 --- a/tests/ui/sanitizer/memory-passing.rs +++ b/tests/ui/sanitizer/memory-passing.rs @@ -1,6 +1,8 @@ //@ needs-sanitizer-support //@ needs-sanitizer-memory // +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer +// //@ revisions: unoptimized optimized // //@ [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O diff --git a/tests/ui/sanitizer/memory.rs b/tests/ui/sanitizer/memory.rs index a91fefe4d16d..1566637acd22 100644 --- a/tests/ui/sanitizer/memory.rs +++ b/tests/ui/sanitizer/memory.rs @@ -1,6 +1,8 @@ //@ needs-sanitizer-support //@ needs-sanitizer-memory // +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer +// //@ revisions: unoptimized optimized // //@ [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O diff --git a/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs b/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs index c1a2c2f26ace..b66568474277 100644 --- a/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs +++ b/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs @@ -6,6 +6,8 @@ //@ needs-sanitizer-address //@ ignore-cross-compile // +//@ compile-flags: -C unsafe-allow-abi-mismatch=sanitizer +// //@ no-prefer-dynamic //@ revisions: opt0 opt1 //@ compile-flags: -Zsanitizer=address -Clto=thin diff --git a/tests/ui/sanitizer/thread.rs b/tests/ui/sanitizer/thread.rs index 9073124d1bd3..8f72b1b41a84 100644 --- a/tests/ui/sanitizer/thread.rs +++ b/tests/ui/sanitizer/thread.rs @@ -13,7 +13,7 @@ //@ needs-sanitizer-support //@ needs-sanitizer-thread // -//@ compile-flags: -Z sanitizer=thread -O +//@ compile-flags: -Z sanitizer=thread -O -C unsafe-allow-abi-mismatch=sanitizer // //@ run-fail-or-crash //@ error-pattern: WARNING: ThreadSanitizer: data race diff --git a/tests/ui/sanitizer/use-after-scope.rs b/tests/ui/sanitizer/use-after-scope.rs index 106dc6466d6a..1c477d0be14b 100644 --- a/tests/ui/sanitizer/use-after-scope.rs +++ b/tests/ui/sanitizer/use-after-scope.rs @@ -2,7 +2,7 @@ //@ needs-sanitizer-address //@ ignore-cross-compile // -//@ compile-flags: -Zsanitizer=address +//@ compile-flags: -Zsanitizer=address -C unsafe-allow-abi-mismatch=sanitizer //@ run-fail-or-crash //@ error-pattern: ERROR: AddressSanitizer: stack-use-after-scope diff --git a/tests/ui/span/issue-39698.stderr b/tests/ui/span/issue-39698.stderr index 73fcc5c84775..eb18969c3c0d 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 df36287cc69e..1d6ba195fa28 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.: 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 000000000000..a9ffb425c523 --- /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 000000000000..dbf46537caa1 --- /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 b34a48aba261..a958700231a3 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 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 7b75367b48c2..d85bccce4410 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 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/target_modifiers/auxiliary/kcfi-normalize-ints.rs b/tests/ui/target_modifiers/auxiliary/kcfi-normalize-ints.rs new file mode 100644 index 000000000000..f97005a14502 --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/kcfi-normalize-ints.rs @@ -0,0 +1,7 @@ +//@ no-prefer-dynamic +//@ needs-sanitizer-kcfi +//@ compile-flags: -C panic=abort -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/auxiliary/no-sanitizers.rs b/tests/ui/target_modifiers/auxiliary/no-sanitizers.rs new file mode 100644 index 000000000000..1d47ff6826da --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/no-sanitizers.rs @@ -0,0 +1,6 @@ +//@ no-prefer-dynamic +//@ compile-flags: -C panic=abort + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/auxiliary/safestack-and-kcfi.rs b/tests/ui/target_modifiers/auxiliary/safestack-and-kcfi.rs new file mode 100644 index 000000000000..029744d2a1fe --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/safestack-and-kcfi.rs @@ -0,0 +1,10 @@ +//@ no-prefer-dynamic + +//@ needs-sanitizer-kcfi +//@ needs-sanitizer-safestack + +//@ compile-flags: -C panic=abort -Zsanitizer=safestack,kcfi + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.rs b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.rs new file mode 100644 index 000000000000..cb9f701349ae --- /dev/null +++ b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.rs @@ -0,0 +1,18 @@ +// For kCFI, the helper flag -Zsanitizer-cfi-normalize-integers should also be a target modifier. + +//@ needs-sanitizer-kcfi +//@ aux-build:kcfi-normalize-ints.rs +//@ compile-flags: -Cpanic=abort + +//@ revisions: ok wrong_flag wrong_sanitizer +//@[ok] compile-flags: -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers +//@[wrong_flag] compile-flags: -Zsanitizer=kcfi +//@[ok] check-pass + +#![feature(no_core)] +//[wrong_flag]~^ ERROR mixing `-Zsanitizer-cfi-normalize-integers` will cause an ABI mismatch in crate `sanitizer_kcfi_normalize_ints` +//[wrong_sanitizer]~^^ ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_kcfi_normalize_ints` +#![crate_type = "rlib"] +#![no_core] + +extern crate kcfi_normalize_ints; diff --git a/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_flag.stderr b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_flag.stderr new file mode 100644 index 000000000000..1db79b025e9c --- /dev/null +++ b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_flag.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zsanitizer-cfi-normalize-integers` will cause an ABI mismatch in crate `sanitizer_kcfi_normalize_ints` + --> $DIR/sanitizer-kcfi-normalize-ints.rs:12:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zsanitizer-cfi-normalize-integers` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: unset `-Zsanitizer-cfi-normalize-integers` in this crate is incompatible with `-Zsanitizer-cfi-normalize-integers=` in dependency `kcfi_normalize_ints` + = help: set `-Zsanitizer-cfi-normalize-integers=` in this crate or unset `-Zsanitizer-cfi-normalize-integers` in `kcfi_normalize_ints` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer-cfi-normalize-integers` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_sanitizer.stderr b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_sanitizer.stderr new file mode 100644 index 000000000000..5b949c87350b --- /dev/null +++ b/tests/ui/target_modifiers/sanitizer-kcfi-normalize-ints.wrong_sanitizer.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_kcfi_normalize_ints` + --> $DIR/sanitizer-kcfi-normalize-ints.rs:12:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: unset `-Zsanitizer` in this crate is incompatible with `-Zsanitizer=kcfi` in dependency `kcfi_normalize_ints` + = help: set `-Zsanitizer=kcfi` in this crate or unset `-Zsanitizer` in `kcfi_normalize_ints` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/sanitizers-good-for-inconsistency.rs b/tests/ui/target_modifiers/sanitizers-good-for-inconsistency.rs new file mode 100644 index 000000000000..abda7be9e405 --- /dev/null +++ b/tests/ui/target_modifiers/sanitizers-good-for-inconsistency.rs @@ -0,0 +1,19 @@ +// AddressSanitizer, LeakSanitizer are good to be inconsistent (they are not a target modifiers) + +//@ revisions: wrong_address_san wrong_leak_san + +//@[wrong_address_san] needs-sanitizer-address +//@[wrong_leak_san] needs-sanitizer-leak + +//@ aux-build:no-sanitizers.rs +//@ compile-flags: -Cpanic=abort -C target-feature=-crt-static + +//@[wrong_address_san] compile-flags: -Zsanitizer=address +//@[wrong_leak_san] compile-flags: -Zsanitizer=leak +//@ check-pass + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] + +extern crate no_sanitizers; diff --git a/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_both.stderr b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_both.stderr new file mode 100644 index 000000000000..440a91c7707f --- /dev/null +++ b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_both.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi` + --> $DIR/sanitizers-safestack-and-kcfi.rs:16:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: unset `-Zsanitizer` in this crate is incompatible with `-Zsanitizer=safestack,kcfi` in dependency `safestack_and_kcfi` + = help: set `-Zsanitizer=safestack,kcfi` in this crate or unset `-Zsanitizer` in `safestack_and_kcfi` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_kcfi.stderr b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_kcfi.stderr new file mode 100644 index 000000000000..6cdd7facc378 --- /dev/null +++ b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_kcfi.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi` + --> $DIR/sanitizers-safestack-and-kcfi.rs:16:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: `-Zsanitizer=safestack` in this crate is incompatible with `-Zsanitizer=safestack,kcfi` in dependency `safestack_and_kcfi` + = help: set `-Zsanitizer=safestack,kcfi` in this crate or `-Zsanitizer=safestack` in `safestack_and_kcfi` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_safestack.stderr b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_safestack.stderr new file mode 100644 index 000000000000..ecfbcace39fe --- /dev/null +++ b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.missed_safestack.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi` + --> $DIR/sanitizers-safestack-and-kcfi.rs:16:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: `-Zsanitizer=kcfi` in this crate is incompatible with `-Zsanitizer=safestack,kcfi` in dependency `safestack_and_kcfi` + = help: set `-Zsanitizer=safestack,kcfi` in this crate or `-Zsanitizer=kcfi` in `safestack_and_kcfi` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.rs b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.rs new file mode 100644 index 000000000000..6c3ceb7e9100 --- /dev/null +++ b/tests/ui/target_modifiers/sanitizers-safestack-and-kcfi.rs @@ -0,0 +1,23 @@ +//@ needs-sanitizer-kcfi +//@ needs-sanitizer-safestack + +//@ aux-build:safestack-and-kcfi.rs +//@ compile-flags: -Cpanic=abort + +//@ revisions: good good_reverted missed_safestack missed_kcfi missed_both +//@[good] compile-flags: -Zsanitizer=safestack,kcfi +//@[good_reverted] compile-flags: -Zsanitizer=kcfi,safestack +//@[missed_safestack] compile-flags: -Zsanitizer=kcfi +//@[missed_kcfi] compile-flags: -Zsanitizer=safestack +// [missed_both] no additional compile-flags: +//@[good] check-pass +//@[good_reverted] check-pass + +#![feature(no_core)] +//[missed_safestack]~^ ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi` +//[missed_kcfi]~^^ ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi` +//[missed_both]~^^^ ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizers_safestack_and_kcfi` +#![crate_type = "rlib"] +#![no_core] + +extern crate safestack_and_kcfi; diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr index b545cd75ddb5..e19915a58a32 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 1a9652c10230..5a683884238a 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 9cb6a181beff..9f07e63e4544 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 cf2e95203fa4..b957c6465e60 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1306,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