about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-07-24 17:17:39 +0000
committerbors <bors@rust-lang.org>2021-07-24 17:17:39 +0000
commitbddb59cf07efcf6e606f16b87f85e3ecd2c1ca69 (patch)
treecc383acd5cf79e1b84b757bad894ebeb979246a1
parent18840b0719aa766a1bc49ea2eb5dc2e4cde7da3f (diff)
parentacfa3ac4052dfe127eee3fe8d352a48918bc2d9d (diff)
downloadrust-bddb59cf07efcf6e606f16b87f85e3ecd2c1ca69.tar.gz
rust-bddb59cf07efcf6e606f16b87f85e3ecd2c1ca69.zip
Auto merge of #87434 - Manishearth:rollup-b09njin, r=Manishearth
Rollup of 9 pull requests

Successful merges:

 - #87348 (Fix span when suggesting to add an associated type bound)
 - #87359 (Remove detection of rustup and cargo in 'missing extern crate' diagnostics)
 - #87370 (Add support for powerpc-unknown-freebsd)
 - #87389 (Rename `known_attrs` to `expanded_inert_attrs` and move to rustc_expand)
 - #87395 (Clear up std::env::set_var panic section.)
 - #87403 (Implement `AssignToDroppingUnionField` in THIR unsafeck)
 - #87410 (Mark `format_args_nl` as `#[doc(hidden)]`)
 - #87419 (IEEE 754 is not an RFC)
 - #87422 (DOC: remove unnecessary feature crate attribute from example code)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--RELEASES.md2
-rw-r--r--compiler/rustc_expand/src/base.rs6
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_metadata/src/locator.rs7
-rw-r--r--compiler/rustc_middle/src/ty/error.rs65
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs48
-rw-r--r--compiler/rustc_session/src/session.rs10
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs27
-rw-r--r--library/core/src/macros/mod.rs1
-rw-r--r--library/core/src/mem/maybe_uninit.rs1
-rw-r--r--library/std/src/env.rs7
-rw-r--r--src/bootstrap/native.rs9
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/test/ui/associated-types/issue-87261.rs99
-rw-r--r--src/test/ui/associated-types/issue-87261.stderr238
-rw-r--r--src/test/ui/crate-loading/missing-std.rs1
-rw-r--r--src/test/ui/crate-loading/missing-std.stderr2
-rw-r--r--src/test/ui/issues/issue-37131.stderr2
-rw-r--r--src/test/ui/issues/issue-49851/compiler-builtins-error.stderr2
-rw-r--r--src/test/ui/union/union-unsafe.rs4
-rw-r--r--src/test/ui/union/union-unsafe.thir.stderr18
22 files changed, 493 insertions, 62 deletions
diff --git a/RELEASES.md b/RELEASES.md
index 35e5627e61f..6eb70dee395 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -44,7 +44,7 @@ Libraries
 - [`leading_zeros`, and `trailing_zeros` are now available on all
   `NonZero` integer types.][84082]
 - [`{f32, f64}::from_str` now parse and print special values
-  (`NaN`, `-0`) according to IEEE RFC 754.][78618]
+  (`NaN`, `-0`) according to IEEE 754.][78618]
 - [You can now index into slices using `(Bound<usize>, Bound<usize>)`.][77704]
 - [Add the `BITS` associated constant to all numeric types.][82565]
 
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 8c6aef80635..3d5bc770c4f 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1,6 +1,7 @@
 use crate::expand::{self, AstFragment, Invocation};
 use crate::module::DirOwnership;
 
+use rustc_ast::attr::MarkedAttrs;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Nonterminal};
 use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
@@ -951,6 +952,10 @@ pub struct ExtCtxt<'a> {
     ///
     /// `Ident` is the module name.
     pub(super) extern_mod_loaded: OnExternModLoaded<'a>,
