diff options
| author | bors <bors@rust-lang.org> | 2025-02-07 17:56:45 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-02-07 17:56:45 +0000 |
| commit | a9e7b30487235621751cc628f170c0f15fb215c4 (patch) | |
| tree | dd52a558529c0170e5d6dc6ce1ffe28afeb58694 /compiler | |
| parent | 64e06c0f5578829373743884b708d494136c3e8f (diff) | |
| parent | b4c4913abbbd0d050d6fb4abd323c1065fe6dc41 (diff) | |
| download | rust-a9e7b30487235621751cc628f170c0f15fb215c4.tar.gz rust-a9e7b30487235621751cc628f170c0f15fb215c4.zip | |
Auto merge of #136697 - matthiaskrgr:rollup-eww4vl9, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #134367 (Stabilize `feature(trait_upcasting)`) - #135940 (Update toolstate maintainers) - #135945 (Remove some unnecessary parens in `assert!` conditions) - #136577 (Pattern Migration 2024: try to suggest eliding redundant binding modifiers) - #136598 (Fix suggestion for `dependency_on_unit_never_type_fallback` involving closures + format args expansions) - #136653 (Remove dead code from rustc_codegen_llvm and the LLVM wrapper) - #136664 (replace one `.map_or(true, ...)` with `.is_none_or(...)`) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
18 files changed, 266 insertions, 260 deletions
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 0d04f770bc6..50a40c9c309 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -69,19 +69,6 @@ pub enum LLVMRustResult { Failure, } -/// Translation of LLVM's MachineTypes enum, defined in llvm\include\llvm\BinaryFormat\COFF.h. -/// -/// We include only architectures supported on Windows. -#[derive(Copy, Clone, PartialEq)] -#[repr(C)] -pub enum LLVMMachineType { - AMD64 = 0x8664, - I386 = 0x14c, - ARM64 = 0xaa64, - ARM64EC = 0xa641, - ARM = 0x01c0, -} - /// Must match the layout of `LLVMRustModuleFlagMergeBehavior`. /// /// When merging modules (e.g. during LTO), their metadata flags are combined. Conflicts are @@ -645,16 +632,6 @@ pub enum ThreadLocalMode { LocalExec, } -/// LLVMRustTailCallKind -#[derive(Copy, Clone)] -#[repr(C)] -pub enum TailCallKind { - None, - Tail, - MustTail, - NoTail, -} - /// LLVMRustChecksumKind #[derive(Copy, Clone)] #[repr(C)] @@ -773,7 +750,6 @@ pub struct Builder<'a>(InvariantOpaque<'a>); #[repr(C)] pub struct PassManager<'a>(InvariantOpaque<'a>); unsafe extern "C" { - pub type Pass; pub type TargetMachine; pub type Archive; } @@ -799,7 +775,6 @@ unsafe extern "C" { } pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void); -pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint); pub mod debuginfo { use std::ptr; @@ -853,7 +828,6 @@ pub mod debuginfo { pub type DIFile = DIScope; pub type DILexicalBlock = DIScope; pub type DISubprogram = DIScope; - pub type DINameSpace = DIScope; pub type DIType = DIDescriptor; pub type DIBasicType = DIType; pub type DIDerivedType = DIType; @@ -1809,7 +1783,6 @@ unsafe extern "C" { Name: *const c_char, NameLen: size_t, ) -> Option<&Value>; - pub fn LLVMRustSetTailCallKind(CallInst: &Value, TKC: TailCallKind); // Operations on attributes pub fn LLVMRustCreateAttrNoValue(C: &Context, attr: AttributeKind) -> &Attribute; @@ -2586,8 +2559,6 @@ unsafe extern "C" { pub fn LLVMRustGetElementTypeArgIndex(CallSite: &Value) -> i32; - pub fn LLVMRustIsBitcode(ptr: *const u8, len: usize) -> bool; - pub fn LLVMRustLLVMHasZlibCompressionForDebugSymbols() -> bool; pub fn LLVMRustLLVMHasZstdCompressionForDebugSymbols() -> bool; diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 6c431086414..822cf4982b5 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -400,6 +400,9 @@ declare_features! ( /// Allows `#[track_caller]` to be used which provides /// accurate caller location reporting during panic (RFC 2091). (accepted, track_caller, "1.46.0", Some(47809)), + /// Allows dyn upcasting trait objects via supertraits. + /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. + (accepted, trait_upcasting, "CURRENT_RUSTC_VERSION", Some(65991)), /// Allows #[repr(transparent)] on univariant enums (RFC 2645). (accepted, transparent_enums, "1.42.0", Some(60405)), /// Allows indexing tuples. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 094962b265b..3a2e810dc6a 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -634,9 +634,6 @@ declare_features! ( (unstable, thread_local, "1.0.0", Some(29594)), /// Allows defining `trait X = A + B;` alias items. (unstable, trait_alias, "1.24.0", Some(41517)), - /// Allows dyn upcasting trait objects via supertraits. - /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. - (unstable, trait_upcasting, "1.56.0", Some(65991)), /// Allows for transmuting between arrays with sizes that contain generic consts. (unstable, transmute_generic_consts, "1.70.0", Some(109929)), /// Allows #[repr(transparent)] on unions (RFC 2645). diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 83acc7dd6af..56cc9b6d551 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -605,7 +605,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { )]; let mut has_unsized_tuple_coercion = false; - let mut has_trait_upcasting_coercion = None; // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where @@ -690,13 +689,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // these here and emit a feature error if coercion doesn't fail // due to another reason. match impl_source { - traits::ImplSource::Builtin( - BuiltinImplSource::TraitUpcasting { .. }, - _, - ) => { - has_trait_upcasting_coercion = - Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1))); - } traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { has_unsized_tuple_coercion = true; } @@ -707,21 +699,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } - if let Some((sub, sup)) = has_trait_upcasting_coercion - && !self.tcx().features().trait_upcasting() - { - // Renders better when we erase regions, since they're not really the point here. - let (sub, sup) = self.tcx.erase_regions((sub, sup)); - let mut err = feature_err( - &self.tcx.sess, - sym::trait_upcasting, - self.cause.span, - format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"), - ); - err.note(format!("required when coercing `{source}` into `{target}`")); - err.emit(); - } - if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion() { feature_err( &self.tcx.sess, diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 1f3f03b9929..4618c5d3849 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -651,6 +651,7 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> { if let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(inf_id) && let Some(vid) = self.fcx.root_vid(ty) && self.reachable_vids.contains(&vid) + && inf_span.can_be_used_for_suggestions() { return ControlFlow::Break(errors::SuggestAnnotation::Unit(inf_span)); } @@ -662,7 +663,7 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> { &mut self, qpath: &'tcx rustc_hir::QPath<'tcx>, id: HirId, - _span: Span, + span: Span, ) -> Self::Result { let arg_segment = match qpath { hir::QPath::Resolved(_, path) => { @@ -674,13 +675,21 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> { } }; // Alternatively, try to turbofish `::<_, (), _>`. - if let Some(def_id) = self.fcx.typeck_results.borrow().qpath_res(qpath, id).opt_def_id() { + if let Some(def_id) = self.fcx.typeck_results.borrow().qpath_res(qpath, id).opt_def_id() + && span.can_be_used_for_suggestions() + { self.suggest_for_segment(arg_segment, def_id, id)?; } hir::intravisit::walk_qpath(self, qpath, id) } fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result { + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) + | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) = expr.kind + { + self.visit_body(self.fcx.tcx.hir().body(body))?; + } + // Try to suggest adding an explicit qself `()` to a trait method path. // i.e. changing `Default::default()` to `<() as Default>::default()`. if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind @@ -691,17 +700,21 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> { && let Some(vid) = self.fcx.root_vid(self_ty) && self.reachable_vids.contains(&vid) && let [.., trait_segment, _method_segment] = path.segments + && expr.span.can_be_used_for_suggestions() { let span = path.span.shrink_to_lo().to(trait_segment.ident.span); return ControlFlow::Break(errors::SuggestAnnotation::Path(span)); } + // Or else, try suggesting turbofishing the method args. if let hir::ExprKind::MethodCall(segment, ..) = expr.kind && let Some(def_id) = self.fcx.typeck_results.borrow().type_dependent_def_id(expr.hir_id) + && expr.span.can_be_used_for_suggestions() { self.suggest_for_segment(segment, def_id, expr.hir_id)?; } + hir::intravisit::walk_expr(self, expr) } @@ -712,6 +725,7 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> { && let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(local.hir_id) && let Some(vid) = self.fcx.root_vid(ty) && self.reachable_vids.contains(&vid) + && local.span.can_be_used_for_suggestions() { return ControlFlow::Break(errors::SuggestAnnotation::Local( local.pat.span.shrink_to_hi(), diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 2e7415cec5d..7c2a2b3fdf7 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -812,7 +812,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Determine the binding mode... let bm = match user_bind_annot { - BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => { + BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => { // Only mention the experimental `mut_ref` feature if if we're in edition 2024 and // using other experimental matching features compatible with it. if pat.span.at_least_rust_2024() @@ -834,22 +834,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `mut` resets the binding mode on edition <= 2021 self.add_rust_2024_migration_desugared_pat( pat_info.top_info.hir_id, - pat.span, + pat, ident.span, - "requires binding by-value, but the implicit default is by-reference", + def_br_mutbl, ); BindingMode(ByRef::No, Mutability::Mut) } } BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl), BindingMode(ByRef::Yes(_), _) => { - if matches!(def_br, ByRef::Yes(_)) { + if let ByRef::Yes(def_br_mutbl) = def_br { // `ref`/`ref mut` overrides the binding mode on edition <= 2021 self.add_rust_2024_migration_desugared_pat( pat_info.top_info.hir_id, - pat.span, + pat, ident.span, - "cannot override to bind by-reference when that is the implicit default", + def_br_mutbl, ); } user_bind_annot @@ -2386,9 +2386,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_info.binding_mode = ByRef::No; self.add_rust_2024_migration_desugared_pat( pat_info.top_info.hir_id, - pat.span, + pat, inner.span, - "cannot implicitly match against multiple layers of reference", + inh_mut, ) } } @@ -2778,33 +2778,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn add_rust_2024_migration_desugared_pat( &self, pat_id: HirId, - subpat_span: Span, + subpat: &'tcx Pat<'tcx>, cutoff_span: Span, - detailed_label: &str, + def_br_mutbl: Mutability, ) { // Try to trim the span we're labeling to just the `&` or binding mode that's an issue. // If the subpattern's span is is from an expansion, the emitted label will not be trimmed. let source_map = self.tcx.sess.source_map(); let cutoff_span = source_map - .span_extend_prev_while(cutoff_span, char::is_whitespace) + .span_extend_prev_while(cutoff_span, |c| c.is_whitespace() || c == '(') .unwrap_or(cutoff_span); - // Ensure we use the syntax context and thus edition of `subpat_span`; this will be a hard + // Ensure we use the syntax context and thus edition of `subpat.span`; this will be a hard // error if the subpattern is of edition >= 2024. - let trimmed_span = subpat_span.until(cutoff_span).with_ctxt(subpat_span.ctxt()); + let trimmed_span = subpat.span.until(cutoff_span).with_ctxt(subpat.span.ctxt()); + + let mut typeck_results = self.typeck_results.borrow_mut(); + let mut table = typeck_results.rust_2024_migration_desugared_pats_mut(); + // FIXME(ref_pat_eat_one_layer_2024): The migration diagnostic doesn't know how to track the + // default binding mode in the presence of Rule 3 or Rule 5. As a consequence, the labels it + // gives for default binding modes are wrong, as well as suggestions based on the default + // binding mode. This keeps it from making those suggestions, as doing so could panic. + let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo { + primary_labels: Vec::new(), + bad_modifiers: false, + bad_ref_pats: false, + suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024() + && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(), + }); // Only provide a detailed label if the problematic subpattern isn't from an expansion. // In the case that it's from a macro, we'll add a more detailed note in the emitter. - let desc = if subpat_span.from_expansion() { - "default binding mode is reset within expansion" + let from_expansion = subpat.span.from_expansion(); + let primary_label = if from_expansion { + // NB: This wording assumes the only expansions that can produce problematic reference + // patterns and bindings are macros. If a desugaring or AST pass is added that can do + // so, we may want to inspect the span's source callee or macro backtrace. + "occurs within macro expansion".to_owned() } else { - detailed_label + let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind { + info.bad_modifiers |= true; + // If the user-provided binding modifier doesn't match the default binding mode, we'll + // need to suggest reference patterns, which can affect other bindings. + // For simplicity, we opt to suggest making the pattern fully explicit. + info.suggest_eliding_modes &= + user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not); + "binding modifier" + } else { + info.bad_ref_pats |= true; + // For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll + // suggest adding them instead, which can affect the types assigned to bindings. + // As such, we opt to suggest making the pattern fully explicit. + info.suggest_eliding_modes = false; + "reference pattern" + }; + let dbm_str = match def_br_mutbl { + Mutability::Not => "ref", + Mutability::Mut => "ref mut", + }; + format!("{pat_kind} not allowed under `{dbm_str}` default binding mode") }; - - self.typeck_results - .borrow_mut() - .rust_2024_migration_desugared_pats_mut() - .entry(pat_id) - .or_default() - .push((trimmed_span, desc.to_owned())); + info.primary_labels.push((trimmed_span, primary_label)); } } diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index 657642e093c..181f44fb4de 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -1,6 +1,5 @@ use rustc_hir::{self as hir, LangItem}; use rustc_middle::ty; -use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::sym; use rustc_trait_selection::traits::supertraits; @@ -9,11 +8,12 @@ use crate::lints::{SupertraitAsDerefTarget, SupertraitAsDerefTargetLabel}; use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { - /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the - /// `Deref` implementation with a `dyn SuperTrait` type as `Output`. + /// The `deref_into_dyn_supertrait` lint is emitted whenever there is a `Deref` implementation + /// for `dyn SubTrait` with a `dyn SuperTrait` type as the `Output` type. /// - /// These implementations will become shadowed when the `trait_upcasting` feature is stabilized. - /// The `deref` functions will no longer be called implicitly, so there might be behavior change. + /// These implementations are "shadowed" by trait upcasting (stabilized since + /// CURRENT_RUSTC_VERSION). The `deref` functions is no longer called implicitly, which might + /// change behavior compared to previous rustc versions. /// /// ### Example /// @@ -43,15 +43,14 @@ declare_lint! { /// /// ### Explanation /// - /// The dyn upcasting coercion feature adds new coercion rules, taking priority - /// over certain other coercion rules, which will cause some behavior change. + /// The trait upcasting coercion added a new coercion rule, taking priority over certain other + /// coercion rules, which causes some behavior change compared to older `rustc` versions. + /// + /// `deref` can be still called explicitly, it just isn't called as part of a deref coercion + /// (since trait upcasting coercion takes priority). pub DEREF_INTO_DYN_SUPERTRAIT, - Warn, - "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange, - reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>", - }; + Allow, + "`Deref` implementation with a supertrait trait object for output is shadowed by trait upcasting", } declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index fd6c17735c5..3e97f4c86ba 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -21,6 +21,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(trait_upcasting))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] @@ -32,7 +33,6 @@ #![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![feature(trait_upcasting)] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 76ad7fc8909..b8cef6a7e25 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -195,33 +195,6 @@ LLVMRustVerifyFunction(LLVMValueRef Fn, LLVMRustVerifierFailureAction Action) { return LLVMVerifyFunction(Fn, fromRust(Action)); } -enum class LLVMRustTailCallKind { - None, - Tail, - MustTail, - NoTail, -}; - -static CallInst::TailCallKind fromRust(LLVMRustTailCallKind Kind) { - switch (Kind) { - case LLVMRustTailCallKind::None: - return CallInst::TailCallKind::TCK_None; - case LLVMRustTailCallKind::Tail: - return CallInst::TailCallKind::TCK_Tail; - case LLVMRustTailCallKind::MustTail: - return CallInst::TailCallKind::TCK_MustTail; - case LLVMRustTailCallKind::NoTail: - return CallInst::TailCallKind::TCK_NoTail; - default: - report_fatal_error("bad CallInst::TailCallKind."); - } -} - -extern "C" void LLVMRustSetTailCallKind(LLVMValueRef Call, - LLVMRustTailCallKind TCK) { - unwrap<CallInst>(Call)->setTailCallKind(fromRust(TCK)); -} - extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, const char *Name, size_t NameLen, @@ -1976,10 +1949,6 @@ extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) { return -1; } -extern "C" bool LLVMRustIsBitcode(char *ptr, size_t len) { - return identify_magic(StringRef(ptr, len)) == file_magic::bitcode; -} - extern "C" bool LLVMRustIsNonGVFunctionPointerTy(LLVMValueRef V) { if (unwrap<Value>(V)->getType()->isPointerTy()) { if (auto *GV = dyn_cast<GlobalValue>(unwrap<Value>(V))) { diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 7a6d329fd47..95128a5d903 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,6 +29,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(trait_upcasting))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] @@ -56,7 +57,6 @@ #![feature(ptr_alignment_type)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![feature(trait_upcasting)] #![feature(trusted_len)] #![feature(try_blocks)] #![feature(try_trait_v2)] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 88eea6101b5..6fe1502c66d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -94,7 +94,7 @@ pub use self::sty::{ pub use self::trait_def::TraitDef; pub use self::typeck_results::{ CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity, - TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind, + Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind, }; pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 3c6ed997845..49bdb5e9dc3 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -73,9 +73,9 @@ pub struct TypeckResults<'tcx> { /// Stores the actual binding mode for all instances of [`BindingMode`]. pat_binding_modes: ItemLocalMap<BindingMode>, - /// Top-level patterns whose match ergonomics need to be desugared by the Rust 2021 -> 2024 - /// migration lint. Problematic subpatterns are stored in the `Vec` for the lint to highlight. - rust_2024_migration_desugared_pats: ItemLocalMap<Vec<(Span, String)>>, + /// Top-level patterns incompatible with Rust 2024's match ergonomics. These will be translated + /// to a form valid in all Editions, either as a lint diagnostic or hard error. + rust_2024_migration_desugared_pats: ItemLocalMap<Rust2024IncompatiblePatInfo>, /// Stores the types which were implicitly dereferenced in pattern binding modes /// for later usage in THIR lowering. For example, @@ -420,7 +420,7 @@ impl<'tcx> TypeckResults<'tcx> { pub fn rust_2024_migration_desugared_pats( &self, - ) -> LocalTableInContext<'_, Vec<(Span, String)>> { + ) -> LocalTableInContext<'_, Rust2024IncompatiblePatInfo> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.rust_2024_migration_desugared_pats, @@ -429,7 +429,7 @@ impl<'tcx> TypeckResults<'tcx> { pub fn rust_2024_migration_desugared_pats_mut( &mut self, - ) -> LocalTableInContextMut<'_, Vec<(Span, String)>> { + ) -> LocalTableInContextMut<'_, Rust2024IncompatiblePatInfo> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.rust_2024_migration_desugared_pats, @@ -811,3 +811,17 @@ impl<'tcx> std::fmt::Display for UserTypeKind<'tcx> { } } } + +/// Information on a pattern incompatible with Rust 2024, for use by the error/migration diagnostic +/// emitted during THIR construction. +#[derive(TyEncodable, TyDecodable, Debug, HashStable)] +pub struct Rust2024IncompatiblePatInfo { + /// Labeled spans for `&`s, `&mut`s, and binding modifiers incompatible with Rust 2024. + pub primary_labels: Vec<(Span, String)>, + /// Whether any binding modifiers occur under a non-`move` default binding mode. + pub bad_modifiers: bool, + /// Whether any `&` or `&mut` patterns occur under a non-`move` default binding mode. + pub bad_ref_pats: bool, + /// If `true`, we can give a simpler suggestion solely by eliding explicit binding modifiers. + pub suggest_eliding_modes: bool, +} diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 3cf3c332893..fae159103e7 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -285,7 +285,16 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future -mir_build_rust_2024_incompatible_pat = this pattern relies on behavior which may change in edition 2024 +mir_build_rust_2024_incompatible_pat = {$bad_modifiers -> + *[true] binding modifiers{$bad_ref_pats -> + *[true] {" "}and reference patterns + [false] {""} + } + [false] reference patterns + } may only be written when the default binding mode is `move`{$is_hard_error -> + *[true] {""} + [false] {" "}in Rust 2024 + } mir_build_static_in_pattern = statics cannot be referenced in patterns .label = can't be used in patterns diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index af6f33d9cdd..07bdc59756a 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, @@ -1097,41 +1098,70 @@ pub(crate) enum MiscPatternSuggestion { #[derive(LintDiagnostic)] #[diag(mir_build_rust_2024_incompatible_pat)] -pub(crate) struct Rust2024IncompatiblePat<'a> { +pub(crate) struct Rust2024IncompatiblePat { #[subdiagnostic] - pub(crate) sugg: Rust2024IncompatiblePatSugg<'a>, + pub(crate) sugg: Rust2024IncompatiblePatSugg, + pub(crate) bad_modifiers: bool, + pub(crate) bad_ref_pats: bool, + pub(crate) is_hard_error: bool, } -pub(crate) struct Rust2024IncompatiblePatSugg<'a> { +pub(crate) struct Rust2024IncompatiblePatSugg { + /// If true, our suggestion is to elide explicit binding modifiers. + /// If false, our suggestion is to make the pattern fully explicit. + pub(crate) suggest_eliding_modes: bool, pub(crate) suggestion: Vec<(Span, String)>, pub(crate) ref_pattern_count: usize, pub(crate) binding_mode_count: usize, - /// Labeled spans for subpatterns invalid in Rust 2024. - pub(crate) labels: &'a [(Span, String)], + /// Internal state: the ref-mutability of the default binding mode at the subpattern being + /// lowered, with the span where it was introduced. `None` for a by-value default mode. + pub(crate) default_mode_span: Option<(Span, ty::Mutability)>, + /// Labels for where incompatibility-causing by-ref default binding modes were introduced. + pub(crate) default_mode_labels: FxIndexMap<Span, ty::Mutability>, } -impl<'a> Subdiagnostic for Rust2024IncompatiblePatSugg<'a> { +impl Subdiagnostic for Rust2024IncompatiblePatSugg { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, _f: &F, ) { + // Format and emit explanatory notes about default binding modes. Reversing the spans' order + // means if we have nested spans, the innermost ones will be visited first. + for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() { + // Don't point to a macro call site. + if !span.from_expansion() { + let note_msg = "matching on a reference type with a non-reference pattern changes the default binding mode"; + let label_msg = + format!("this matches on type `{}_`", def_br_mutbl.ref_prefix_str()); + let mut label = MultiSpan::from(span); + label.push_span_label(span, label_msg); + diag.span_note(label, note_msg); + } + } + + // Format and emit the suggestion. let applicability = if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect }; - let plural_derefs = pluralize!(self.ref_pattern_count); - let and_modes = if self.binding_mode_count > 0 { - format!(" and variable binding mode{}", pluralize!(self.binding_mode_count)) + let msg = if self.suggest_eliding_modes { + let plural_modes = pluralize!(self.binding_mode_count); + format!("remove the unnecessary binding modifier{plural_modes}") } else { - String::new() + let plural_derefs = pluralize!(self.ref_pattern_count); + let and_modes = if self.binding_mode_count > 0 { + format!(" and variable binding mode{}", pluralize!(self.binding_mode_count)) + } else { + String::new() + }; + format!("make the implied reference pattern{plural_derefs}{and_modes} explicit") }; - diag.multipart_suggestion_verbose( - format!("make the implied reference pattern{plural_derefs}{and_modes} explicit"), - self.suggestion, - applicability, - ); + // FIXME(dianne): for peace of mind, don't risk emitting a 0-part suggestion (that panics!) + if !self.suggestion.is_empty() { + diag.multipart_suggestion_verbose(msg, self.suggestion, applicability); + } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index c862d012f4e..83fef7b0de6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -35,7 +35,7 @@ struct PatCtxt<'a, 'tcx> { typeck_results: &'a ty::TypeckResults<'tcx>, /// Used by the Rust 2024 migration lint. - rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg<'a>>, + rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg>, } pub(super) fn pat_from_hir<'a, 'tcx>( @@ -44,25 +44,30 @@ pub(super) fn pat_from_hir<'a, 'tcx>( typeck_results: &'a ty::TypeckResults<'tcx>, pat: &'tcx hir::Pat<'tcx>, ) -> Box<Pat<'tcx>> { + let migration_info = typeck_results.rust_2024_migration_desugared_pats().get(pat.hir_id); let mut pcx = PatCtxt { tcx, typing_env, typeck_results, - rust_2024_migration_suggestion: typeck_results - .rust_2024_migration_desugared_pats() - .get(pat.hir_id) - .map(|labels| Rust2024IncompatiblePatSugg { + rust_2024_migration_suggestion: migration_info.and_then(|info| { + Some(Rust2024IncompatiblePatSugg { + suggest_eliding_modes: info.suggest_eliding_modes, suggestion: Vec::new(), ref_pattern_count: 0, binding_mode_count: 0, - labels: labels.as_slice(), - }), + default_mode_span: None, + default_mode_labels: Default::default(), + }) + }), }; let result = pcx.lower_pattern(pat); debug!("pat_from_hir({:?}) = {:?}", pat, result); - if let Some(sugg) = pcx.rust_2024_migration_suggestion { - let mut spans = MultiSpan::from_spans(sugg.labels.iter().map(|(span, _)| *span).collect()); - for (span, label) in sugg.labels { + if let Some(info) = migration_info + && let Some(sugg) = pcx.rust_2024_migration_suggestion + { + let mut spans = + MultiSpan::from_spans(info.primary_labels.iter().map(|(span, _)| *span).collect()); + for (span, label) in &info.primary_labels { spans.push_span_label(*span, label.clone()); } // If a relevant span is from at least edition 2024, this is a hard error. @@ -70,10 +75,13 @@ pub(super) fn pat_from_hir<'a, 'tcx>( if is_hard_error { let mut err = tcx.dcx().struct_span_err(spans, fluent::mir_build_rust_2024_incompatible_pat); - if let Some(info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible { + if let Some(lint_info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible { // provide the same reference link as the lint - err.note(format!("for more information, see {}", info.reference)); + err.note(format!("for more information, see {}", lint_info.reference)); } + err.arg("bad_modifiers", info.bad_modifiers); + err.arg("bad_ref_pats", info.bad_ref_pats); + err.arg("is_hard_error", true); err.subdiagnostic(sugg); err.emit(); } else { @@ -81,7 +89,12 @@ pub(super) fn pat_from_hir<'a, 'tcx>( lint::builtin::RUST_2024_INCOMPATIBLE_PAT, pat.hir_id, spans, - Rust2024IncompatiblePat { sugg }, + Rust2024IncompatiblePat { + sugg, + bad_modifiers: info.bad_modifiers, + bad_ref_pats: info.bad_ref_pats, + is_hard_error, + }, ); } } @@ -90,6 +103,35 @@ pub(super) fn pat_from_hir<'a, 'tcx>( impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> { + let adjustments: &[Ty<'tcx>] = + self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v); + + let mut opt_old_mode_span = None; + if let Some(s) = &mut self.rust_2024_migration_suggestion + && !adjustments.is_empty() + { + let implicit_deref_mutbls = adjustments.iter().map(|ref_ty| { + let &ty::Ref(_, _, mutbl) = ref_ty.kind() else { + span_bug!(pat.span, "pattern implicitly dereferences a non-ref type"); + }; + mutbl + }); + + if !s.suggest_eliding_modes { + let suggestion_str: String = + implicit_deref_mutbls.clone().map(|mutbl| mutbl.ref_prefix_str()).collect(); + s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str)); + s.ref_pattern_count += adjustments.len(); + } + + // Remember if this changed the default binding mode, in case we want to label it. + let min_mutbl = implicit_deref_mutbls.min().unwrap(); + if s.default_mode_span.is_none_or(|(_, old_mutbl)| min_mutbl < old_mutbl) { + opt_old_mode_span = Some(s.default_mode_span); + s.default_mode_span = Some((pat.span, min_mutbl)); + } + }; + // When implicit dereferences have been inserted in this pattern, the unadjusted lowered // pattern has the type that results *after* dereferencing. For example, in this code: // @@ -118,8 +160,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => self.lower_pattern_unadjusted(pat), }; - let adjustments: &[Ty<'tcx>] = - self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v); let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| { debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty); Box::new(Pat { @@ -130,24 +170,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }); if let Some(s) = &mut self.rust_2024_migration_suggestion - && !adjustments.is_empty() + && let Some(old_mode_span) = opt_old_mode_span { - let suggestion_str: String = adjustments - .iter() - .map(|ref_ty| { - let &ty::Ref(_, _, mutbl) = ref_ty.kind() else { - span_bug!(pat.span, "pattern implicitly dereferences a non-ref type"); - }; - - match mutbl { - ty::Mutability::Not => "&", - ty::Mutability::Mut => "&mut ", - } - }) - .collect(); - s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str)); - s.ref_pattern_count += adjustments.len(); - }; + s.default_mode_span = old_mode_span; + } adjusted_pat } @@ -340,7 +366,22 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), mutability } } - hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => { + hir::PatKind::Ref(subpattern, _) => { + // Track the default binding mode for the Rust 2024 migration suggestion. + let old_mode_span = self.rust_2024_migration_suggestion.as_mut().and_then(|s| { + if let Some((default_mode_span, default_ref_mutbl)) = s.default_mode_span { + // If this eats a by-ref default binding mode, label the binding mode. + s.default_mode_labels.insert(default_mode_span, default_ref_mutbl); + } + s.default_mode_span.take() + }); + let subpattern = self.lower_pattern(subpattern); + if let Some(s) = &mut self.rust_2024_migration_suggestion { + s.default_mode_span = old_mode_span; + } + PatKind::Deref { subpattern } + } + hir::PatKind::Box(subpattern) => { PatKind::Deref { subpattern: self.lower_pattern(subpattern) } } @@ -367,19 +408,32 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .get(pat.hir_id) .expect("missing binding mode"); - if let Some(s) = &mut self.rust_2024_migration_suggestion - && explicit_ba.0 == ByRef::No - && let ByRef::Yes(mutbl) = mode.0 - { - let sugg_str = match mutbl { - Mutability::Not => "ref ", - Mutability::Mut => "ref mut ", - }; - s.suggestion.push(( - pat.span.with_lo(ident.span.lo()).shrink_to_lo(), - sugg_str.to_owned(), - )); - s.binding_mode_count += 1; + if let Some(s) = &mut self.rust_2024_migration_suggestion { + if explicit_ba != hir::BindingMode::NONE + && let Some((default_mode_span, default_ref_mutbl)) = s.default_mode_span + { + // If this overrides a by-ref default binding mode, label the binding mode. + s.default_mode_labels.insert(default_mode_span, default_ref_mutbl); + // If our suggestion is to elide redundnt modes, this will be one of them. + if s.suggest_eliding_modes { + s.suggestion.push((pat.span.with_hi(ident.span.lo()), String::new())); + s.binding_mode_count += 1; + } + } + if !s.suggest_eliding_modes + && explicit_ba.0 == ByRef::No + && let ByRef::Yes(mutbl) = mode.0 + { + let sugg_str = match mutbl { + Mutability::Not => "ref ", + Mutability::Mut => "ref mut ", + }; + s.suggestion.push(( + pat.span.with_lo(ident.span.lo()).shrink_to_lo(), + sugg_str.to_owned(), + )); + s.binding_mode_count += 1; + } } // A ref x pattern is the same node used for x, and as such it has diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index a0d41110d96..0bfd72c6848 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -142,7 +142,7 @@ where // Remove any trivial region constraints once we've resolved regions external_constraints .region_constraints - .retain(|outlives| outlives.0.as_region().map_or(true, |re| re != outlives.1)); + .retain(|outlives| outlives.0.as_region().is_none_or(|re| re != outlives.1)); let canonical = Canonicalizer::canonicalize_response( self.delegate, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 13a6744c2e9..e495bdbf782 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -12,9 +12,7 @@ use hir::LangItem; use hir::def_id::DefId; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_hir as hir; -use rustc_infer::traits::{ - Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError, -}; +use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; @@ -23,8 +21,6 @@ use tracing::{debug, instrument, trace}; use super::SelectionCandidate::*; use super::{BuiltinImplConditions, SelectionCandidateSet, SelectionContext, TraitObligationStack}; -use crate::traits; -use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::util; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { @@ -904,54 +900,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } - /// Temporary migration for #89190 - fn need_migrate_deref_output_trait_object( - &mut self, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: &ObligationCause<'tcx>, - ) -> Option<ty::PolyExistentialTraitRef<'tcx>> { - // Don't drop any candidates in intercrate mode, as it's incomplete. - // (Not that it matters, since `Unsize` is not a stable trait.) - // - // FIXME(@lcnr): This should probably only trigger during analysis, - // disabling candidates during codegen is also questionable. - if let TypingMode::Coherence = self.infcx.typing_mode() { - return None; - } - - let tcx = self.tcx(); - if tcx.features().trait_upcasting() { - return None; - } - - // <ty as Deref> - let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]); - - let obligation = - traits::Obligation::new(tcx, cause.clone(), param_env, ty::Binder::dummy(trait_ref)); - if !self.infcx.predicate_may_hold(&obligation) { - return None; - } - - self.infcx.probe(|_| { - let ty = traits::normalize_projection_ty( - self, - param_env, - ty::AliasTy::new_from_args(tcx, tcx.lang_items().deref_target()?, trait_ref.args), - cause.clone(), - 0, - // We're *intentionally* throwing these away, - // since we don't actually use them. - &mut PredicateObligations::new(), - ) - .as_type() - .unwrap(); - - if let ty::Dynamic(data, ..) = ty.kind() { data.principal() } else { None } - }) - } - /// Searches for unsizing that might apply to `obligation`. fn assemble_candidates_for_unsizing( &mut self, @@ -1019,15 +967,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let principal_a = a_data.principal().unwrap(); let target_trait_did = principal_def_id_b.unwrap(); let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); - if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( - source, - obligation.param_env, - &obligation.cause, - ) { - if deref_trait_ref.def_id() == target_trait_did { - return; - } - } for (idx, upcast_trait_ref) in util::supertraits(self.tcx(), source_trait_ref).enumerate() diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index c06004d4d0f..a562b751d8a 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -179,9 +179,7 @@ pub enum BuiltinImplSource { Object(usize), /// A built-in implementation of `Upcast` for trait objects to other trait objects. /// - /// This can be removed when `feature(dyn_upcasting)` is stabilized, since we only - /// use it to detect when upcasting traits in hir typeck. The index is only used - /// for winnowing. + /// The index is only used for winnowing. TraitUpcasting(usize), /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`. /// |
