about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-01-22 18:22:32 +0000
committerbors <bors@rust-lang.org>2024-01-22 18:22:32 +0000
commitd5fd0997291ca0135401a39dff25c8a9c13b8961 (patch)
tree3fd6447ffcb2d9dc5d5aad5fc7c921ae173a5476 /compiler
parent021861aea8de20c76c7411eb8ada7e8235e3d9b5 (diff)
parent0b0f0be4198de16f3a23f05e824b3a054dda1355 (diff)
Auto merge of #120242 - matthiaskrgr:rollup-a93yj3i, r=matthiaskrgr
Rollup of 10 pull requests

Successful merges:

 - #117910 (Refactor uses of `objc_msgSend` to no longer have clashing definitions)
 - #118639 (Undeprecate lint `unstable_features` and make use of it in the compiler)
 - #119801 (Fix deallocation with wrong allocator in (A)Rc::from_box_in)
 - #120058 (bootstrap: improvements for compiler builds)
 - #120059 (Make generic const type mismatches not hide trait impls from the trait solver)
 - #120097 (Report unreachable subpatterns consistently)
 - #120137 (Validate AggregateKind types in MIR)
 - #120164 (`maybe_lint_impl_trait`: separate `is_downgradable` from `is_object_safe`)
 - #120181 (Allow any `const` expression blocks in `thread_local!`)
 - #120218 (rustfmt: Check that a token can begin a nonterminal kind before parsing it as a macro arg)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs62
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/lint.rs16
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs34
-rw-r--r--compiler/rustc_lexer/src/lib.rs5
-rw-r--r--compiler/rustc_lint/messages.ftl2
-rw-r--r--compiler/rustc_lint/src/builtin.rs34
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs88
-rw-r--r--compiler/rustc_parse_format/src/lib.rs5
8 files changed, 163 insertions, 83 deletions
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 9c2f336e912..5564902396e 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -796,7 +796,67 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             };
         }
         match rvalue {
-            Rvalue::Use(_) | Rvalue::CopyForDeref(_) | Rvalue::Aggregate(..) => {}
+            Rvalue::Use(_) | Rvalue::CopyForDeref(_) => {}
+            Rvalue::Aggregate(kind, fields) => match **kind {
+                AggregateKind::Tuple => {}
+                AggregateKind::Array(dest) => {
+                    for src in fields {
+                        if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) {
+                            self.fail(location, "array field has the wrong type");
+                        }
+                    }
+                }
+                AggregateKind::Adt(def_id, idx, args, _, Some(field)) => {
+                    let adt_def = self.tcx.adt_def(def_id);
+                    assert!(adt_def.is_union());
+                    assert_eq!(idx, FIRST_VARIANT);
+                    let dest = adt_def.non_enum_variant().fields[field].ty(self.tcx, args);
+                    if fields.len() != 1 {
+                        self.fail(location, "unions should have one initialized field");
+                    }
+                    if !self.mir_assign_valid_types(fields.raw[0].ty(self.body, self.tcx), dest) {
+                        self.fail(location, "union field has the wrong type");
+                    }
+                }
+                AggregateKind::Adt(def_id, idx, args, _, None) => {
+                    let adt_def = self.tcx.adt_def(def_id);
+                    assert!(!adt_def.is_union());
+                    let variant = &adt_def.variants()[idx];
+                    if variant.fields.len() != fields.len() {
+                        self.fail(location, "adt has the wrong number of initialized fields");
+                    }
+                    for (src, dest) in std::iter::zip(fields, &variant.fields) {
+                        if !self.mir_assign_valid_types(
+                            src.ty(self.body, self.tcx),
+                            dest.ty(self.tcx, args),
+                        ) {
+                            self.fail(location, "adt field has the wrong type");
+                        }
+                    }
+                }
+                AggregateKind::Closure(_, args) => {
+                    let upvars = args.as_closure().upvar_tys();
+                    if upvars.len() != fields.len() {
+                        self.fail(location, "closure has the wrong number of initialized fields");
+                    }
+                    for (src, dest) in std::iter::zip(fields, upvars) {
+                        if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) {
+                            self.fail(location, "closure field has the wrong type");
+                        }
+                    }
+                }
+                AggregateKind::Coroutine(_, args) => {
+                    let upvars = args.as_coroutine().upvar_tys();
+                    if upvars.len() != fields.len() {
+                        self.fail(location, "coroutine has the wrong number of initialized fields");
+                    }
+                    for (src, dest) in std::iter::zip(fields, upvars) {
+                        if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) {
+                            self.fail(location, "coroutine field has the wrong type");
+                        }
+                    }
+                }
+            },
             Rvalue::Ref(_, BorrowKind::Fake, _) => {
                 if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
                     self.fail(
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index b5f42e98127..27dc088d5dd 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -94,15 +94,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             return false;
         };
         let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
+        let mut is_downgradable = true;
         let is_object_safe = match self_ty.kind {
             hir::TyKind::TraitObject(objects, ..) => {
                 objects.iter().all(|o| match o.trait_ref.path.res {
-                    Res::Def(DefKind::Trait, id) if Some(id) == owner => {
-                        // When we're dealing with a recursive trait, we don't want to downgrade
-                        // the error, so we consider them to be object safe always. (#119652)
-                        true
+                    Res::Def(DefKind::Trait, id) => {
+                        if Some(id) == owner {
+                            // For recursive traits, don't downgrade the error. (#119652)
+                            is_downgradable = false;
+                        }
+                        tcx.check_is_object_safe(id)
                     }
-                    Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id),
                     _ => false,
                 })
             }
@@ -130,7 +132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ],
                     Applicability::MachineApplicable,
                 );
