diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index c06e3c8b3c174..7d72de7efa4a1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1198,6 +1198,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ); return; } + + // Do not suggest changing type if that is not under user control. + if self.is_closure_arg_with_non_locally_decided_type(local) { + return; + } + let decl_span = local_decl.source_info.span; let (amp_mut_sugg, local_var_ty_info) = match *local_decl.local_info() { @@ -1500,6 +1506,60 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { Applicability::HasPlaceholders, ); } + + /// Returns `true` if `local` is an argument in a closure passed to a + /// function defined in another crate. + /// + /// For example, in the following code this function returns `true` for `x` + /// since `Option::inspect()` is not defined in the current crate: + /// + /// ```text + /// some_option.as_mut().inspect(|x| { + /// ``` + fn is_closure_arg_with_non_locally_decided_type(&self, local: Local) -> bool { + // We don't care about regular local variables, only args. + if self.body.local_kind(local) != LocalKind::Arg { + return false; + } + + // Make sure we are inside a closure. + let InstanceKind::Item(body_def_id) = self.body.source.instance else { + return false; + }; + let Some(Node::Expr(hir::Expr { hir_id: body_hir_id, kind, .. })) = + self.infcx.tcx.hir_get_if_local(body_def_id) + else { + return false; + }; + let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind else { + return false; + }; + + // Check if the method/function that our closure is passed to is defined + // in another crate. + let Node::Expr(closure_parent) = self.infcx.tcx.parent_hir_node(*body_hir_id) else { + return false; + }; + match closure_parent.kind { + ExprKind::MethodCall(method, _, _, _) => self + .infcx + .tcx + .typeck(method.hir_id.owner.def_id) + .type_dependent_def_id(closure_parent.hir_id) + .is_some_and(|def_id| !def_id.is_local()), + ExprKind::Call(func, _) => self + .infcx + .tcx + .typeck(func.hir_id.owner.def_id) + .node_type_opt(func.hir_id) + .and_then(|ty| match ty.kind() { + ty::FnDef(def_id, _) => Some(def_id), + _ => None, + }) + .is_some_and(|def_id| !def_id.is_local()), + _ => false, + } + } } struct BindingFinder { diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index f2e454c3d4373..b77a121ca0b95 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -10,6 +10,7 @@ use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable}; /// Selects the first arm whose predicate evaluates to true. fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> { + let mut result = None; for (cfg, tt, arm_span) in branches.reachable { if let EvalConfigResult::True = attr::eval_config_entry( &ecx.sess, @@ -17,11 +18,13 @@ fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenSt ecx.current_expansion.lint_node_id, ShouldEmit::ErrorsAndLints, ) { - return Some((tt, arm_span)); + // FIXME(#149215) Ideally we should short-circuit here, but `eval_config_entry` currently emits lints so we cannot do this yet. + result.get_or_insert((tt, arm_span)); } } - branches.wildcard.map(|(_, tt, span)| (tt, span)) + let wildcard = branches.wildcard.map(|(_, tt, span)| (tt, span)); + result.or(wildcard) } pub(super) fn expand_cfg_select<'cx>( diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index af1c35774a67a..c0f8f33692e8c 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -24,6 +24,7 @@ use rustc_session::parse::ParseSess; use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, lint}; use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs}; use rustc_span::{FileName, sym}; +use rustc_target::spec::Target; use tracing::trace; use crate::util; @@ -385,7 +386,7 @@ pub struct Config { /// custom driver where the custom codegen backend has arbitrary data." /// (See #102759.) pub make_codegen_backend: - Option Box + Send>>, + Option Box + Send>>, /// Registry of diagnostics codes. pub registry: Registry, @@ -453,7 +454,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se Some(make_codegen_backend) => { // N.B. `make_codegen_backend` takes precedence over // `target.default_codegen_backend`, which is ignored in this case. - make_codegen_backend(&config.opts) + make_codegen_backend(&config.opts, &target) } }; diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index de4175c3511e7..7e9c135661630 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -339,7 +339,7 @@ pub fn get_codegen_backend( filename if filename.contains('.') => { load_backend_from_dylib(early_dcx, filename.as_ref()) } - "dummy" => || Box::new(DummyCodegenBackend), + "dummy" => || Box::new(DummyCodegenBackend { target_config_override: None }), #[cfg(feature = "llvm")] "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new, backend_name => get_codegen_sysroot(early_dcx, sysroot, backend_name), @@ -352,7 +352,9 @@ pub fn get_codegen_backend( unsafe { load() } } -struct DummyCodegenBackend; +pub struct DummyCodegenBackend { + pub target_config_override: Option TargetConfig>>, +} impl CodegenBackend for DummyCodegenBackend { fn locale_resource(&self) -> &'static str { @@ -364,6 +366,10 @@ impl CodegenBackend for DummyCodegenBackend { } fn target_config(&self, sess: &Session) -> TargetConfig { + if let Some(target_config_override) = &self.target_config_override { + return target_config_override(sess); + } + let abi_required_features = sess.target.abi_required_features(); let (target_features, unstable_target_features) = cfg_target_feature::<0>( sess, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index a1c7990f2311d..9ecc2365e69b7 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -126,8 +126,6 @@ #![feature(str_split_inclusive_remainder)] #![feature(str_split_remainder)] #![feature(ub_checks)] -#![feature(unchecked_neg)] -#![feature(unchecked_shifts)] #![feature(unsafe_pinned)] #![feature(utf16_extra)] #![feature(variant_count)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 21f9be8fc7695..62f83a3a14d94 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1275,11 +1275,8 @@ macro_rules! int_impl { /// i.e. when [`checked_neg`] would return `None`. /// #[doc = concat!("[`checked_neg`]: ", stringify!($SelfT), "::checked_neg")] - #[unstable( - feature = "unchecked_neg", - reason = "niche optimization path", - issue = "85122", - )] + #[stable(feature = "unchecked_neg", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unchecked_neg", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1395,11 +1392,8 @@ macro_rules! int_impl { /// i.e. when [`checked_shl`] would return `None`. /// #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")] - #[unstable( - feature = "unchecked_shifts", - reason = "niche optimization path", - issue = "85122", - )] + #[stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -1570,11 +1564,8 @@ macro_rules! int_impl { /// i.e. when [`checked_shr`] would return `None`. /// #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")] - #[unstable( - feature = "unchecked_shifts", - reason = "niche optimization path", - issue = "85122", - )] + #[stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index e3e843f955bd2..c8224e92b17e4 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1851,11 +1851,8 @@ macro_rules! uint_impl { /// i.e. when [`checked_shl`] would return `None`. /// #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")] - #[unstable( - feature = "unchecked_shifts", - reason = "niche optimization path", - issue = "85122", - )] + #[stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] @@ -2023,11 +2020,8 @@ macro_rules! uint_impl { /// i.e. when [`checked_shr`] would return `None`. /// #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")] - #[unstable( - feature = "unchecked_shifts", - reason = "niche optimization path", - issue = "85122", - )] + #[stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unchecked_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 9f1ff238359a1..57b052d0dfe09 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -10,6 +10,7 @@ // The rustc crates we need extern crate rustc_abi; +extern crate rustc_codegen_ssa; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_hir; @@ -19,6 +20,7 @@ extern crate rustc_log; extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; +extern crate rustc_target; /// See docs in https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc/src/main.rs /// and https://github.com/rust-lang/rust/pull/146627 for why we need this. @@ -36,6 +38,7 @@ use std::num::{NonZero, NonZeroI32}; use std::ops::Range; use std::rc::Rc; use std::str::FromStr; +use std::sync::Once; use std::sync::atomic::{AtomicU32, Ordering}; use miri::{ @@ -43,12 +46,14 @@ use miri::{ ProvenanceMode, TreeBorrowsParams, ValidationMode, run_genmc_mode, }; use rustc_abi::ExternAbi; +use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::sync::{self, DynSync}; use rustc_driver::Compilation; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::{self as hir, Node}; use rustc_hir_analysis::check::check_function_signature; use rustc_interface::interface::Config; +use rustc_interface::util::DummyCodegenBackend; use rustc_log::tracing::debug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{ @@ -58,8 +63,9 @@ use rustc_middle::query::LocalCrate; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::EarlyDiagCtxt; -use rustc_session::config::{CrateType, ErrorOutputType, OptLevel}; +use rustc_session::config::{CrateType, ErrorOutputType, OptLevel, Options}; use rustc_span::def_id::DefId; +use rustc_target::spec::Target; use crate::log::setup::{deinit_loggers, init_early_loggers, init_late_loggers}; @@ -161,7 +167,31 @@ fn run_many_seeds( } } +/// Generates the codegen backend for code that Miri will interpret: we basically +/// use the dummy backend, except that we put the LLVM backend in charge of +/// target features. +fn make_miri_codegen_backend(opts: &Options, target: &Target) -> Box { + let early_dcx = EarlyDiagCtxt::new(opts.error_format); + + // Use the target_config method of the default codegen backend (eg LLVM) to ensure the + // calculated target features match said backend by respecting eg -Ctarget-cpu. + let target_config_backend = + rustc_interface::util::get_codegen_backend(&early_dcx, &opts.sysroot, None, &target); + let target_config_backend_init = Once::new(); + + Box::new(DummyCodegenBackend { + target_config_override: Some(Box::new(move |sess| { + target_config_backend_init.call_once(|| target_config_backend.init(sess)); + target_config_backend.target_config(sess) + })), + }) +} + impl rustc_driver::Callbacks for MiriCompilerCalls { + fn config(&mut self, config: &mut rustc_interface::interface::Config) { + config.make_codegen_backend = Some(Box::new(make_miri_codegen_backend)); + } + fn after_analysis<'tcx>( &mut self, _: &rustc_interface::interface::Compiler, @@ -244,11 +274,20 @@ struct MiriBeRustCompilerCalls { impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { #[allow(rustc::potential_query_instability)] // rustc_codegen_ssa (where this code is copied from) also allows this lint fn config(&mut self, config: &mut Config) { - if config.opts.prints.is_empty() && self.target_crate { + if !self.target_crate { + // For a host crate, we fully behave like rustc. + return; + } + // For a target crate, we emit an rlib that Miri can later consume. + config.make_codegen_backend = Some(Box::new(make_miri_codegen_backend)); + + // Avoid warnings about unsupported crate types. However, only do that we we are *not* being + // queried by cargo about the supported crate types so that cargo still receives the + // warnings it expects. + if config.opts.prints.is_empty() { #[allow(rustc::bad_opt_access)] // tcx does not exist yet { let any_crate_types = !config.opts.crate_types.is_empty(); - // Avoid warnings about unsupported crate types. config .opts .crate_types @@ -259,66 +298,63 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { assert!(!config.opts.crate_types.is_empty()); } } - - // Queries overridden here affect the data stored in `rmeta` files of dependencies, - // which will be used later in non-`MIRI_BE_RUSTC` mode. - config.override_queries = Some(|_, local_providers| { - // We need to add #[used] symbols to exported_symbols for `lookup_link_section`. - // FIXME handle this somehow in rustc itself to avoid this hack. - local_providers.exported_non_generic_symbols = |tcx, LocalCrate| { - let reachable_set = tcx.with_stable_hashing_context(|hcx| { - tcx.reachable_set(()).to_sorted(&hcx, true) - }); - tcx.arena.alloc_from_iter( - // This is based on: - // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63 - // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174 - reachable_set.into_iter().filter_map(|&local_def_id| { - // Do the same filtering that rustc does: - // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L84-L102 - // Otherwise it may cause unexpected behaviours and ICEs - // (https://github.com/rust-lang/rust/issues/86261). - let is_reachable_non_generic = matches!( - tcx.hir_node_by_def_id(local_def_id), - Node::Item(&hir::Item { - kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn{ .. }, - .. - }) | Node::ImplItem(&hir::ImplItem { - kind: hir::ImplItemKind::Fn(..), - .. - }) - if !tcx.generics_of(local_def_id).requires_monomorphization(tcx) - ); - if !is_reachable_non_generic { - return None; - } - let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id); - if codegen_fn_attrs.contains_extern_indicator() - || codegen_fn_attrs - .flags - .contains(CodegenFnAttrFlags::USED_COMPILER) - || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) - { - Some(( - ExportedSymbol::NonGeneric(local_def_id.to_def_id()), - // Some dummy `SymbolExportInfo` here. We only use - // `exported_symbols` in shims/foreign_items.rs and the export info - // is ignored. - SymbolExportInfo { - level: SymbolExportLevel::C, - kind: SymbolExportKind::Text, - used: false, - rustc_std_internal_symbol: false, - }, - )) - } else { - None - } - }), - ) - } - }); } + + // Queries overridden here affect the data stored in `rmeta` files of dependencies, + // which will be used later in non-`MIRI_BE_RUSTC` mode. + config.override_queries = Some(|_, local_providers| { + // We need to add #[used] symbols to exported_symbols for `lookup_link_section`. + // FIXME handle this somehow in rustc itself to avoid this hack. + local_providers.exported_non_generic_symbols = |tcx, LocalCrate| { + let reachable_set = tcx + .with_stable_hashing_context(|hcx| tcx.reachable_set(()).to_sorted(&hcx, true)); + tcx.arena.alloc_from_iter( + // This is based on: + // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63 + // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174 + reachable_set.into_iter().filter_map(|&local_def_id| { + // Do the same filtering that rustc does: + // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L84-L102 + // Otherwise it may cause unexpected behaviours and ICEs + // (https://github.com/rust-lang/rust/issues/86261). + let is_reachable_non_generic = matches!( + tcx.hir_node_by_def_id(local_def_id), + Node::Item(&hir::Item { + kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn{ .. }, + .. + }) | Node::ImplItem(&hir::ImplItem { + kind: hir::ImplItemKind::Fn(..), + .. + }) + if !tcx.generics_of(local_def_id).requires_monomorphization(tcx) + ); + if !is_reachable_non_generic { + return None; + } + let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id); + if codegen_fn_attrs.contains_extern_indicator() + || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) + || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) + { + Some(( + ExportedSymbol::NonGeneric(local_def_id.to_def_id()), + // Some dummy `SymbolExportInfo` here. We only use + // `exported_symbols` in shims/foreign_items.rs and the export info + // is ignored. + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Text, + used: false, + rustc_std_internal_symbol: false, + }, + )) + } else { + None + } + }), + ) + } + }); } fn after_analysis<'tcx>( diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 5ec2e8edd857d..b30395b738b17 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -165,7 +165,6 @@ pub use crate::shims::unwind::{CatchUnwindData, EvalContextExt as _}; /// Also disable the MIR pass that inserts an alignment check on every pointer dereference. Miri /// does that too, and with a better error message. pub const MIRI_DEFAULT_ARGS: &[&str] = &[ - "-Zcodegen-backend=dummy", "--cfg=miri", "-Zalways-encode-mir", "-Zextra-const-ub-checks", diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_shl.rs b/src/tools/miri/tests/fail/intrinsics/unchecked_shl.rs index abb345938fa0e..e22d36c024d7c 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_shl.rs +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_shl.rs @@ -1,5 +1,3 @@ -#![feature(unchecked_shifts)] - fn main() { unsafe { let _n = 1i8.unchecked_shl(8); diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_shr.rs b/src/tools/miri/tests/fail/intrinsics/unchecked_shr.rs index cdc10185e4707..59402be4992b5 100644 --- a/src/tools/miri/tests/fail/intrinsics/unchecked_shr.rs +++ b/src/tools/miri/tests/fail/intrinsics/unchecked_shr.rs @@ -1,5 +1,3 @@ -#![feature(unchecked_shifts)] - fn main() { unsafe { let _n = 1i64.unchecked_shr(64); diff --git a/src/tools/miri/tests/pass/target-cpu-implies-target-feature.rs b/src/tools/miri/tests/pass/target-cpu-implies-target-feature.rs new file mode 100644 index 0000000000000..1acbd51ae81fe --- /dev/null +++ b/src/tools/miri/tests/pass/target-cpu-implies-target-feature.rs @@ -0,0 +1,16 @@ +// Test that target-cpu implies the correct target features +//@only-target: x86_64 +//@compile-flags: -C target-cpu=x86-64-v4 + +fn main() { + assert!(cfg!(target_feature = "avx2")); + assert!(cfg!(target_feature = "avx512bw")); + assert!(cfg!(target_feature = "avx512cd")); + assert!(cfg!(target_feature = "avx512dq")); + assert!(cfg!(target_feature = "avx512f")); + assert!(cfg!(target_feature = "avx512vl")); + assert!(is_x86_feature_detected!("avx512bw")); + + assert!(cfg!(not(target_feature = "avx512vpopcntdq"))); + assert!(!is_x86_feature_detected!("avx512vpopcntdq")); +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 7f4dad873cd6f..dedc12aa653fd 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -11840,34 +11840,6 @@ extern "rust-call" fn add_args(args: (u32, u32)) -> u32 { fn main() {} ``` -"##, - default_severity: Severity::Allow, - warn_since: None, - deny_since: None, - }, - Lint { - label: "unchecked_neg", - description: r##"# `unchecked_neg` - -The tracking issue for this feature is: [#85122] - -[#85122]: https://github.com/rust-lang/rust/issues/85122 - ------------------------- -"##, - default_severity: Severity::Allow, - warn_since: None, - deny_since: None, - }, - Lint { - label: "unchecked_shifts", - description: r##"# `unchecked_shifts` - -The tracking issue for this feature is: [#85122] - -[#85122]: https://github.com/rust-lang/rust/issues/85122 - ------------------------- "##, default_severity: Severity::Allow, warn_since: None, diff --git a/tests/codegen-llvm/checked_math.rs b/tests/codegen-llvm/checked_math.rs index 66667c6948818..f24d9f24dcb23 100644 --- a/tests/codegen-llvm/checked_math.rs +++ b/tests/codegen-llvm/checked_math.rs @@ -1,7 +1,6 @@ //@ compile-flags: -Copt-level=3 -Z merge-functions=disabled #![crate_type = "lib"] -#![feature(unchecked_shifts)] // Because the result of something like `u32::checked_sub` can only be used if it // didn't overflow, make sure that LLVM actually knows that in optimized builds. diff --git a/tests/codegen-llvm/unchecked_shifts.rs b/tests/codegen-llvm/unchecked_shifts.rs index 3f533718a2d0d..2e17a827f62f5 100644 --- a/tests/codegen-llvm/unchecked_shifts.rs +++ b/tests/codegen-llvm/unchecked_shifts.rs @@ -4,7 +4,6 @@ // optimizations so it doesn't need to worry about them adding more flags. #![crate_type = "lib"] -#![feature(unchecked_shifts)] #![feature(core_intrinsics)] // CHECK-LABEL: @unchecked_shl_unsigned_same diff --git a/tests/mir-opt/inline/unchecked_shifts.rs b/tests/mir-opt/inline/unchecked_shifts.rs index 122f099da4b7d..a20b13dc1149d 100644 --- a/tests/mir-opt/inline/unchecked_shifts.rs +++ b/tests/mir-opt/inline/unchecked_shifts.rs @@ -1,6 +1,5 @@ // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![crate_type = "lib"] -#![feature(unchecked_shifts)] //@ compile-flags: -Zmir-opt-level=2 -Zinline-mir diff --git a/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr index 8191f1f4394b7..60ff010193fd2 100644 --- a/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr +++ b/tests/ui/borrowck/issue-115259-suggest-iter-mut.stderr @@ -2,9 +2,7 @@ error[E0596]: cannot borrow `**layer` as mutable, as it is behind a `&` referenc --> $DIR/issue-115259-suggest-iter-mut.rs:15:65 | LL | self.layers.iter().fold(0, |result, mut layer| result + layer.process()) - | --------- ^^^^^ `layer` is a `&` reference, so it cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut Box` + | ^^^^^ `layer` is a `&` reference, so it cannot be borrowed as mutable | help: you may want to use `iter_mut` here | diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr index 29121b85f3a08..ba765f06a2c8f 100644 --- a/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut-2.stderr @@ -2,9 +2,7 @@ error[E0596]: cannot borrow `*container` as mutable, as it is behind a `&` refer --> $DIR/issue-62387-suggest-iter-mut-2.rs:30:45 | LL | vec.iter().flat_map(|container| container.things()).cloned().collect::>(); - | --------- ^^^^^^^^^ `container` is a `&` reference, so it cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut Container` + | ^^^^^^^^^ `container` is a `&` reference, so it cannot be borrowed as mutable | help: you may want to use `iter_mut` here | diff --git a/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr index 55c17ab6cdea1..677d71d85580d 100644 --- a/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr +++ b/tests/ui/borrowck/issue-62387-suggest-iter-mut.stderr @@ -2,9 +2,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/issue-62387-suggest-iter-mut.rs:18:27 | LL | v.iter().for_each(|a| a.double()); - | - ^ `a` is a `&` reference, so it cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut A` + | ^ `a` is a `&` reference, so it cannot be borrowed as mutable | help: you may want to use `iter_mut` here | @@ -15,9 +13,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/issue-62387-suggest-iter-mut.rs:25:39 | LL | v.iter().rev().rev().for_each(|a| a.double()); - | - ^ `a` is a `&` reference, so it cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut A` + | ^ `a` is a `&` reference, so it cannot be borrowed as mutable | help: you may want to use `iter_mut` here | diff --git a/tests/ui/borrowck/option-inspect-mutation.rs b/tests/ui/borrowck/option-inspect-mutation.rs new file mode 100644 index 0000000000000..038d06e7e6a91 --- /dev/null +++ b/tests/ui/borrowck/option-inspect-mutation.rs @@ -0,0 +1,18 @@ +//! Regression test for . + +struct Struct { + field: u32, +} + +fn main() { + let mut some_struct = Some(Struct { field: 42 }); + some_struct.as_mut().inspect(|some_struct| { + some_struct.field *= 10; //~ ERROR cannot assign to `some_struct.field`, which is behind a `&` reference + // Users can't change type of `some_struct` param, so above error must not suggest it. + }); + + // Same check as above but using `hir::ExprKind::Call` instead of `hir::ExprKind::MethodCall`. + Option::inspect(some_struct.as_mut(), |some_struct| { + some_struct.field *= 20; //~ ERROR cannot assign to `some_struct.field`, which is behind a `&` reference + }); +} diff --git a/tests/ui/borrowck/option-inspect-mutation.stderr b/tests/ui/borrowck/option-inspect-mutation.stderr new file mode 100644 index 0000000000000..1b6167b00e7e7 --- /dev/null +++ b/tests/ui/borrowck/option-inspect-mutation.stderr @@ -0,0 +1,15 @@ +error[E0594]: cannot assign to `some_struct.field`, which is behind a `&` reference + --> $DIR/option-inspect-mutation.rs:10:9 + | +LL | some_struct.field *= 10; + | ^^^^^^^^^^^^^^^^^^^^^^^ `some_struct` is a `&` reference, so it cannot be written to + +error[E0594]: cannot assign to `some_struct.field`, which is behind a `&` reference + --> $DIR/option-inspect-mutation.rs:16:9 + | +LL | some_struct.field *= 20; + | ^^^^^^^^^^^^^^^^^^^^^^^ `some_struct` is a `&` reference, so it cannot be written to + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr index ca0d0bd8a3caa..9b4061af967ed 100644 --- a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr +++ b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr @@ -18,9 +18,7 @@ error[E0596]: cannot borrow `*cb` as mutable, as it is behind a `&` reference --> $DIR/suggest-as-ref-on-mut-closure.rs:12:26 | LL | cb.as_ref().map(|cb| cb()); - | -- ^^ `cb` is a `&` reference, so it cannot be borrowed as mutable - | | - | consider changing this binding's type to be: `&mut &mut dyn FnMut()` + | ^^ `cb` is a `&` reference, so it cannot be borrowed as mutable error: aborting due to 2 previous errors diff --git a/tests/ui/check-cfg/cfg-select.rs b/tests/ui/check-cfg/cfg-select.rs new file mode 100644 index 0000000000000..39703489818d8 --- /dev/null +++ b/tests/ui/check-cfg/cfg-select.rs @@ -0,0 +1,18 @@ +//@ check-pass + +#![feature(cfg_select)] +#![crate_type = "lib"] + +cfg_select! { + true => {} + invalid_cfg1 => {} + //~^ WARN unexpected `cfg` condition name + _ => {} +} + +cfg_select! { + invalid_cfg2 => {} + //~^ WARN unexpected `cfg` condition name + true => {} + _ => {} +} diff --git a/tests/ui/check-cfg/cfg-select.stderr b/tests/ui/check-cfg/cfg-select.stderr new file mode 100644 index 0000000000000..23ed5918e71ce --- /dev/null +++ b/tests/ui/check-cfg/cfg-select.stderr @@ -0,0 +1,22 @@ +warning: unexpected `cfg` condition name: `invalid_cfg1` + --> $DIR/cfg-select.rs:8:5 + | +LL | invalid_cfg1 => {} + | ^^^^^^^^^^^^ + | + = help: expected names are: `FALSE` and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(invalid_cfg1)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `invalid_cfg2` + --> $DIR/cfg-select.rs:14:5 + | +LL | invalid_cfg2 => {} + | ^^^^^^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(invalid_cfg2)` + = note: see for more information about checking conditional configuration + +warning: 2 warnings emitted + diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/liveness-ice-issue-146445.rs b/tests/ui/pattern/rfc-3637-guard-patterns/liveness-ice-issue-146445.rs new file mode 100644 index 0000000000000..2612cb689954e --- /dev/null +++ b/tests/ui/pattern/rfc-3637-guard-patterns/liveness-ice-issue-146445.rs @@ -0,0 +1,21 @@ +//@ check-pass +//! Regression test for issue #146445. +//! +//! This test ensures that liveness linting works correctly with guard patterns +//! and doesn't cause an ICE ("no successor") when using variables without +//! underscore prefixes in guard expressions. +//! +//! Fixed by #142390 which moved liveness analysis to MIR. + +#![feature(guard_patterns)] +#![expect(incomplete_features)] + +fn main() { + // This used to ICE before liveness analysis was moved to MIR. + // The variable `main` (without underscore prefix) would trigger + // liveness linting which wasn't properly implemented for guard patterns. + match (0,) { + (_ if { let main = false; main },) => {} + _ => {} + } +} diff --git a/tests/ui/precondition-checks/unchecked_shl.rs b/tests/ui/precondition-checks/unchecked_shl.rs index 57c617e08455b..20eaeb2dbaeac 100644 --- a/tests/ui/precondition-checks/unchecked_shl.rs +++ b/tests/ui/precondition-checks/unchecked_shl.rs @@ -2,8 +2,6 @@ //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_shl cannot overflow -#![feature(unchecked_shifts)] - fn main() { unsafe { 0u8.unchecked_shl(u8::BITS); diff --git a/tests/ui/precondition-checks/unchecked_shr.rs b/tests/ui/precondition-checks/unchecked_shr.rs index 18502d2b64593..c66fd3729a71f 100644 --- a/tests/ui/precondition-checks/unchecked_shr.rs +++ b/tests/ui/precondition-checks/unchecked_shr.rs @@ -2,8 +2,6 @@ //@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: u8::unchecked_shr cannot overflow -#![feature(unchecked_shifts)] - fn main() { unsafe { 0u8.unchecked_shr(u8::BITS);