+    /// When we 'expand' an inert attribute, we leave it
+    /// in the AST, but insert it here so that we know
+    /// not to expand it again.
+    pub(super) expanded_inert_attrs: MarkedAttrs,
 }
 
 impl<'a> ExtCtxt<'a> {
@@ -977,6 +982,7 @@ impl<'a> ExtCtxt<'a> {
             },
             force_mode: false,
             expansions: FxHashMap::default(),
+            expanded_inert_attrs: MarkedAttrs::new(),
         }
     }
 
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 03d2105e5cc..c72b1b33dbc 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -754,7 +754,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     }
                 }
                 SyntaxExtensionKind::NonMacroAttr { mark_used } => {
-                    self.cx.sess.mark_attr_known(&attr);
+                    self.cx.expanded_inert_attrs.mark(&attr);
                     if *mark_used {
                         self.cx.sess.mark_attr_used(&attr);
                     }
@@ -1040,7 +1040,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         item.visit_attrs(|attrs| {
             attr = attrs
                 .iter()
-                .position(|a| !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a))
+                .position(|a| !self.cx.expanded_inert_attrs.is_marked(a) && !is_builtin_attr(a))
                 .map(|attr_pos| {
                     let attr = attrs.remove(attr_pos);
                     let following_derives = attrs[attr_pos..]
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 028104fd6b5..4936b22c7b9 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -1080,7 +1080,10 @@ impl CrateError {
                                 locator.triple
                             ));
                         }
-                        if missing_core && std::env::var("RUSTUP_HOME").is_ok() {
+                        // NOTE: this suggests using rustup, even though the user may not have it installed.
+                        // That's because they could choose to install it; or this may give them a hint which
+                        // target they need to install from their distro.
+                        if missing_core {
                             err.help(&format!(
                                 "consider downloading the target with `rustup target add {}`",
                                 locator.triple
@@ -1097,7 +1100,7 @@ impl CrateError {
                                 current_crate
                             ));
                         }
-                        if sess.is_nightly_build() && std::env::var("CARGO").is_ok() {
+                        if sess.is_nightly_build() {
                             err.help("consider building the standard library from source with `cargo build -Zbuild-std`");
                         }
                     } else if Some(crate_name)
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 96aae3bd70c..f1c7c1ea852 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -628,6 +628,7 @@ impl<T> Trait<T> for X {
                             assoc_substs,
                             ty,
                             msg,
+                            false,
                         ) {
                             return true;
                         }
@@ -646,6 +647,7 @@ impl<T> Trait<T> for X {
                             assoc_substs,
                             ty,
                             msg,
+                            false,
                         );
                     }
                 }
@@ -771,13 +773,24 @@ fn foo(&self) -> Self::T { String::new() }
     ) -> bool {
         let assoc = self.associated_item(proj_ty.item_def_id);
         if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
-            self.constrain_associated_type_structured_suggestion(
+            let opaque_local_def_id = def_id.expect_local();
+            let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id);
+            let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind {
+                hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
+                _ => bug!("The HirId comes from a `ty::Opaque`"),
+            };
+
+            let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
+
+            self.constrain_generic_bound_associated_type_structured_suggestion(
                 db,
-                self.def_span(def_id),
-                &assoc,
-                proj_ty.trait_ref_and_own_substs(self).1,
+                &trait_ref,
+                opaque_hir_ty.bounds,
+                assoc,
+                assoc_substs,
                 ty,
-                &msg,
+                msg,
+                true,
             )
         } else {
             false
@@ -899,6 +912,11 @@ fn foo(&self) -> Self::T { String::new() }
 
     /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
     /// requirement, provide a structured suggestion to constrain it to a given type `ty`.
+    ///
+    /// `is_bound_surely_present` indicates whether we know the bound we're looking for is
+    /// inside `bounds`. If that's the case then we can consider `bounds` containing only one
+    /// trait bound as the one we're looking for. This can help in cases where the associated
+    /// type is defined on a supertrait of the one present in the bounds.
     fn constrain_generic_bound_associated_type_structured_suggestion(
         self,
         db: &mut DiagnosticBuilder<'_>,
@@ -908,23 +926,30 @@ fn foo(&self) -> Self::T { String::new() }
         assoc_substs: &[ty::GenericArg<'tcx>],
         ty: Ty<'tcx>,
         msg: &str,
+        is_bound_surely_present: bool,
     ) -> bool {
         // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
-        bounds.iter().any(|bound| match bound {
-            hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => {
-                // Relate the type param against `T` in `<A as T>::Foo`.
-                ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
-                    && self.constrain_associated_type_structured_suggestion(
-                        db,
-                        ptr.span,
-                        assoc,
-                        assoc_substs,
-                        ty,
-                        msg,
-                    )
-            }
-            _ => false,
-        })
+
+        let trait_bounds = bounds.iter().filter_map(|bound| match bound {
+            hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
+            _ => None,
+        });
+
+        let matching_trait_bounds = trait_bounds
+            .clone()
+            .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
+            .collect::<Vec<_>>();
+
+        let span = match &matching_trait_bounds[..] {
+            &[ptr] => ptr.span,
+            &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
+                &[ptr] => ptr.span,
+                _ => return false,
+            },
+            _ => return false,
+        };
+
+        self.constrain_associated_type_structured_suggestion(db, span, assoc, assoc_substs, ty, msg)
     }
 
     /// Given a span corresponding to a bound, provide a structured suggestion to set an
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 82e19c05527..21534290d12 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -5,7 +5,7 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::thir::*;
-use rustc_middle::ty::{self, ParamEnv, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
 use rustc_session::lint::Level;
 use rustc_span::def_id::{DefId, LocalDefId};
@@ -27,7 +27,9 @@ struct UnsafetyVisitor<'a, 'tcx> {
     /// The `#[target_feature]` attributes of the body. Used for checking
     /// calls to functions with `#[target_feature]` (RFC 2396).
     body_target_features: &'tcx Vec<Symbol>,
-    in_possible_lhs_union_assign: bool,
+    /// When inside the LHS of an assignment to a field, this is the type
+    /// of the LHS and the span of the assignment expression.
+    assignment_info: Option<(Ty<'tcx>, Span)>,
     in_union_destructure: bool,
     param_env: ParamEnv<'tcx>,
     inside_adt: bool,
@@ -287,7 +289,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
     }
 
     fn visit_expr(&mut self, expr: &Expr<'tcx>) {
-        // could we be in a the LHS of an assignment of a union?
+        // could we be in the LHS of an assignment to a field?
         match expr.kind {
             ExprKind::Field { .. }
             | ExprKind::VarRef { .. }
@@ -329,7 +331,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             | ExprKind::InlineAsm { .. }
             | ExprKind::LlvmInlineAsm { .. }
             | ExprKind::LogicalOp { .. }
-            | ExprKind::Use { .. } => self.in_possible_lhs_union_assign = false,
+            | ExprKind::Use { .. } => {
+                // We don't need to save the old value and restore it
+                // because all the place expressions can't have more
+                // than one child.
+                self.assignment_info = None;
+            }
         };
         match expr.kind {
             ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => {
@@ -409,11 +416,21 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 self.safety_context = closure_visitor.safety_context;
             }
             ExprKind::Field { lhs, .. } => {
-                // assigning to union field is okay for AccessToUnionField
-                if let ty::Adt(adt_def, _) = &self.thir[lhs].ty.kind() {
+                let lhs = &self.thir[lhs];
+                if let ty::Adt(adt_def, _) = lhs.ty.kind() {
                     if adt_def.is_union() {
-                        if self.in_possible_lhs_union_assign {
-                            // FIXME: trigger AssignToDroppingUnionField unsafety if needed
+                        if let Some((assigned_ty, assignment_span)) = self.assignment_info {
+                            // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping.
+                            if !(assigned_ty
+                                .ty_adt_def()
+                                .map_or(false, |adt| adt.is_manually_drop())
+                                || assigned_ty
+                                    .is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env))
+                            {
+                                self.requires_unsafe(assignment_span, AssignToDroppingUnionField);
+                            } else {
+                                // write to non-drop union field, safe
+                            }
                         } else {
                             self.requires_unsafe(expr.span, AccessToUnionField);
                         }
@@ -421,9 +438,10 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 }
             }
             ExprKind::Assign { lhs, rhs } | ExprKind::AssignOp { lhs, rhs, .. } => {
+                let lhs = &self.thir[lhs];
                 // First, check whether we are mutating a layout constrained field
                 let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
-                visit::walk_expr(&mut visitor, &self.thir[lhs]);
+                visit::walk_expr(&mut visitor, lhs);
                 if visitor.found {
                     self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField);
                 }
@@ -431,10 +449,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 // Second, check for accesses to union fields
                 // don't have any special handling for AssignOp since it causes a read *and* write to lhs
                 if matches!(expr.kind, ExprKind::Assign { .. }) {
-                    // assigning to a union is safe, check here so it doesn't get treated as a read later
-                    self.in_possible_lhs_union_assign = true;
-                    visit::walk_expr(self, &self.thir()[lhs]);
-                    self.in_possible_lhs_union_assign = false;
+                    self.assignment_info = Some((lhs.ty, expr.span));
+                    visit::walk_expr(self, lhs);
+                    self.assignment_info = None;
                     visit::walk_expr(self, &self.thir()[rhs]);
                     return; // we have already visited everything by now
                 }
@@ -506,12 +523,9 @@ enum UnsafeOpKind {
     UseOfMutableStatic,
     UseOfExternStatic,
     DerefOfRawPointer,
-    #[allow(dead_code)] // FIXME
     AssignToDroppingUnionField,
     AccessToUnionField,
-    #[allow(dead_code)] // FIXME
     MutationOfLayoutConstrainedField,
-    #[allow(dead_code)] // FIXME
     BorrowOfLayoutConstrainedField,
     CallToFunctionWith,
 }
@@ -619,7 +633,7 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
         hir_context: hir_id,
         body_unsafety,
         body_target_features,
-        in_possible_lhs_union_assign: false,
+        assignment_info: None,
         in_union_destructure: false,
         param_env: tcx.param_env(def.did),
         inside_adt: false,
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 86d495c3353..369af437c43 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -219,7 +219,6 @@ pub struct Session {
     /// Set of enabled features for the current target.
     pub target_features: FxHashSet<Symbol>,
 
-    known_attrs: Lock<MarkedAttrs>,
     used_attrs: Lock<MarkedAttrs>,
 
     /// `Span`s for `if` conditions that we have suggested turning into `if let`.
@@ -1076,14 +1075,6 @@ impl Session {
             == config::InstrumentCoverage::ExceptUnusedFunctions
     }
 
-    pub fn mark_attr_known(&self, attr: &Attribute) {
-        self.known_attrs.lock().mark(attr)
-    }
-
-    pub fn is_attr_known(&self, attr: &Attribute) -> bool {
-        self.known_attrs.lock().is_marked(attr)
-    }
-
     pub fn mark_attr_used(&self, attr: &Attribute) {
         self.used_attrs.lock().mark(attr)
     }
@@ -1389,7 +1380,6 @@ pub fn build_session(
         miri_unleashed_features: Lock::new(Default::default()),
         asm_arch,
         target_features: FxHashSet::default(),
-        known_attrs: Lock::new(MarkedAttrs::new()),
         used_attrs: Lock::new(MarkedAttrs::new()),
         if_let_suggestions: Default::default(),
     };
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 0185132ee36..ad84e07edfb 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -802,6 +802,7 @@ supported_targets! {
     ("armv6-unknown-freebsd", armv6_unknown_freebsd),
     ("armv7-unknown-freebsd", armv7_unknown_freebsd),
     ("i686-unknown-freebsd", i686_unknown_freebsd),
+    ("powerpc-unknown-freebsd", powerpc_unknown_freebsd),
     ("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd),
     ("powerpc64le-unknown-freebsd", powerpc64le_unknown_freebsd),
     ("x86_64-unknown-freebsd", x86_64_unknown_freebsd),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
new file mode 100644
index 00000000000..e11318027d5
--- /dev/null
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
@@ -0,0 +1,27 @@
+use crate::abi::Endian;
+use crate::spec::{LinkerFlavor, RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    let mut base = super::freebsd_base::opts();
+    base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
+    // Extra hint to linker that we are generating secure-PLT code.
+    base.pre_link_args
+        .entry(LinkerFlavor::Gcc)
+        .or_default()
+        .push("--target=powerpc-unknown-freebsd13.0".to_string());
+    base.max_atomic_width = Some(32);
+
+    Target {
+        llvm_target: "powerpc-unknown-freebsd13.0".to_string(),
+        pointer_width: 32,
+        data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
+        arch: "powerpc".to_string(),
+        options: TargetOptions {
+            endian: Endian::Big,
+            features: "+secure-plt".to_string(),
+            relocation_model: RelocModel::Pic,
+            mcount: "_mcount".to_string(),
+            ..base
+        },
+    }
+}
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 3ca8f27c79a..07ee589e29f 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -845,6 +845,7 @@ pub(crate) mod builtin {
                   language use and is subject to change"
     )]
     #[allow_internal_unstable(fmt_internals)]
+    #[doc(hidden)]
     #[rustc_builtin_macro]
     #[macro_export]
     macro_rules! format_args_nl {
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 5122421ea8c..d3ebc1cebb6 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -461,7 +461,6 @@ impl<T> MaybeUninit<T> {
     /// With `write`, we can avoid the need to write through a raw pointer:
     ///
     /// ```rust
-    /// #![feature(maybe_uninit_extra)]
     /// use core::pin::Pin;
     /// use core::mem::MaybeUninit;
     ///
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 64f88c1aba6..5709d97d643 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -294,7 +294,7 @@ impl Error for VarError {
     }
 }
 
-/// Sets the environment variable `k` to the value `v` for the currently running
+/// Sets the environment variable `key` to the value `value` for the currently running
 /// process.
 ///
 /// Note that while concurrent access to environment variables is safe in Rust,
@@ -310,9 +310,8 @@ impl Error for VarError {
 ///
 /// # Panics
 ///
-/// This function may panic if `key` is empty, contains an ASCII equals sign
-/// `'='` or the NUL character `'\0'`, or when the value contains the NUL
-/// character.
+/// This function may panic if `key` is empty, contains an ASCII equals sign `'='`
+/// or the NUL character `'\0'`, or when `value` contains the NUL character.
 ///
 /// # Examples
 ///
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 1be414b29a1..b8a1513f2a6 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -118,6 +118,10 @@ impl Step for Llvm {
             let idx = target.triple.find('-').unwrap();
 
             format!("riscv{}{}", &target.triple[5..7], &target.triple[idx..])
+        } else if self.target.starts_with("powerpc") && self.target.ends_with("freebsd") {
+            // FreeBSD 13 had incompatible ABI changes on all PowerPC platforms.
+            // Set the version suffix to 13.0 so the correct target details are used.
+            format!("{}{}", self.target, "13.0")
         } else {
             target.to_string()
         };
@@ -277,6 +281,11 @@ impl Step for Llvm {
             }
         }
 
+        // Workaround for ppc32 lld limitation
+        if target == "powerpc-unknown-freebsd" {
+            cfg.define("CMAKE_EXE_LINKER_FLAGS", "-fuse-ld=bfd");
+        }
+
         // https://llvm.org/docs/HowToCrossCompileLLVM.html
         if target != builder.config.build {
             builder.ensure(Llvm { target: builder.config.build });
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 885010b039e..90ef48798dd 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -249,6 +249,7 @@ target | std | host | notes
 `powerpc-wrs-vxworks` | ? |  |
 `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
 `powerpc64le-unknown-freebsd` |   |   | PPC64LE FreeBSD
+`powerpc-unknown-freebsd` |   |   | PowerPC FreeBSD
 `powerpc64-unknown-linux-musl` | ? |  |
 `powerpc64-wrs-vxworks` | ? |  |
 `powerpc64le-unknown-linux-musl` | ? |  |
diff --git a/src/test/ui/associated-types/issue-87261.rs b/src/test/ui/associated-types/issue-87261.rs
new file mode 100644
index 00000000000..a70f771e482
--- /dev/null
+++ b/src/test/ui/associated-types/issue-87261.rs
@@ -0,0 +1,99 @@
+trait Foo {}
+
+trait Trait {
+    type Associated;
+}
+trait DerivedTrait: Trait {}
+trait GenericTrait<A> {
+    type Associated;
+}
+
+struct Impl;
+impl Foo for Impl {}
+impl Trait for Impl {
+    type Associated = ();
+}
+impl DerivedTrait for Impl {}
+impl<A> GenericTrait<A> for Impl {
+    type Associated = ();
+}
+
+fn returns_opaque() -> impl Trait + 'static {
+    Impl
+}
+fn returns_opaque_derived() -> impl DerivedTrait + 'static {
+    Impl
+}
+fn returns_opaque_foo() -> impl Trait + Foo {
+    Impl
+}
+fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
+    Impl
+}
+fn returns_opaque_generic() -> impl GenericTrait<()> + 'static {
+    Impl
+}
+fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
+    Impl
+}
+fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
+    Impl
+}
+
+fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+
+fn check_generics<A, B, C, D, E, F, G>(a: A, b: B, c: C, d: D, e: E, f: F, g: G)
+where
+    A: Trait + 'static,
+    B: DerivedTrait + 'static,
+    C: Trait + Foo,
+    D: DerivedTrait + Foo,
+    E: GenericTrait<()> + 'static,
+    F: GenericTrait<()> + Foo,
+    G: GenericTrait<()> + GenericTrait<u8>,
+{
+    accepts_trait(a);
+    //~^ ERROR type mismatch resolving `<A as Trait>::Associated == ()`
+
+    accepts_trait(b);
+    //~^ ERROR type mismatch resolving `<B as Trait>::Associated == ()`
+
+    accepts_trait(c);
+    //~^ ERROR type mismatch resolving `<C as Trait>::Associated == ()`
+
+    accepts_trait(d);
+    //~^ ERROR type mismatch resolving `<D as Trait>::Associated == ()`
+
+    accepts_generic_trait(e);
+    //~^ ERROR type mismatch resolving `<E as GenericTrait<()>>::Associated == ()`
+
+    accepts_generic_trait(f);
+    //~^ ERROR type mismatch resolving `<F as GenericTrait<()>>::Associated == ()`
+
+    accepts_generic_trait(g);
+    //~^ ERROR type mismatch resolving `<G as GenericTrait<()>>::Associated == ()`
+}
+
+fn main() {
+    accepts_trait(returns_opaque());
+    //~^ ERROR type mismatch resolving `<impl Trait as Trait>::Associated == ()`
+
+    accepts_trait(returns_opaque_derived());
+    //~^ ERROR type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
+
+    accepts_trait(returns_opaque_foo());
+    //~^ ERROR type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
+
+    accepts_trait(returns_opaque_derived_foo());
+    //~^ ERROR type mismatch resolving `<impl DerivedTrait+Foo as Trait>::Associated == ()`
+
+    accepts_generic_trait(returns_opaque_generic());
+    //~^ ERROR type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+
+    accepts_generic_trait(returns_opaque_generic_foo());
+    //~^ ERROR type mismatch resolving `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated == ()`
+
+    accepts_generic_trait(returns_opaque_generic_duplicate());
+    //~^ ERROR type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+}
diff --git a/src/test/ui/associated-types/issue-87261.stderr b/src/test/ui/associated-types/issue-87261.stderr
new file mode 100644
index 00000000000..0725acfe537
--- /dev/null
+++ b/src/test/ui/associated-types/issue-87261.stderr
@@ -0,0 +1,238 @@
+error[E0271]: type mismatch resolving `<A as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:56:5
+   |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(a);
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<A as Trait>::Associated`
+help: consider constraining the associated type `<A as Trait>::Associated` to `()`
+   |
+LL |     A: Trait<Associated = ()> + 'static,
+   |             ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<B as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:59:5
+   |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(b);
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<B as Trait>::Associated`
+   = help: consider constraining the associated type `<B as Trait>::Associated` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<C as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:62:5
+   |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(c);
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<C as Trait>::Associated`
+help: consider constraining the associated type `<C as Trait>::Associated` to `()`
+   |
+LL |     C: Trait<Associated = ()> + Foo,
+   |             ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<D as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:65:5
+   |
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(d);
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<D as Trait>::Associated`
+   = help: consider constraining the associated type `<D as Trait>::Associated` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<E as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:68:5
+   |
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(e);
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<E as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<E as GenericTrait<()>>::Associated` to `()`
+   |
+LL |     E: GenericTrait<(), Associated = ()> + 'static,
+   |                       ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<F as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:71:5
+   |
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(f);
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<F as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<F as GenericTrait<()>>::Associated` to `()`
+   |
+LL |     F: GenericTrait<(), Associated = ()> + Foo,
+   |                       ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<G as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:74:5
+   |
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(g);
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<G as GenericTrait<()>>::Associated`
+   = help: consider constraining the associated type `<G as GenericTrait<()>>::Associated` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<impl Trait as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:79:5
+   |
+LL | fn returns_opaque() -> impl Trait + 'static {
+   |                        -------------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(returns_opaque());
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl Trait as Trait>::Associated`
+help: consider constraining the associated type `<impl Trait as Trait>::Associated` to `()`
+   |
+LL | fn returns_opaque() -> impl Trait<Associated = ()> + 'static {
+   |                                  ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:82:5
+   |
+LL | fn returns_opaque_derived() -> impl DerivedTrait + 'static {
+   |                                --------------------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(returns_opaque_derived());
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl DerivedTrait as Trait>::Associated`
+help: consider constraining the associated type `<impl DerivedTrait as Trait>::Associated` to `()`
+   |
+LL | fn returns_opaque_derived() -> impl DerivedTrait<Associated = ()> + 'static {
+   |                                                 ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl Trait+Foo as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:85:5
+   |
+LL | fn returns_opaque_foo() -> impl Trait + Foo {
+   |                            ---------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(returns_opaque_foo());
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl Trait+Foo as Trait>::Associated`
+help: consider constraining the associated type `<impl Trait+Foo as Trait>::Associated` to `()`
+   |
+LL | fn returns_opaque_foo() -> impl Trait<Associated = ()> + Foo {
+   |                                      ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl DerivedTrait+Foo as Trait>::Associated == ()`
+  --> $DIR/issue-87261.rs:88:5
+   |
+LL | fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
+   |                                    ----------------------- the found opaque type
+...
+LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
+   |                           --------------- required by this bound in `accepts_trait`
+...
+LL |     accepts_trait(returns_opaque_derived_foo());
+   |     ^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl DerivedTrait+Foo as Trait>::Associated`
+   = help: consider constraining the associated type `<impl DerivedTrait+Foo as Trait>::Associated` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0271]: type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:91:5
+   |
+LL | fn returns_opaque_generic() -> impl GenericTrait<()> + 'static {
+   |                                ------------------------------- the found opaque type
+...
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(returns_opaque_generic());
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl GenericTrait<()> as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<impl GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
+   |
+LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static {
+   |                                                    ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:94:5
+   |
+LL | fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
+   |                                    --------------------------- the found opaque type
+...
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(returns_opaque_generic_foo());
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated`
+help: consider constraining the associated type `<impl GenericTrait<()>+Foo as GenericTrait<()>>::Associated` to `()`
+   |
+LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo {
+   |                                                        ^^^^^^^^^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+  --> $DIR/issue-87261.rs:97:5
+   |
+LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
+   |                                          ---------------------------------------- the found opaque type
+...
+LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
+   |                                              --------------- required by this bound in `accepts_generic_trait`
+...
+LL |     accepts_generic_trait(returns_opaque_generic_duplicate());
+   |     ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+   |
+   = note:    expected unit type `()`
+           found associated type `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated`
+   = help: consider constraining the associated type `<impl GenericTrait<()>+GenericTrait<u8> as GenericTrait<()>>::Associated` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/crate-loading/missing-std.rs b/src/test/ui/crate-loading/missing-std.rs
index de4ccc18560..1a34c21ba54 100644
--- a/src/test/ui/crate-loading/missing-std.rs
+++ b/src/test/ui/crate-loading/missing-std.rs
@@ -1,7 +1,6 @@
 // compile-flags: --target x86_64-unknown-uefi
 // needs-llvm-components: x86
 // rustc-env:CARGO=/usr/bin/cargo
-// rustc-env:RUSTUP_HOME=/home/bors/.rustup
 #![no_core]
 extern crate core;
 //~^ ERROR can't find crate for `core`
diff --git a/src/test/ui/crate-loading/missing-std.stderr b/src/test/ui/crate-loading/missing-std.stderr
index e61486fdc6f..25808efdfa6 100644
--- a/src/test/ui/crate-loading/missing-std.stderr
+++ b/src/test/ui/crate-loading/missing-std.stderr
@@ -1,5 +1,5 @@
 error[E0463]: can't find crate for `core`
-  --> $DIR/missing-std.rs:6:1
+  --> $DIR/missing-std.rs:5:1
    |
 LL | extern crate core;
    | ^^^^^^^^^^^^^^^^^^ can't find crate
diff --git a/src/test/ui/issues/issue-37131.stderr b/src/test/ui/issues/issue-37131.stderr
index 660a6935f36..b45574f0c49 100644
--- a/src/test/ui/issues/issue-37131.stderr
+++ b/src/test/ui/issues/issue-37131.stderr
@@ -1,6 +1,8 @@
 error[E0463]: can't find crate for `std`
    |
    = note: the `thumbv6m-none-eabi` target may not be installed
+   = help: consider downloading the target with `rustup target add thumbv6m-none-eabi`
+   = help: consider building the standard library from source with `cargo build -Zbuild-std`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr b/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr
index 7e23e0fd747..d963c07ea91 100644
--- a/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr
+++ b/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr
@@ -1,6 +1,8 @@
 error[E0463]: can't find crate for `core`
    |
    = note: the `thumbv7em-none-eabihf` target may not be installed
+   = help: consider downloading the target with `rustup target add thumbv7em-none-eabihf`
+   = help: consider building the standard library from source with `cargo build -Zbuild-std`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs
index e8414903d54..3cb3a18cb75 100644
--- a/src/test/ui/union/union-unsafe.rs
+++ b/src/test/ui/union/union-unsafe.rs
@@ -36,8 +36,8 @@ fn deref_union_field(mut u: URef) {
 
 fn assign_noncopy_union_field(mut u: URefCell) {
     // FIXME(thir-unsafeck)
-    u.a = (RefCell::new(0), 1); //[mir]~ ERROR assignment to union field that might need dropping
-    u.a.0 = RefCell::new(0); //[mir]~ ERROR assignment to union field that might need dropping
+    u.a = (RefCell::new(0), 1); //~ ERROR assignment to union field that might need dropping
+    u.a.0 = RefCell::new(0); //~ ERROR assignment to union field that might need dropping
     u.a.1 = 1; // OK
 }
 
diff --git a/src/test/ui/union/union-unsafe.thir.stderr b/src/test/ui/union/union-unsafe.thir.stderr
index 51f19879c81..e88642b0ff7 100644
--- a/src/test/ui/union/union-unsafe.thir.stderr
+++ b/src/test/ui/union/union-unsafe.thir.stderr
@@ -6,6 +6,22 @@ LL |     *(u.p) = 13;
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
+error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
+  --> $DIR/union-unsafe.rs:39:5
+   |
+LL |     u.a = (RefCell::new(0), 1);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
+   |
+   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+
+error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
+  --> $DIR/union-unsafe.rs:40:5
+   |
+LL |     u.a.0 = RefCell::new(0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
+   |
+   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+
 error[E0133]: access to union field is unsafe and requires unsafe function or block
   --> $DIR/union-unsafe.rs:47:6
    |
@@ -70,6 +86,6 @@ LL |     *u3.a = String::from("new");
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
-error: aborting due to 9 previous errors
+error: aborting due to 11 previous errors
 
 For more information about this error, try `rustc --explain E0133`.