-            } else if diag.is_error() {
+            } else if diag.is_error() && is_downgradable {
                 // We'll emit the object safety error already, with a structured suggestion.
                 diag.downgrade_to_delayed_bug();
             }
@@ -156,7 +158,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             if !is_object_safe {
                 diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
-                if diag.is_error() {
+                if diag.is_error() && is_downgradable {
                     // We'll emit the object safety error already, with a structured suggestion.
                     diag.downgrade_to_delayed_bug();
                 }
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 9e1dab12b4d..1c120646f1f 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -165,9 +165,9 @@ impl<'tcx> InferCtxt<'tcx> {
         //
         // This probe is probably not strictly necessary but it seems better to be safe and not accidentally find
         // ourselves with a check to find bugs being required for code to compile because it made inference progress.
-        let compatible_types = self.probe(|_| {
+        self.probe(|_| {
             if a.ty() == b.ty() {
-                return Ok(());
+                return;
             }
 
             // We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the
@@ -177,32 +177,18 @@ impl<'tcx> InferCtxt<'tcx> {
                 relation.param_env().and((a.ty(), b.ty())),
                 &mut OriginalQueryValues::default(),
             );
-            self.tcx.check_tys_might_be_eq(canonical).map_err(|_| {
+            self.tcx.check_tys_might_be_eq(canonical).unwrap_or_else(|_| {
+                // The error will only be reported later. If we emit an ErrorGuaranteed
+                // here, then we will never get to the code that actually emits the error.
                 self.tcx.dcx().delayed_bug(format!(
                     "cannot relate consts of different types (a={a:?}, b={b:?})",
-                ))
-            })
+                ));
+                // We treat these constants as if they were of the same type, so that any
+                // such constants being used in impls make these impls match barring other mismatches.
+                // This helps with diagnostics down the road.
+            });
         });
 
-        // If the consts have differing types, just bail with a const error with
-        // the expected const's type. Specifically, we don't want const infer vars
-        // to do any type shapeshifting before and after resolution.
-        if let Err(guar) = compatible_types {
-            // HACK: equating both sides with `[const error]` eagerly prevents us
-            // from leaving unconstrained inference vars during things like impl
-            // matching in the solver.
-            let a_error = ty::Const::new_error(self.tcx, guar, a.ty());
-            if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() {
-                return self.unify_const_variable(vid, a_error, relation.param_env());
-            }
-            let b_error = ty::Const::new_error(self.tcx, guar, b.ty());
-            if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() {
-                return self.unify_const_variable(vid, b_error, relation.param_env());
-            }
-
-            return Ok(if relation.a_is_expected() { a_error } else { b_error });
-        }
-
         match (a.kind(), b.kind()) {
             (
                 ty::ConstKind::Infer(InferConst::Var(a_vid)),
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 43dfd34a6ff..f6c9289b529 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -20,8 +20,9 @@
 //! [`rustc_parse::lexer`]: ../rustc_parse/lexer/index.html
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
-// We want to be able to build this crate with a stable compiler, so no
-// `#![feature]` attributes should be added.
+// We want to be able to build this crate with a stable compiler,
+// so no `#![feature]` attributes should be added.
+#![deny(unstable_features)]
 
 mod cursor;
 pub mod unescape;
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 7d4afc5bad7..33f96139f20 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -148,7 +148,7 @@ lint_builtin_unsafe_impl = implementation of an `unsafe` trait
 
 lint_builtin_unsafe_trait = declaration of an `unsafe` trait
 
-lint_builtin_unstable_features = unstable feature
+lint_builtin_unstable_features = use of an unstable feature
 
 lint_builtin_unused_doc_comment = unused doc comment
     .label = rustdoc does not generate documentation for {$kind}
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 5e1f2ed11ac..2ce78152cc2 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1233,10 +1233,30 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
 }
 
 declare_lint! {
-    /// The `unstable_features` is deprecated and should no longer be used.
+    /// The `unstable_features` lint detects uses of `#![feature]`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unstable_features)]
+    /// #![feature(test)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In larger nightly-based projects which
+    ///
+    /// * consist of a multitude of crates where a subset of crates has to compile on
+    ///   stable either unconditionally or depending on a `cfg` flag to for example
+    ///   allow stable users to depend on them,
+    /// * don't use nightly for experimental features but for, e.g., unstable options only,
+    ///
+    /// this lint may come in handy to enforce policies of these kinds.
     UNSTABLE_FEATURES,
     Allow,
-    "enabling unstable features (deprecated. do not use)"
+    "enabling unstable features"
 }
 
 declare_lint_pass!(
@@ -1246,11 +1266,11 @@ declare_lint_pass!(
 
 impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
     fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
-        if attr.has_name(sym::feature) {
-            if let Some(items) = attr.meta_item_list() {
-                for item in items {
-                    cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
-                }
+        if attr.has_name(sym::feature)
+            && let Some(items) = attr.meta_item_list()
+        {
+            for item in items {
+                cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
             }
         }
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 693dc49c6e8..03de79e92be 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1,9 +1,8 @@
 use rustc_pattern_analysis::errors::Uncovered;
 use rustc_pattern_analysis::rustc::{
-    Constructor, DeconstructedPat, RustcMatchCheckCtxt as MatchCheckCtxt, Usefulness,
+    Constructor, DeconstructedPat, MatchArm, RustcMatchCheckCtxt as MatchCheckCtxt, Usefulness,
     UsefulnessReport, WitnessPat,
 };
-use rustc_pattern_analysis::{analyze_match, MatchArm};
 
 use crate::errors::*;
 
@@ -390,6 +389,34 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         }
     }
 
+    fn analyze_patterns(
+        &mut self,
+        cx: &MatchCheckCtxt<'p, 'tcx>,
+        arms: &[MatchArm<'p, 'tcx>],
+        scrut_ty: Ty<'tcx>,
+    ) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
+        let report =
+            rustc_pattern_analysis::analyze_match(&cx, &arms, scrut_ty).map_err(|err| {
+                self.error = Err(err);
+                err
+            })?;
+
+        // Warn unreachable subpatterns.
+        for (arm, is_useful) in report.arm_usefulness.iter() {
+            if let Usefulness::Useful(redundant_subpats) = is_useful
+                && !redundant_subpats.is_empty()
+            {
+                let mut redundant_subpats = redundant_subpats.clone();
+                // Emit lints in the order in which they occur in the file.
+                redundant_subpats.sort_unstable_by_key(|pat| pat.data().unwrap().span);
+                for pat in redundant_subpats {
+                    report_unreachable_pattern(cx, arm.arm_data, pat.data().unwrap().span, None)
+                }
+            }
+        }
+        Ok(report)
+    }
+
     #[instrument(level = "trace", skip(self))]
     fn check_let(&mut self, pat: &'p Pat<'tcx>, scrutinee: Option<ExprId>, span: Span) {
         assert!(self.let_source != LetSource::None);
@@ -435,14 +462,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             }
         }
 
-        let scrut_ty = scrut.ty;
-        let report = match analyze_match(&cx, &tarms, scrut_ty) {
-            Ok(report) => report,
-            Err(err) => {
-                self.error = Err(err);
-                return;
-            }
-        };
+        let Ok(report) = self.analyze_patterns(&cx, &tarms, scrut.ty) else { return };
 
         match source {
             // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
@@ -474,7 +494,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                 );
             } else {
                 self.error = Err(report_non_exhaustive_match(
-                    &cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span,
+                    &cx, self.thir, scrut.ty, scrut.span, witnesses, arms, expr_span,
                 ));
             }
         }
@@ -556,7 +576,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         let cx = self.new_cx(refutability, None, scrut, pat.span);
         let pat = self.lower_pattern(&cx, pat)?;
         let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
-        let report = analyze_match(&cx, &arms, pat.ty().inner())?;
+        let report = self.analyze_patterns(&cx, &arms, pat.ty().inner())?;
         Ok((cx, report))
     }
 
@@ -567,7 +587,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
     ) -> Result<RefutableFlag, ErrorGuaranteed> {
         let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?;
         // Report if the pattern is unreachable, which can only occur when the type is uninhabited.
-        // This also reports unreachable sub-patterns.
         report_arm_reachability(&cx, &report);
         // If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is
         // irrefutable.
@@ -851,38 +870,29 @@ fn report_irrefutable_let_patterns(
 }
 
 /// Report unreachable arms, if any.
+fn report_unreachable_pattern<'p, 'tcx>(
+    cx: &MatchCheckCtxt<'p, 'tcx>,
+    hir_id: HirId,
+    span: Span,
+    catchall: Option<Span>,
+) {
+    cx.tcx.emit_spanned_lint(
+        UNREACHABLE_PATTERNS,
+        hir_id,
+        span,
+        UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall },
+    );
+}
+
+/// Report unreachable arms, if any.
 fn report_arm_reachability<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     report: &UsefulnessReport<'p, 'tcx>,
 ) {
-    let report_unreachable_pattern = |span, hir_id, catchall: Option<Span>| {
-        cx.tcx.emit_spanned_lint(
-            UNREACHABLE_PATTERNS,
-            hir_id,
-            span,
-            UnreachablePattern {
-                span: if catchall.is_some() { Some(span) } else { None },
-                catchall,
-            },
-        );
-    };
-
     let mut catchall = None;
     for (arm, is_useful) in report.arm_usefulness.iter() {
-        match is_useful {
-            Usefulness::Redundant => {
-                report_unreachable_pattern(arm.pat.data().unwrap().span, arm.arm_data, catchall)
-            }
-            Usefulness::Useful(redundant_subpats) if redundant_subpats.is_empty() => {}
-            // The arm is reachable, but contains redundant subpatterns (from or-patterns).
-            Usefulness::Useful(redundant_subpats) => {
-                let mut redundant_subpats = redundant_subpats.clone();
-                // Emit lints in the order in which they occur in the file.
-                redundant_subpats.sort_unstable_by_key(|pat| pat.data().unwrap().span);
-                for pat in redundant_subpats {
-                    report_unreachable_pattern(pat.data().unwrap().span, arm.arm_data, None);
-                }
-            }
+        if matches!(is_useful, Usefulness::Redundant) {
+            report_unreachable_pattern(cx, arm.arm_data, arm.pat.data().unwrap().span, catchall)
         }
         if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
             catchall = Some(arm.pat.data().unwrap().span);
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 1e1d45d6f70..625764876a6 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -11,8 +11,9 @@
 )]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
-// WARNING: We want to be able to build this crate with a stable compiler,
-//          so no `#![feature]` attributes should be added!
+// We want to be able to build this crate with a stable compiler,
+// so no `#![feature]` attributes should be added.
+#![deny(unstable_features)]
 
 use rustc_lexer::unescape;
 pub use Alignment::*;