about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-09-22 11:15:49 +0000
committerbors <bors@rust-lang.org>2025-09-22 11:15:49 +0000
commit29005cb128e6d447e6bd9c110c9a684665f95985 (patch)
treea25020539ef1a6939c6298a4f77126720d2168d9
parent9f32ccf35fb877270bc44a86a126440f04d676d0 (diff)
parent8f80707bc5fa74992bdc2dc201a6461860769f28 (diff)
downloadrust-29005cb128e6d447e6bd9c110c9a684665f95985.tar.gz
rust-29005cb128e6d447e6bd9c110c9a684665f95985.zip
Auto merge of #146879 - Zalathar:rollup-vm97j8b, r=Zalathar
Rollup of 9 pull requests

Successful merges:

 - rust-lang/rust#145411 (regression test for Cow<[u8]> layout)
 - rust-lang/rust#146397 (std_detect on Darwin AArch64: update features)
 - rust-lang/rust#146791 (emit attribute for readonly non-pure inline assembly)
 - rust-lang/rust#146831 (Support ctr and lr as clobber-only registers in PowerPC inline assembly)
 - rust-lang/rust#146838 (Introduce "wrapper" helpers to rustdoc)
 - rust-lang/rust#146845 (Add self-profile events for target-machine creation)
 - rust-lang/rust#146846 (btree InternalNode::new safety comments)
 - rust-lang/rust#146858 (Make mips64el-unknown-linux-muslabi64 link dynamically)
 - rust-lang/rust#146878 (assert_unsafe_precondition: fix some incorrect check_language_ub)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp5
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/asm/mod.rs5
-rw-r--r--compiler/rustc_target/src/asm/powerpc.rs12
-rw-r--r--compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs2
-rw-r--r--library/alloc/src/collections/btree/node.rs5
-rw-r--r--library/core/src/ascii/ascii_char.rs2
-rw-r--r--library/core/src/num/int_macros.rs6
-rw-r--r--library/core/src/num/uint_macros.rs4
-rw-r--r--library/core/src/slice/index.rs2
-rw-r--r--library/core/src/ub_checks.rs5
-rw-r--r--library/std_detect/src/detect/os/darwin/aarch64.rs22
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md6
-rw-r--r--src/librustdoc/clean/cfg.rs78
-rw-r--r--src/librustdoc/display.rs86
-rw-r--r--src/librustdoc/html/format.rs348
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--tests/codegen-llvm/asm/powerpc-clobbers.rs8
-rw-r--r--tests/codegen-llvm/asm/readonly-not-pure.rs48
-rw-r--r--tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs17
-rw-r--r--tests/run-make/musl-default-linking/rmake.rs3
-rw-r--r--tests/ui/asm/powerpc/bad-reg.aix64.stderr162
-rw-r--r--tests/ui/asm/powerpc/bad-reg.powerpc.stderr176
-rw-r--r--tests/ui/asm/powerpc/bad-reg.powerpc64.stderr168
-rw-r--r--tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr162
-rw-r--r--tests/ui/asm/powerpc/bad-reg.rs30
30 files changed, 948 insertions, 462 deletions
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 17e2e028b16..a14881c502c 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -698,8 +698,12 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str {
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
-        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
-        | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+        InlineAsmRegClass::PowerPC(
+            PowerPCInlineAsmRegClass::cr
+            | PowerPCInlineAsmRegClass::ctr
+            | PowerPCInlineAsmRegClass::lr
+            | PowerPCInlineAsmRegClass::xer,
+        ) => {
             unreachable!("clobber-only")
         }
         InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
@@ -777,8 +781,12 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
         InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => {
             cx.type_vector(cx.type_i32(), 4)
         }
-        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
-        | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+        InlineAsmRegClass::PowerPC(
+            PowerPCInlineAsmRegClass::cr
+            | PowerPCInlineAsmRegClass::ctr
+            | PowerPCInlineAsmRegClass::lr
+            | PowerPCInlineAsmRegClass::xer,
+        ) => {
             unreachable!("clobber-only")
         }
         InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index b79176e9098..cc09fa5b69b 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -340,8 +340,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
             attrs.push(llvm::AttributeKind::WillReturn.create_attr(self.cx.llcx));
         } else if options.contains(InlineAsmOptions::NOMEM) {
             attrs.push(llvm::MemoryEffects::InaccessibleMemOnly.create_attr(self.cx.llcx));
-        } else {
-            // LLVM doesn't have an attribute to represent ReadOnly + SideEffect
+        } else if options.contains(InlineAsmOptions::READONLY) {
+            attrs.push(llvm::MemoryEffects::ReadOnlyNotPure.create_attr(self.cx.llcx));
         }
         attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
 
@@ -662,7 +662,12 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
             PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
             PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
             PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
-            PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => {
+            PowerPC(
+                PowerPCInlineAsmRegClass::cr
+                | PowerPCInlineAsmRegClass::ctr
+                | PowerPCInlineAsmRegClass::lr
+                | PowerPCInlineAsmRegClass::xer,
+            ) => {
                 unreachable!("clobber-only")
             }
             RiscV(RiscVInlineAsmRegClass::reg) => "r",
@@ -830,7 +835,12 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
         PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
         PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
         PowerPC(PowerPCInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i32(), 4),
-        PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => {
+        PowerPC(
+            PowerPCInlineAsmRegClass::cr
+            | PowerPCInlineAsmRegClass::ctr
+            | PowerPCInlineAsmRegClass::lr
+            | PowerPCInlineAsmRegClass::xer,
+        ) => {
             unreachable!("clobber-only")
         }
         RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index c4881f0aafc..1950b8288d1 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -204,6 +204,9 @@ pub(crate) fn target_machine_factory(
     optlvl: config::OptLevel,
     target_features: &[String],
 ) -> TargetMachineFactoryFn<LlvmCodegenBackend> {
+    // Self-profile timer for creating a _factory_.
+    let _prof_timer = sess.prof.generic_activity("target_machine_factory");
+
     let reloc_model = to_llvm_relocation_model(sess.relocation_model());
 
     let (opt_level, _) = to_llvm_opt_settings(optlvl);
@@ -259,6 +262,9 @@ pub(crate) fn target_machine_factory(
         .into_string()
         .unwrap_or_default();
     let command_line_args = quote_command_line_args(&sess.expanded_args);
+    // Self-profile counter for the number of bytes produced by command-line quoting.
+    // Values are summed, so the summary result is cumulative across all TM factories.
+    sess.prof.artifact_size("quoted_command_line_args", "-", command_line_args.len() as u64);
 
     let debuginfo_compression = sess.opts.debuginfo_compression.to_string();
     match sess.opts.debuginfo_compression {
@@ -281,7 +287,11 @@ pub(crate) fn target_machine_factory(
 
     let use_wasm_eh = wants_wasm_eh(sess);
 
+    let prof = SelfProfilerRef::clone(&sess.prof);
     Arc::new(move |config: TargetMachineFactoryConfig| {
+        // Self-profile timer for invoking a factory to create a target machine.
+        let _prof_timer = prof.generic_activity("target_machine_factory_inner");
+
         let path_to_cstring_helper = |path: Option<PathBuf>| -> CString {
             let path = path.unwrap_or_default();
             let path = path_mapping
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 9a86e4373d8..fd972f371df 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -710,6 +710,7 @@ pub(crate) enum MemoryEffects {
     None,
     ReadOnly,
     InaccessibleMemOnly,
+    ReadOnlyNotPure,
 }
 
 /// LLVMOpcode
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 64151962321..414274f24fb 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -553,6 +553,7 @@ enum class LLVMRustMemoryEffects {
   None,
   ReadOnly,
   InaccessibleMemOnly,
+  ReadOnlyNotPure,
 };
 
 extern "C" LLVMAttributeRef
@@ -568,6 +569,10 @@ LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C,
   case LLVMRustMemoryEffects::InaccessibleMemOnly:
     return wrap(Attribute::getWithMemoryEffects(
         *unwrap(C), MemoryEffects::inaccessibleMemOnly()));
+  case LLVMRustMemoryEffects::ReadOnlyNotPure:
+    return wrap(Attribute::getWithMemoryEffects(
+        *unwrap(C),
+        MemoryEffects::readOnly() | MemoryEffects::inaccessibleMemOnly()));
   default:
     report_fatal_error("bad MemoryEffects.");
   }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 4fef65f46b1..a6ae58f87dc 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -794,6 +794,7 @@ symbols! {
         ctlz,
         ctlz_nonzero,
         ctpop,
+        ctr,
         cttz,
         cttz_nonzero,
         custom_attribute,
@@ -1333,6 +1334,7 @@ symbols! {
         loongarch_target_feature,
         loop_break_value,
         loop_match,
+        lr,
         lt,
         m68k_target_feature,
         macro_at_most_once_rep,
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index e06f881e4b1..0601613567e 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -1260,11 +1260,12 @@ impl InlineAsmClobberAbi {
                     v8, v9, v10, v11, v12, v13, v14,
                     v15, v16, v17, v18, v19,
 
-                    // cr0-cr1, cr5-cr7, xer
+                    // cr0-cr1, cr5-cr7, ctr, lr, xer
                     cr0, cr1,
                     cr5, cr6, cr7,
+                    ctr,
+                    lr,
                     xer,
-                    // lr and ctr are reserved
                 }
             },
             InlineAsmClobberAbi::S390x => clobbered_regs! {
diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs
index f3934afa6d9..2348a0fd202 100644
--- a/compiler/rustc_target/src/asm/powerpc.rs
+++ b/compiler/rustc_target/src/asm/powerpc.rs
@@ -13,6 +13,8 @@ def_reg_class! {
         freg,
         vreg,
         cr,
+        ctr,
+        lr,
         xer,
     }
 }
@@ -56,7 +58,7 @@ impl PowerPCInlineAsmRegClass {
                 altivec: VecI8(16), VecI16(8), VecI32(4), VecF32(4);
                 vsx: F32, F64, VecI64(2), VecF64(2);
             },
-            Self::cr | Self::xer => &[],
+            Self::cr | Self::ctr | Self::lr | Self::xer => &[],
         }
     }
 }
@@ -195,6 +197,8 @@ def_regs! {
         cr5: cr = ["cr5"],
         cr6: cr = ["cr6"],
         cr7: cr = ["cr7"],
+        ctr: ctr = ["ctr"],
+        lr: lr = ["lr"],
         xer: xer = ["xer"],
         #error = ["r1", "1", "sp"] =>
             "the stack pointer cannot be used as an operand for inline asm",
@@ -206,10 +210,6 @@ def_regs! {
             "r30 is used internally by LLVM and cannot be used as an operand for inline asm",
         #error = ["r31", "31", "fp"] =>
             "the frame pointer cannot be used as an operand for inline asm",
-        #error = ["lr"] =>
-            "the link register cannot be used as an operand for inline asm",
-        #error = ["ctr"] =>
-            "the counter register cannot be used as an operand for inline asm",
         #error = ["vrsave"] =>
             "the vrsave register cannot be used as an operand for inline asm",
     }
@@ -247,6 +247,8 @@ impl PowerPCInlineAsmReg {
             (v24, "24"), (v25, "25"), (v26, "26"), (v27, "27"), (v28, "28"), (v29, "29"), (v30, "30"), (v31, "31");
             (cr, "cr");
             (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7");
+            (ctr, "ctr");
+            (lr, "lr");
             (xer, "xer");
         }
     }
diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
index d42e097b0fd..38c3c7dfaa1 100644
--- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs
@@ -5,8 +5,6 @@ pub(crate) fn target() -> Target {
     base.cpu = "mips64r2".into();
     base.features = "+mips64r2,+xgot".into();
     base.max_atomic_width = Some(64);
-    // FIXME(compiler-team#422): musl targets should be dynamically linked by default.
-    base.crt_static_default = true;
     Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64el-unknown-linux-musl".into(),
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index b233e1740b7..2b8103c8b77 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -117,10 +117,11 @@ impl<K, V> InternalNode<K, V> {
     /// initialized and valid edge. This function does not set up
     /// such an edge.
     unsafe fn new<A: Allocator + Clone>(alloc: A) -> Box<Self, A> {
+        let mut node = Box::<Self, _>::new_uninit_in(alloc);
         unsafe {
-            let mut node = Box::<Self, _>::new_uninit_in(alloc);
-            // We only need to initialize the data; the edges are MaybeUninit.
+            // SAFETY: argument points to the `node.data` `LeafNode`
             LeafNode::init(&raw mut (*node.as_mut_ptr()).data);
+            // SAFETY: `node.data` was just initialized and `node.edges` is MaybeUninit.
             node.assume_init()
         }
     }
diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs
index 178af2c0e3b..d77fafed203 100644
--- a/library/core/src/ascii/ascii_char.rs
+++ b/library/core/src/ascii/ascii_char.rs
@@ -515,7 +515,7 @@ impl AsciiChar {
     #[track_caller]
     pub const unsafe fn digit_unchecked(d: u8) -> Self {
         assert_unsafe_precondition!(
-            check_language_ub,
+            check_library_ub,
             "`ascii::Char::digit_unchecked` input cannot exceed 9.",
             (d: u8 = d) => d < 10
         );
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 64a3dd3e8bc..0d80c40fb23 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1460,8 +1460,8 @@ macro_rules! int_impl {
         #[inline]
         pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT {
             assert_unsafe_precondition!(
-                check_language_ub,
-                concat!(stringify!($SelfT), "::unchecked_exact_shl cannot shift out non-zero bits"),
+                check_library_ub,
+                concat!(stringify!($SelfT), "::unchecked_exact_shl cannot shift out bits that would change the value of the first bit"),
                 (
                     zeros: u32 = self.leading_zeros(),
                     ones: u32 = self.leading_ones(),
@@ -1638,7 +1638,7 @@ macro_rules! int_impl {
         #[inline]
         pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT {
             assert_unsafe_precondition!(
-                check_language_ub,
+                check_library_ub,
                 concat!(stringify!($SelfT), "::unchecked_exact_shr cannot shift out non-zero bits"),
                 (
                     zeros: u32 = self.trailing_zeros(),
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index bf72ec83197..d68c7be9865 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1865,7 +1865,7 @@ macro_rules! uint_impl {
         #[inline]
         pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT {
             assert_unsafe_precondition!(
-                check_language_ub,
+                check_library_ub,
                 concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"),
                 (
                     zeros: u32 = self.leading_zeros(),
@@ -2037,7 +2037,7 @@ macro_rules! uint_impl {
         #[inline]
         pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT {
             assert_unsafe_precondition!(
-                check_language_ub,
+                check_library_ub,
                 concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"),
                 (
                     zeros: u32 = self.trailing_zeros(),
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index a8147d745f3..d4c466201ed 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -233,7 +233,7 @@ unsafe impl<T> const SliceIndex<[T]> for usize {
     #[track_caller]
     unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
         assert_unsafe_precondition!(
-            check_language_ub,
+            check_language_ub, // okay because of the `assume` below
             "slice::get_unchecked requires that the index is within the slice",
             (this: usize = self, len: usize = slice.len()) => this < len
         );
diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs
index b809294cfce..514ff93c982 100644
--- a/library/core/src/ub_checks.rs
+++ b/library/core/src/ub_checks.rs
@@ -21,8 +21,9 @@ use crate::intrinsics::{self, const_eval_select};
 /// slow down const-eval/Miri and we'll get the panic message instead of the interpreter's nice
 /// diagnostic, but our ability to detect UB is unchanged.
 /// But if `check_language_ub` is used when the check is actually for library UB, the check is
-/// omitted in const-eval/Miri and thus if we eventually execute language UB which relies on the
-/// library UB, the backtrace Miri reports may be far removed from original cause.
+/// omitted in const-eval/Miri and thus UB might occur undetected. Even if we eventually execute
+/// language UB which relies on the library UB, the backtrace Miri reports may be far removed from
+/// original cause.
 ///
 /// These checks are behind a condition which is evaluated at codegen time, not expansion time like
 /// [`debug_assert`]. This means that a standard library built with optimizations and debug
diff --git a/library/std_detect/src/detect/os/darwin/aarch64.rs b/library/std_detect/src/detect/os/darwin/aarch64.rs
index f5409361d93..8c9fd9647b8 100644
--- a/library/std_detect/src/detect/os/darwin/aarch64.rs
+++ b/library/std_detect/src/detect/os/darwin/aarch64.rs
@@ -37,24 +37,25 @@ pub(crate) fn detect_features() -> cache::Initializer {
     // Armv8.0 features not using the standard identifiers
     let fp = _sysctlbyname(c"hw.optional.floatingpoint");
     let asimd = _sysctlbyname(c"hw.optional.AdvSIMD");
-    let crc = _sysctlbyname(c"hw.optional.armv8_crc32");
+    let crc_old = _sysctlbyname(c"hw.optional.armv8_crc32");
 
     // Armv8 and Armv9 features using the standard identifiers
     let aes = _sysctlbyname(c"hw.optional.arm.FEAT_AES");
     let bf16 = _sysctlbyname(c"hw.optional.arm.FEAT_BF16");
     let bti = _sysctlbyname(c"hw.optional.arm.FEAT_BTI");
+    let crc = _sysctlbyname(c"hw.optional.arm.FEAT_CRC32");
     let cssc = _sysctlbyname(c"hw.optional.arm.FEAT_CSSC");
     let dit = _sysctlbyname(c"hw.optional.arm.FEAT_DIT");
+    let dotprod = _sysctlbyname(c"hw.optional.arm.FEAT_DotProd");
     let dpb = _sysctlbyname(c"hw.optional.arm.FEAT_DPB");
     let dpb2 = _sysctlbyname(c"hw.optional.arm.FEAT_DPB2");
-    let dotprod = _sysctlbyname(c"hw.optional.arm.FEAT_DotProd");
     let ecv = _sysctlbyname(c"hw.optional.arm.FEAT_ECV");
     let fcma = _sysctlbyname(c"hw.optional.arm.FEAT_FCMA");
     let fhm = _sysctlbyname(c"hw.optional.arm.FEAT_FHM");
-    let fp16 = _sysctlbyname(c"hw.optional.arm.FEAT_FP16");
-    let frintts = _sysctlbyname(c"hw.optional.arm.FEAT_FRINTTS");
     let flagm = _sysctlbyname(c"hw.optional.arm.FEAT_FlagM");
     let flagm2 = _sysctlbyname(c"hw.optional.arm.FEAT_FlagM2");
+    let fp16 = _sysctlbyname(c"hw.optional.arm.FEAT_FP16");
+    let frintts = _sysctlbyname(c"hw.optional.arm.FEAT_FRINTTS");
     let hbc = _sysctlbyname(c"hw.optional.arm.FEAT_HBC");
     let i8mm = _sysctlbyname(c"hw.optional.arm.FEAT_I8MM");
     let jsconv = _sysctlbyname(c"hw.optional.arm.FEAT_JSCVT");
@@ -62,6 +63,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
     let rcpc2 = _sysctlbyname(c"hw.optional.arm.FEAT_LRCPC2");
     let lse = _sysctlbyname(c"hw.optional.arm.FEAT_LSE");
     let lse2 = _sysctlbyname(c"hw.optional.arm.FEAT_LSE2");
+    let mte = _sysctlbyname(c"hw.optional.arm.FEAT_MTE");
+    let mte2 = _sysctlbyname(c"hw.optional.arm.FEAT_MTE2");
     let pauth = _sysctlbyname(c"hw.optional.arm.FEAT_PAuth");
     let pmull = _sysctlbyname(c"hw.optional.arm.FEAT_PMULL");
     let rdm = _sysctlbyname(c"hw.optional.arm.FEAT_RDM");
@@ -72,6 +75,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
     let sha512 = _sysctlbyname(c"hw.optional.arm.FEAT_SHA512");
     let sme = _sysctlbyname(c"hw.optional.arm.FEAT_SME");
     let sme2 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2");
+    let sme2p1 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2p1");
     let sme_f64f64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F64F64");
     let sme_i16i64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_I16I64");
     let ssbs = _sysctlbyname(c"hw.optional.arm.FEAT_SSBS");
@@ -87,6 +91,12 @@ pub(crate) fn detect_features() -> cache::Initializer {
     let ebf16 = _sysctlbyname(c"hw.optional.arm.FEAT_EBF16");
     let fpac = _sysctlbyname(c"hw.optional.arm.FEAT_FPAC");
     let fpaccombine = _sysctlbyname(c"hw.optional.arm.FEAT_FPACCOMBINE");
+    let mte_async = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_ASYNC");
+    let mte_canonical_tags = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_CANONICAL_TAGS");
+    let mte_no_address_tags = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_NO_ADDRESS_TAGS");
+    let mte_store_only = _sysctlbyname(c"hw.optional.arm.FEAT_MTE_STORE_ONLY");
+    let mte3 = _sysctlbyname(c"hw.optional.arm.FEAT_MTE3");
+    let mte4 = _sysctlbyname(c"hw.optional.arm.FEAT_MTE4");
     let pacimp = _sysctlbyname(c"hw.optional.arm.FEAT_PACIMP");
     let pauth2 = _sysctlbyname(c"hw.optional.arm.FEAT_PAuth2");
     let rpres = _sysctlbyname(c"hw.optional.arm.FEAT_RPRES");
@@ -111,7 +121,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
     enable_feature(Feature::asimd, asimd);
     enable_feature(Feature::bf16, bf16);
     enable_feature(Feature::bti, bti);
-    enable_feature(Feature::crc, crc);
+    enable_feature(Feature::crc, crc_old || crc);
     enable_feature(Feature::cssc, cssc);
     enable_feature(Feature::dit, dit);
     enable_feature(Feature::dotprod, dotprod);
@@ -130,6 +140,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
     enable_feature(Feature::jsconv, jsconv);
     enable_feature(Feature::lse, lse);
     enable_feature(Feature::lse2, lse2);
+    enable_feature(Feature::mte, mte && mte2);
     enable_feature(Feature::paca, pauth);
     enable_feature(Feature::pacg, pauth);
     enable_feature(Feature::pmull, aes && pmull);
@@ -141,6 +152,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
     enable_feature(Feature::sha3, sha512 && sha3 && asimd);
     enable_feature(Feature::sme, sme);
     enable_feature(Feature::sme2, sme2);
+    enable_feature(Feature::sme2p1, sme2p1);
     enable_feature(Feature::sme_f64f64, sme_f64f64);
     enable_feature(Feature::sme_i16i64, sme_i16i64);
     enable_feature(Feature::ssbs, ssbs);
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index d9566c9f55c..9434868dc08 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -36,6 +36,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | PowerPC      | `freg`         | `f[0-31]`                          | `f`                  |
 | PowerPC      | `vreg`         | `v[0-31]`                          | `v`                  |
 | PowerPC      | `cr`           | `cr[0-7]`, `cr`                    | Only clobbers        |
+| PowerPC      | `ctr`          | `ctr`                              | Only clobbers        |
+| PowerPC      | `lr`           | `lr`                               | Only clobbers        |
 | PowerPC      | `xer`          | `xer`                              | Only clobbers        |
 | wasm32       | `local`        | None\*                             | `r`                  |
 | BPF          | `reg`          | `r[0-10]`                          | `r`                  |
@@ -78,6 +80,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | PowerPC      | `vreg`                          | `altivec`      | `i8x16`, `i16x8`, `i32x4`, `f32x4`      |
 | PowerPC      | `vreg`                          | `vsx`          | `f32`, `f64`, `i64x2`, `f64x2`          |
 | PowerPC      | `cr`                            | N/A            | Only clobbers                           |
+| PowerPC      | `ctr`                           | N/A            | Only clobbers                           |
+| PowerPC      | `lr`                            | N/A            | Only clobbers                           |
 | PowerPC      | `xer`                           | N/A            | Only clobbers                           |
 | wasm32       | `local`                         | None           | `i8` `i16` `i32` `i64` `f32` `f64`      |
 | BPF          | `reg`                           | None           | `i8` `i16` `i32` `i64`                  |
@@ -150,8 +154,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | MIPS         | `$ra`                                   | Return address cannot be used as inputs or outputs.                                                                                                                                 |
 | Hexagon      | `lr`                                    | This is the link register which cannot be used as an input or output.                                                                                                               |
 | PowerPC      | `r2`, `r13`                             | These are system reserved registers.                                                                                                                                                |
-| PowerPC      | `lr`                                    | The link register cannot be used as an input or output.                                                                                                                             |
-| PowerPC      | `ctr`                                   | The counter register cannot be used as an input or output.                                                                                                                          |
 | PowerPC      | `vrsave`                                | The vrsave register cannot be used as an input or output.                                                                                                                           |
 | AVR          | `r0`, `r1`, `r1r0`                      | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs.  If modified, they must be restored to their original values before the end of the block. |
 |MSP430        | `r0`, `r2`, `r3`                        | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to.                          |
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index e204e1788ba..8feca1367fc 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -3,16 +3,16 @@
 // FIXME: Once the portability lint RFC is implemented (see tracking issue #41619),
 // switch to use those structures instead.
 
-use std::fmt::{self, Write};
-use std::{mem, ops};
+use std::{fmt, mem, ops};
 
+use itertools::Either;
 use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_session::parse::ParseSess;
 use rustc_span::Span;
 use rustc_span::symbol::{Symbol, sym};
 
-use crate::display::Joined as _;
+use crate::display::{Joined as _, MaybeDisplay, Wrapped};
 use crate::html::escape::Escape;
 
 #[cfg(test)]
@@ -376,27 +376,20 @@ impl Format {
             Format::LongPlain => false,
         }
     }
+
+    fn escape(self, s: &str) -> impl fmt::Display {
+        if self.is_html() { Either::Left(Escape(s)) } else { Either::Right(s) }
+    }
 }
 
 /// Pretty-print wrapper for a `Cfg`. Also indicates what form of rendering should be used.
 struct Display<'a>(&'a Cfg, Format);
 
-fn write_with_opt_paren<T: fmt::Display>(
-    fmt: &mut fmt::Formatter<'_>,
-    has_paren: bool,
-    obj: T,
-) -> fmt::Result {
-    if has_paren {
-        fmt.write_char('(')?;
-    }
-    obj.fmt(fmt)?;
-    if has_paren {
-        fmt.write_char(')')?;
+impl Display<'_> {
+    fn code_wrappers(&self) -> Wrapped<&'static str> {
+        if self.1.is_html() { Wrapped::with("<code>", "</code>") } else { Wrapped::with("`", "`") }
     }
-    Ok(())
-}
 
-impl Display<'_> {
     fn display_sub_cfgs(
         &self,
         fmt: &mut fmt::Formatter<'_>,
@@ -427,20 +420,17 @@ impl Display<'_> {
             sub_cfgs
                 .iter()
                 .map(|sub_cfg| {
-                    fmt::from_fn(move |fmt| {
-                        if let Cfg::Cfg(_, Some(feat)) = sub_cfg
-                            && short_longhand
-                        {
-                            if self.1.is_html() {
-                                write!(fmt, "<code>{feat}</code>")?;
-                            } else {
-                                write!(fmt, "`{feat}`")?;
-                            }
-                        } else {
-                            write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
-                        }
-                        Ok(())
-                    })
+                    if let Cfg::Cfg(_, Some(feat)) = sub_cfg
+                        && short_longhand
+                    {
+                        Either::Left(self.code_wrappers().wrap(feat))
+                    } else {
+                        Either::Right(
+                            Wrapped::with_parens()
+                                .when(!sub_cfg.is_all())
+                                .wrap(Display(sub_cfg, self.1)),
+                        )
+                    }
                 })
                 .joined(separator, f)
         })
@@ -461,9 +451,9 @@ impl fmt::Display for Display<'_> {
                 sub_cfgs
                     .iter()
                     .map(|sub_cfg| {
-                        fmt::from_fn(|fmt| {
-                            write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))
-                        })
+                        Wrapped::with_parens()
+                            .when(!sub_cfg.is_all())
+                            .wrap(Display(sub_cfg, self.1))
                     })
                     .joined(separator, fmt)
             }
@@ -568,21 +558,13 @@ impl fmt::Display for Display<'_> {
                 };
                 if !human_readable.is_empty() {
                     fmt.write_str(human_readable)
-                } else if let Some(v) = value {
-                    if self.1.is_html() {
-                        write!(
-                            fmt,
-                            r#"<code>{}="{}"</code>"#,
-                            Escape(name.as_str()),
-                            Escape(v.as_str())
-                        )
-                    } else {
-                        write!(fmt, r#"`{name}="{v}"`"#)
-                    }
-                } else if self.1.is_html() {
-                    write!(fmt, "<code>{}</code>", Escape(name.as_str()))
                 } else {
-                    write!(fmt, "`{name}`")
+                    let value = value
+                        .map(|v| fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str()))))
+                        .maybe_display();
+                    self.code_wrappers()
+                        .wrap(format_args!("{}{value}", self.1.escape(name.as_str())))
+                        .fmt(fmt)
                 }
             }
         }
diff --git a/src/librustdoc/display.rs b/src/librustdoc/display.rs
index db868c5c9a8..d62ea4c3688 100644
--- a/src/librustdoc/display.rs
+++ b/src/librustdoc/display.rs
@@ -1,6 +1,6 @@
 //! Various utilities for working with [`fmt::Display`] implementations.
 
-use std::fmt::{self, Display, Formatter};
+use std::fmt::{self, Display, Formatter, FormattingOptions};
 
 pub(crate) trait Joined: IntoIterator {
     /// Takes an iterator over elements that implement [`Display`], and format them into `f`, separated by `sep`.
@@ -45,3 +45,87 @@ impl<T: Display> MaybeDisplay for Option<T> {
         })
     }
 }
+
+#[derive(Clone, Copy)]
+pub(crate) struct Wrapped<T> {
+    prefix: T,
+    suffix: T,
+}
+
+pub(crate) enum AngleBracket {
+    Open,
+    Close,
+}
+
+impl Display for AngleBracket {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        f.write_str(match (self, f.alternate()) {
+            (Self::Open, true) => "<",
+            (Self::Open, false) => "&lt;",
+            (Self::Close, true) => ">",
+            (Self::Close, false) => "&gt;",
+        })
+    }
+}
+
+impl Wrapped<AngleBracket> {
+    pub(crate) fn with_angle_brackets() -> Self {
+        Self { prefix: AngleBracket::Open, suffix: AngleBracket::Close }
+    }
+}
+
+impl Wrapped<char> {
+    pub(crate) fn with_parens() -> Self {
+        Self { prefix: '(', suffix: ')' }
+    }
+
+    pub(crate) fn with_square_brackets() -> Self {
+        Self { prefix: '[', suffix: ']' }
+    }
+}
+
+impl<T: Display> Wrapped<T> {
+    pub(crate) fn with(prefix: T, suffix: T) -> Self {
+        Self { prefix, suffix }
+    }
+
+    pub(crate) fn when(self, if_: bool) -> Wrapped<impl Display> {
+        Wrapped {
+            prefix: if_.then_some(self.prefix).maybe_display(),
+            suffix: if_.then_some(self.suffix).maybe_display(),
+        }
+    }
+
+    pub(crate) fn wrap_fn(
+        self,
+        content: impl Fn(&mut Formatter<'_>) -> fmt::Result,
+    ) -> impl Display {
+        fmt::from_fn(move |f| {
+            self.prefix.fmt(f)?;
+            content(f)?;
+            self.suffix.fmt(f)
+        })
+    }
+
+    pub(crate) fn wrap<C: Display>(self, content: C) -> impl Display {
+        self.wrap_fn(move |f| content.fmt(f))
+    }
+}
+
+#[derive(Clone, Copy)]
+pub(crate) struct WithOpts {
+    opts: FormattingOptions,
+}
+
+impl WithOpts {
+    pub(crate) fn from(f: &Formatter<'_>) -> Self {
+        Self { opts: f.options() }
+    }
+
+    pub(crate) fn display(self, t: impl Display) -> impl Display {
+        fmt::from_fn(move |f| {
+            let mut f = f.with_options(self.opts);
+            t.fmt(&mut f)
+        })
+    }
+}
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 8c75f301841..ecaff4cdf43 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -30,7 +30,7 @@ use super::url_parts_builder::UrlPartsBuilder;
 use crate::clean::types::ExternalLocation;
 use crate::clean::utils::find_nearest_parent_module;
 use crate::clean::{self, ExternalCrate, PrimitiveType};
-use crate::display::{Joined as _, MaybeDisplay as _};
+use crate::display::{Joined as _, MaybeDisplay as _, WithOpts, Wrapped};
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::{Escape, EscapeBodyText};
@@ -105,20 +105,16 @@ impl clean::GenericParamDef {
 
 impl clean::Generics {
     pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
-        fmt::from_fn(move |f| {
-            let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
-            if real_params.peek().is_none() {
-                return Ok(());
-            }
-
-            let real_params =
-                fmt::from_fn(|f| real_params.clone().map(|g| g.print(cx)).joined(", ", f));
-            if f.alternate() {
-                write!(f, "<{real_params:#}>")
-            } else {
-                write!(f, "&lt;{real_params}&gt;")
-            }
-        })
+        let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
+        if real_params.peek().is_none() {
+            None
+        } else {
+            Some(
+                Wrapped::with_angle_brackets()
+                    .wrap_fn(move |f| real_params.clone().map(|g| g.print(cx)).joined(", ", f)),
+            )
+        }
+        .maybe_display()
     }
 }
 
@@ -151,11 +147,8 @@ fn print_where_predicate(predicate: &clean::WherePredicate, cx: &Context<'_>) ->
                 Ok(())
             }
             clean::WherePredicate::EqPredicate { lhs, rhs } => {
-                if f.alternate() {
-                    write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
-                } else {
-                    write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
-                }
+                let opts = WithOpts::from(f);
+                write!(f, "{} == {}", opts.display(lhs.print(cx)), opts.display(rhs.print(cx)))
             }
         }
     })
@@ -279,13 +272,10 @@ impl clean::GenericBound {
                 ty.print(cx).fmt(f)
             }
             clean::GenericBound::Use(args) => {
-                if f.alternate() {
-                    f.write_str("use<")?;
-                } else {
-                    f.write_str("use&lt;")?;
-                }
-                args.iter().map(|arg| arg.name()).joined(", ", f)?;
-                if f.alternate() { f.write_str(">") } else { f.write_str("&gt;") }
+                f.write_str("use")?;
+                Wrapped::with_angle_brackets()
+                    .wrap_fn(|f| args.iter().map(|arg| arg.name()).joined(", ", f))
+                    .fmt(f)
             }
         })
     }
@@ -297,40 +287,29 @@ impl clean::GenericArgs {
             match self {
                 clean::GenericArgs::AngleBracketed { args, constraints } => {
                     if !args.is_empty() || !constraints.is_empty() {
-                        if f.alternate() {
-                            f.write_str("<")?;
-                        } else {
-                            f.write_str("&lt;")?;
-                        }
-
-                        [Either::Left(args), Either::Right(constraints)]
-                            .into_iter()
-                            .flat_map(Either::factor_into_iter)
-                            .map(|either| {
-                                either.map_either(
-                                    |arg| arg.print(cx),
-                                    |constraint| constraint.print(cx),
-                                )
+                        Wrapped::with_angle_brackets()
+                            .wrap_fn(|f| {
+                                [Either::Left(args), Either::Right(constraints)]
+                                    .into_iter()
+                                    .flat_map(Either::factor_into_iter)
+                                    .map(|either| {
+                                        either.map_either(
+                                            |arg| arg.print(cx),
+                                            |constraint| constraint.print(cx),
+                                        )
+                                    })
+                                    .joined(", ", f)
                             })
-                            .joined(", ", f)?;
-
-                        if f.alternate() {
-                            f.write_str(">")?;
-                        } else {
-                            f.write_str("&gt;")?;
-                        }
+                            .fmt(f)?;
                     }
                 }
                 clean::GenericArgs::Parenthesized { inputs, output } => {
-                    f.write_str("(")?;
-                    inputs.iter().map(|ty| ty.print(cx)).joined(", ", f)?;
-                    f.write_str(")")?;
+                    Wrapped::with_parens()
+                        .wrap_fn(|f| inputs.iter().map(|ty| ty.print(cx)).joined(", ", f))
+                        .fmt(f)?;
                     if let Some(ref ty) = *output {
-                        if f.alternate() {
-                            write!(f, " -> {:#}", ty.print(cx))?;
-                        } else {
-                            write!(f, " -&gt; {}", ty.print(cx))?;
-                        }
+                        f.write_str(if f.alternate() { " -> " } else { " -&gt; " })?;
+                        ty.print(cx).fmt(f)?;
                     }
                 }
                 clean::GenericArgs::ReturnTypeNotation => {
@@ -834,9 +813,10 @@ fn print_higher_ranked_params_with_space(
     fmt::from_fn(move |f| {
         if !params.is_empty() {
             f.write_str(keyword)?;
-            f.write_str(if f.alternate() { "<" } else { "&lt;" })?;
-            params.iter().map(|lt| lt.print(cx)).joined(", ", f)?;
-            f.write_str(if f.alternate() { "> " } else { "&gt; " })?;
+            Wrapped::with_angle_brackets()
+                .wrap_fn(|f| params.iter().map(|lt| lt.print(cx)).joined(", ", f))
+                .fmt(f)?;
+            f.write_char(' ')?;
         }
         Ok(())
     })
@@ -923,26 +903,23 @@ fn fmt_type(
                         f,
                         PrimitiveType::Tuple,
                         format_args!(
-                            "({})",
-                            fmt::from_fn(|f| generic_names.iter().joined(", ", f))
+                            "{}",
+                            Wrapped::with_parens()
+                                .wrap_fn(|f| generic_names.iter().joined(", ", f))
                         ),
                         cx,
                     )
                 } else {
-                    f.write_str("(")?;
-                    many.iter().map(|item| item.print(cx)).joined(", ", f)?;
-                    f.write_str(")")
+                    Wrapped::with_parens()
+                        .wrap_fn(|f| many.iter().map(|item| item.print(cx)).joined(", ", f))
+                        .fmt(f)
                 }
             }
         },
         clean::Slice(box clean::Generic(name)) => {
             primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx)
         }
-        clean::Slice(t) => {
-            write!(f, "[")?;
-            t.print(cx).fmt(f)?;
-            write!(f, "]")
-        }
+        clean::Slice(t) => Wrapped::with_square_brackets().wrap(t.print(cx)).fmt(f),
         clean::Type::Pat(t, pat) => {
             fmt::Display::fmt(&t.print(cx), f)?;
             write!(f, " is {pat}")
@@ -953,40 +930,27 @@ fn fmt_type(
             format_args!("[{name}; {n}]", n = Escape(n)),
             cx,
         ),
-        clean::Array(t, n) => {
-            write!(f, "[")?;
-            t.print(cx).fmt(f)?;
-            if f.alternate() {
-                write!(f, "; {n}")?;
-            } else {
-                write!(f, "; ")?;
-                primitive_link(f, PrimitiveType::Array, format_args!("{n}", n = Escape(n)), cx)?;
-            }
-            write!(f, "]")
-        }
-        clean::RawPointer(m, t) => {
-            let m = match m {
-                hir::Mutability::Mut => "mut",
-                hir::Mutability::Not => "const",
-            };
-
-            if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() {
-                let ty = t.print(cx);
+        clean::Array(t, n) => Wrapped::with_square_brackets()
+            .wrap(fmt::from_fn(|f| {
+                t.print(cx).fmt(f)?;
+                f.write_str("; ")?;
                 if f.alternate() {
-                    primitive_link(
-                        f,
-                        clean::PrimitiveType::RawPointer,
-                        format_args!("*{m} {ty:#}"),
-                        cx,
-                    )
+                    f.write_str(n)
                 } else {
-                    primitive_link(
-                        f,
-                        clean::PrimitiveType::RawPointer,
-                        format_args!("*{m} {ty}"),
-                        cx,
-                    )
+                    primitive_link(f, PrimitiveType::Array, format_args!("{n}", n = Escape(n)), cx)
                 }
+            }))
+            .fmt(f),
+        clean::RawPointer(m, t) => {
+            let m = m.ptr_str();
+
+            if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() {
+                primitive_link(
+                    f,
+                    clean::PrimitiveType::RawPointer,
+                    format_args!("*{m} {ty}", ty = WithOpts::from(f).display(t.print(cx))),
+                    cx,
+                )
             } else {
                 primitive_link(f, clean::PrimitiveType::RawPointer, format_args!("*{m} "), cx)?;
                 t.print(cx).fmt(f)
@@ -1020,14 +984,10 @@ fn fmt_type(
                 clean::ImplTrait(ref bounds) if bounds.len() > 1 => true,
                 _ => false,
             };
-            if needs_parens {
-                f.write_str("(")?;
-            }
-            fmt_type(ty, f, use_absolute, cx)?;
-            if needs_parens {
-                f.write_str(")")?;
-            }
-            Ok(())
+            Wrapped::with_parens()
+                .when(needs_parens)
+                .wrap_fn(|f| fmt_type(ty, f, use_absolute, cx))
+                .fmt(f)
         }
         clean::ImplTrait(bounds) => {
             f.write_str("impl ")?;
@@ -1057,23 +1017,21 @@ impl clean::QPathData {
             // FIXME(inherent_associated_types): Once we support non-ADT self-types (#106719),
             // we need to surround them with angle brackets in some cases (e.g. `<dyn …>::P`).
 
-            if f.alternate() {
-                if let Some(trait_) = trait_
-                    && should_fully_qualify
-                {
-                    write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))?
-                } else {
-                    write!(f, "{:#}::", self_type.print(cx))?
-                }
+            if let Some(trait_) = trait_
+                && should_fully_qualify
+            {
+                let opts = WithOpts::from(f);
+                Wrapped::with_angle_brackets()
+                    .wrap(format_args!(
+                        "{} as {}",
+                        opts.display(self_type.print(cx)),
+                        opts.display(trait_.print(cx))
+                    ))
+                    .fmt(f)?
             } else {
-                if let Some(trait_) = trait_
-                    && should_fully_qualify
-                {
-                    write!(f, "&lt;{} as {}&gt;::", self_type.print(cx), trait_.print(cx))?
-                } else {
-                    write!(f, "{}::", self_type.print(cx))?
-                }
-            };
+                self_type.print(cx).fmt(f)?;
+            }
+            f.write_str("::")?;
             // It's pretty unsightly to look at `<A as B>::C` in output, and
             // we've got hyperlinking on our side, so try to avoid longer
             // notation as much as possible by making `C` a hyperlink to trait
@@ -1132,7 +1090,7 @@ impl clean::Impl {
 
             if let Some(ref ty) = self.trait_ {
                 if self.is_negative_trait_impl() {
-                    write!(f, "!")?;
+                    f.write_char('!')?;
                 }
                 if self.kind.is_fake_variadic()
                     && let Some(generics) = ty.generics()
@@ -1140,18 +1098,17 @@ impl clean::Impl {
                 {
                     let last = ty.last();
                     if f.alternate() {
-                        write!(f, "{last}<")?;
-                        self.print_type(inner_type, f, use_absolute, cx)?;
-                        write!(f, ">")?;
+                        write!(f, "{last}")?;
                     } else {
-                        write!(f, "{}&lt;", print_anchor(ty.def_id(), last, cx))?;
-                        self.print_type(inner_type, f, use_absolute, cx)?;
-                        write!(f, "&gt;")?;
-                    }
+                        write!(f, "{}", print_anchor(ty.def_id(), last, cx))?;
+                    };
+                    Wrapped::with_angle_brackets()
+                        .wrap_fn(|f| self.print_type(inner_type, f, use_absolute, cx))
+                        .fmt(f)?;
                 } else {
                     ty.print(cx).fmt(f)?;
                 }
-                write!(f, " for ")?;
+                f.write_str(" for ")?;
             }
 
             if let Some(ty) = self.kind.as_blanket_ty() {
@@ -1218,18 +1175,10 @@ impl clean::Impl {
             && let Ok(ty) = generics.exactly_one()
             && self.kind.is_fake_variadic()
         {
-            let wrapper = print_anchor(path.def_id(), path.last(), cx);
-            if f.alternate() {
-                write!(f, "{wrapper:#}&lt;")?;
-            } else {
-                write!(f, "{wrapper}<")?;
-            }
-            self.print_type(ty, f, use_absolute, cx)?;
-            if f.alternate() {
-                write!(f, "&gt;")?;
-            } else {
-                write!(f, ">")?;
-            }
+            print_anchor(path.def_id(), path.last(), cx).fmt(f)?;
+            Wrapped::with_angle_brackets()
+                .wrap_fn(|f| self.print_type(ty, f, use_absolute, cx))
+                .fmt(f)?;
         } else {
             fmt_type(type_, f, use_absolute, cx)?;
         }
@@ -1311,23 +1260,13 @@ impl clean::FnDecl {
     pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| {
             let ellipsis = if self.c_variadic { ", ..." } else { "" };
-            if f.alternate() {
-                write!(
-                    f,
-                    "({params:#}{ellipsis}){arrow:#}",
-                    params = print_params(&self.inputs, cx),
-                    ellipsis = ellipsis,
-                    arrow = self.print_output(cx)
-                )
-            } else {
-                write!(
-                    f,
-                    "({params}{ellipsis}){arrow}",
-                    params = print_params(&self.inputs, cx),
-                    ellipsis = ellipsis,
-                    arrow = self.print_output(cx)
-                )
-            }
+            Wrapped::with_parens()
+                .wrap_fn(|f| {
+                    print_params(&self.inputs, cx).fmt(f)?;
+                    f.write_str(ellipsis)
+                })
+                .fmt(f)?;
+            self.print_output(cx).fmt(f)
         })
     }
 
@@ -1346,8 +1285,7 @@ impl clean::FnDecl {
         fmt::from_fn(move |f| {
             // First, generate the text form of the declaration, with no line wrapping, and count the bytes.
             let mut counter = WriteCounter(0);
-            write!(&mut counter, "{:#}", fmt::from_fn(|f| { self.inner_full_print(None, f, cx) }))
-                .unwrap();
+            write!(&mut counter, "{:#}", fmt::from_fn(|f| { self.inner_full_print(None, f, cx) }))?;
             // If the text form was over 80 characters wide, we will line-wrap our output.
             let line_wrapping_indent =
                 if header_len + counter.0 > 80 { Some(indent) } else { None };
@@ -1365,53 +1303,56 @@ impl clean::FnDecl {
         f: &mut fmt::Formatter<'_>,
         cx: &Context<'_>,
     ) -> fmt::Result {
-        f.write_char('(')?;
+        Wrapped::with_parens()
+            .wrap_fn(|f| {
+                if !self.inputs.is_empty() {
+                    let line_wrapping_indent = line_wrapping_indent.map(|n| Indent(n + 4));
 
-        if !self.inputs.is_empty() {
-            let line_wrapping_indent = line_wrapping_indent.map(|n| Indent(n + 4));
-
-            if let Some(indent) = line_wrapping_indent {
-                write!(f, "\n{indent}")?;
-            }
+                    if let Some(indent) = line_wrapping_indent {
+                        write!(f, "\n{indent}")?;
+                    }
 
-            let sep = fmt::from_fn(|f| {
-                if let Some(indent) = line_wrapping_indent {
-                    write!(f, ",\n{indent}")
-                } else {
-                    f.write_str(", ")
-                }
-            });
+                    let sep = fmt::from_fn(|f| {
+                        if let Some(indent) = line_wrapping_indent {
+                            write!(f, ",\n{indent}")
+                        } else {
+                            f.write_str(", ")
+                        }
+                    });
 
-            self.inputs.iter().map(|param| param.print(cx)).joined(sep, f)?;
+                    self.inputs.iter().map(|param| param.print(cx)).joined(sep, f)?;
 
-            if line_wrapping_indent.is_some() {
-                writeln!(f, ",")?
-            }
+                    if line_wrapping_indent.is_some() {
+                        writeln!(f, ",")?
+                    }
 
-            if self.c_variadic {
-                match line_wrapping_indent {
-                    None => write!(f, ", ...")?,
-                    Some(indent) => writeln!(f, "{indent}...")?,
-                };
-            }
-        }
+                    if self.c_variadic {
+                        match line_wrapping_indent {
+                            None => write!(f, ", ...")?,
+                            Some(indent) => writeln!(f, "{indent}...")?,
+                        };
+                    }
+                }
 
-        if let Some(n) = line_wrapping_indent {
-            write!(f, "{}", Indent(n))?
-        }
+                if let Some(n) = line_wrapping_indent {
+                    write!(f, "{}", Indent(n))?
+                }
 
-        f.write_char(')')?;
+                Ok(())
+            })
+            .fmt(f)?;
 
         self.print_output(cx).fmt(f)
     }
 
     fn print_output(&self, cx: &Context<'_>) -> impl Display {
-        fmt::from_fn(move |f| match &self.output {
-            clean::Tuple(tys) if tys.is_empty() => Ok(()),
-            ty if f.alternate() => {
-                write!(f, " -> {:#}", ty.print(cx))
+        fmt::from_fn(move |f| {
+            if self.output.is_unit() {
+                return Ok(());
             }
-            ty => write!(f, " -&gt; {}", ty.print(cx)),
+
+            f.write_str(if f.alternate() { " -> " } else { " -&gt; " })?;
+            self.output.print(cx).fmt(f)
         })
     }
 }
@@ -1422,10 +1363,13 @@ pub(crate) fn visibility_print_with_space(item: &clean::Item, cx: &Context<'_>)
             f.write_str("#[doc(hidden)] ")?;
         }
 
-        match item.visibility(cx.tcx()) {
-            None => {}
-            Some(ty::Visibility::Public) => f.write_str("pub ")?,
-            Some(ty::Visibility::Restricted(vis_did)) => {
+        let Some(vis) = item.visibility(cx.tcx()) else {
+            return Ok(());
+        };
+
+        match vis {
+            ty::Visibility::Public => f.write_str("pub ")?,
+            ty::Visibility::Restricted(vis_did) => {
                 // FIXME(camelid): This may not work correctly if `item_did` is a module.
                 //                 However, rustdoc currently never displays a module's
                 //                 visibility, so it shouldn't matter.
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 9871066b9eb..0ff1c090689 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -10,6 +10,7 @@
 #![feature(box_patterns)]
 #![feature(debug_closure_helpers)]
 #![feature(file_buffered)]
+#![feature(formatting_options)]
 #![feature(if_let_guard)]
 #![feature(iter_advance_by)]
 #![feature(iter_intersperse)]
diff --git a/tests/codegen-llvm/asm/powerpc-clobbers.rs b/tests/codegen-llvm/asm/powerpc-clobbers.rs
index f7fc7eea5d5..10d7ae4dba4 100644
--- a/tests/codegen-llvm/asm/powerpc-clobbers.rs
+++ b/tests/codegen-llvm/asm/powerpc-clobbers.rs
@@ -58,10 +58,10 @@ pub unsafe fn v0_clobber() {
 
 // Output format depends on the availability of altivec.
 // CHECK-LABEL: @clobber_abi
-// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
-// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
-// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
-// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"()
+// powerpc: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"()
+// powerpc64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"()
+// powerpc64le: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"()
+// aix64: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},={v0},={v1},={v2},={v3},={v4},={v5},={v6},={v7},={v8},={v9},={v10},={v11},={v12},={v13},={v14},={v15},={v16},={v17},={v18},={v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{ctr},~{lr},~{xer}"()
 #[no_mangle]
 pub unsafe fn clobber_abi() {
     asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags));
diff --git a/tests/codegen-llvm/asm/readonly-not-pure.rs b/tests/codegen-llvm/asm/readonly-not-pure.rs
new file mode 100644
index 00000000000..a3c0e276c7f
--- /dev/null
+++ b/tests/codegen-llvm/asm/readonly-not-pure.rs
@@ -0,0 +1,48 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3 --target x86_64-unknown-linux-gnu
+//@ needs-llvm-components: x86
+
+#![crate_type = "rlib"]
+#![feature(no_core)]
+#![no_core]
+
+// Test that when an inline assembly block specifies `readonly` but not `pure`, a detailed
+// `MemoryEffects` is provided to LLVM: this assembly block is not allowed to perform writes,
+// but it may have side-effects.
+
+extern crate minicore;
+use minicore::*;
+
+pub static mut VAR: i32 = 0;
+
+// CHECK-LABEL: @no_options
+// CHECK: call i32 asm
+#[no_mangle]
+pub unsafe fn no_options() -> i32 {
+    VAR = 1;
+    let _ignored: i32;
+    asm!("mov {0}, 1", out(reg) _ignored);
+    VAR
+}
+
+// CHECK-LABEL: @readonly_pure
+// CHECK-NOT: call i32 asm
+#[no_mangle]
+pub unsafe fn readonly_pure() -> i32 {
+    VAR = 1;
+    let _ignored: i32;
+    asm!("mov {0}, 1", out(reg) _ignored, options(pure, readonly));
+    VAR
+}
+
+// CHECK-LABEL: @readonly_not_pure
+// CHECK: call i32 asm {{.*}} #[[ATTR:[0-9]+]]
+#[no_mangle]
+pub unsafe fn readonly_not_pure() -> i32 {
+    VAR = 1;
+    let _ignored: i32;
+    asm!("mov {0}, 1", out(reg) _ignored, options(readonly));
+    VAR
+}
+
+// CHECK: attributes #[[ATTR]] = { nounwind memory(read, inaccessiblemem: readwrite) }
diff --git a/tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs b/tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs
new file mode 100644
index 00000000000..b97729fa146
--- /dev/null
+++ b/tests/codegen-llvm/issues/cows-dont-have-branches-117763.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Copt-level=3
+//@ needs-deterministic-layouts
+
+// Currently Vec<T> and &[T] have layouts that start with (pointer, len)
+// which makes the conversion branchless.
+// A nice-to-have property, not guaranteed.
+#![crate_type = "cdylib"]
+
+// CHECK-LABEL: @branchless_cow_slices
+#[no_mangle]
+pub fn branchless_cow_slices<'a>(cow: &'a std::borrow::Cow<'a, [u8]>) -> &'a [u8] {
+    // CHECK-NOT: br
+    // CHECK-NOT: select
+    // CHECK-NOT: icmp
+    // CHECK: ret { ptr, {{i32|i64}} }
+    &*cow
+}
diff --git a/tests/run-make/musl-default-linking/rmake.rs b/tests/run-make/musl-default-linking/rmake.rs
index 1b30c538b5e..e9d09e359c6 100644
--- a/tests/run-make/musl-default-linking/rmake.rs
+++ b/tests/run-make/musl-default-linking/rmake.rs
@@ -4,7 +4,7 @@ use run_make_support::{rustc, serde_json};
 // Per https://github.com/rust-lang/compiler-team/issues/422,
 // we should be trying to move these targets to dynamically link
 // musl libc by default.
-//@ needs-llvm-components: aarch64 arm mips powerpc x86
+//@ needs-llvm-components: aarch64 arm powerpc x86
 static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[
     "aarch64-unknown-linux-musl",
     "arm-unknown-linux-musleabi",
@@ -14,7 +14,6 @@ static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[
     "armv7-unknown-linux-musleabihf",
     "i586-unknown-linux-musl",
     "i686-unknown-linux-musl",
-    "mips64el-unknown-linux-muslabi64",
     "powerpc64le-unknown-linux-musl",
     "x86_64-unknown-linux-musl",
 ];
diff --git a/tests/ui/asm/powerpc/bad-reg.aix64.stderr b/tests/ui/asm/powerpc/bad-reg.aix64.stderr
index 124013f89af..82faba8d167 100644
--- a/tests/ui/asm/powerpc/bad-reg.aix64.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.aix64.stderr
@@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `lr`: the link register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:48:18
-   |
-LL |         asm!("", out("lr") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:50:18
-   |
-LL |         asm!("", out("ctr") _);
-   |                  ^^^^^^^^^^^^
-
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:100:18
+  --> $DIR/bad-reg.rs:96:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:103:18
+  --> $DIR/bad-reg.rs:99:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:106:26
+  --> $DIR/bad-reg.rs:102:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:109:26
+  --> $DIR/bad-reg.rs:105:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:109:18
+   |
+LL |         asm!("", in("ctr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:112:18
+   |
+LL |         asm!("", out("ctr") x);
+   |                  ^^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:115:26
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                          ^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:118:26
+   |
+LL |         asm!("/* {} */", out(ctr) _);
+   |                          ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:122:18
+   |
+LL |         asm!("", in("lr") x);
+   |                  ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:125:18
+   |
+LL |         asm!("", out("lr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:128:26
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                          ^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:131:26
+   |
+LL |         asm!("/* {} */", out(lr) _);
+   |                          ^^^^^^^^^
+
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:113:18
+  --> $DIR/bad-reg.rs:135:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:116:18
+  --> $DIR/bad-reg.rs:138:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:119:26
+  --> $DIR/bad-reg.rs:141:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:122:26
+  --> $DIR/bad-reg.rs:144:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:126:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -103,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:128:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -111,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:130:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -119,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:132:31
+  --> $DIR/bad-reg.rs:154:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -127,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:134:31
+  --> $DIR/bad-reg.rs:156:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -135,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:136:31
+  --> $DIR/bad-reg.rs:158:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -143,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:138:31
+  --> $DIR/bad-reg.rs:160:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -151,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:140:31
+  --> $DIR/bad-reg.rs:162:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -165,7 +201,7 @@ LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:67:27
+  --> $DIR/bad-reg.rs:63:27
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                           ^
@@ -173,7 +209,7 @@ LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:70:28
+  --> $DIR/bad-reg.rs:66:28
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                            ^
@@ -181,7 +217,7 @@ LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:78:35
+  --> $DIR/bad-reg.rs:74:35
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                                   ^
@@ -189,7 +225,7 @@ LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:100:27
+  --> $DIR/bad-reg.rs:96:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -197,7 +233,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:103:28
+  --> $DIR/bad-reg.rs:99:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -205,7 +241,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:106:33
+  --> $DIR/bad-reg.rs:102:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -213,7 +249,55 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:113:28
+  --> $DIR/bad-reg.rs:109:28
+   |
+LL |         asm!("", in("ctr") x);
+   |                            ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:112:29
+   |
+LL |         asm!("", out("ctr") x);
+   |                             ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:115:34
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                                  ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:122:27
+   |
+LL |         asm!("", in("lr") x);
+   |                           ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:125:28
+   |
+LL |         asm!("", out("lr") x);
+   |                            ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:128:33
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                                 ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:135:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -221,7 +305,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:116:29
+  --> $DIR/bad-reg.rs:138:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -229,12 +313,12 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:119:34
+  --> $DIR/bad-reg.rs:141:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
    |
    = note: register class `xer` supports these types: 
 
-error: aborting due to 34 previous errors
+error: aborting due to 46 previous errors
 
diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr
index b11c946f80d..fac70ea77cb 100644
--- a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr
@@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `lr`: the link register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:48:18
-   |
-LL |         asm!("", out("lr") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:50:18
-   |
-LL |         asm!("", out("ctr") _);
-   |                  ^^^^^^^^^^^^
-
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:100:18
+  --> $DIR/bad-reg.rs:96:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:103:18
+  --> $DIR/bad-reg.rs:99:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:106:26
+  --> $DIR/bad-reg.rs:102:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:109:26
+  --> $DIR/bad-reg.rs:105:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:109:18
+   |
+LL |         asm!("", in("ctr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:112:18
+   |
+LL |         asm!("", out("ctr") x);
+   |                  ^^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:115:26
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                          ^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:118:26
+   |
+LL |         asm!("/* {} */", out(ctr) _);
+   |                          ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:122:18
+   |
+LL |         asm!("", in("lr") x);
+   |                  ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:125:18
+   |
+LL |         asm!("", out("lr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:128:26
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                          ^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:131:26
+   |
+LL |         asm!("/* {} */", out(lr) _);
+   |                          ^^^^^^^^^
+
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:113:18
+  --> $DIR/bad-reg.rs:135:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:116:18
+  --> $DIR/bad-reg.rs:138:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:119:26
+  --> $DIR/bad-reg.rs:141:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:122:26
+  --> $DIR/bad-reg.rs:144:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:126:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -103,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:128:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -111,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:130:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -119,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:132:31
+  --> $DIR/bad-reg.rs:154:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -127,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:134:31
+  --> $DIR/bad-reg.rs:156:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -135,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:136:31
+  --> $DIR/bad-reg.rs:158:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -143,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:138:31
+  --> $DIR/bad-reg.rs:160:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -151,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:140:31
+  --> $DIR/bad-reg.rs:162:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -165,67 +201,67 @@ LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:57:18
+  --> $DIR/bad-reg.rs:53:18
    |
 LL |         asm!("", in("v0") v32x4); // requires altivec
    |                  ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:59:18
+  --> $DIR/bad-reg.rs:55:18
    |
 LL |         asm!("", out("v0") v32x4); // requires altivec
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:61:18
+  --> $DIR/bad-reg.rs:57:18
    |
 LL |         asm!("", in("v0") v64x2); // requires vsx
    |                  ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:64:18
+  --> $DIR/bad-reg.rs:60:18
    |
 LL |         asm!("", out("v0") v64x2); // requires vsx
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:67:18
+  --> $DIR/bad-reg.rs:63:18
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                  ^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:70:18
+  --> $DIR/bad-reg.rs:66:18
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:73:26
+  --> $DIR/bad-reg.rs:69:26
    |
 LL |         asm!("/* {} */", in(vreg) v32x4); // requires altivec
    |                          ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:75:26
+  --> $DIR/bad-reg.rs:71:26
    |
 LL |         asm!("/* {} */", in(vreg) v64x2); // requires vsx
    |                          ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:78:26
+  --> $DIR/bad-reg.rs:74:26
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                          ^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:81:26
+  --> $DIR/bad-reg.rs:77:26
    |
 LL |         asm!("/* {} */", out(vreg) _); // requires altivec
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:100:27
+  --> $DIR/bad-reg.rs:96:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -233,7 +269,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:103:28
+  --> $DIR/bad-reg.rs:99:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -241,7 +277,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:106:33
+  --> $DIR/bad-reg.rs:102:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -249,7 +285,55 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:113:28
+  --> $DIR/bad-reg.rs:109:28
+   |
+LL |         asm!("", in("ctr") x);
+   |                            ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:112:29
+   |
+LL |         asm!("", out("ctr") x);
+   |                             ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:115:34
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                                  ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:122:27
+   |
+LL |         asm!("", in("lr") x);
+   |                           ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:125:28
+   |
+LL |         asm!("", out("lr") x);
+   |                            ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:128:33
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                                 ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:135:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -257,7 +341,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:116:29
+  --> $DIR/bad-reg.rs:138:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -265,12 +349,12 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:119:34
+  --> $DIR/bad-reg.rs:141:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
    |
    = note: register class `xer` supports these types: 
 
-error: aborting due to 41 previous errors
+error: aborting due to 53 previous errors
 
diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr
index a93b2b018df..42a59448f42 100644
--- a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr
@@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `lr`: the link register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:48:18
-   |
-LL |         asm!("", out("lr") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:50:18
-   |
-LL |         asm!("", out("ctr") _);
-   |                  ^^^^^^^^^^^^
-
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:100:18
+  --> $DIR/bad-reg.rs:96:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:103:18
+  --> $DIR/bad-reg.rs:99:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:106:26
+  --> $DIR/bad-reg.rs:102:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:109:26
+  --> $DIR/bad-reg.rs:105:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:109:18
+   |
+LL |         asm!("", in("ctr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:112:18
+   |
+LL |         asm!("", out("ctr") x);
+   |                  ^^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:115:26
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                          ^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:118:26
+   |
+LL |         asm!("/* {} */", out(ctr) _);
+   |                          ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:122:18
+   |
+LL |         asm!("", in("lr") x);
+   |                  ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:125:18
+   |
+LL |         asm!("", out("lr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:128:26
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                          ^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:131:26
+   |
+LL |         asm!("/* {} */", out(lr) _);
+   |                          ^^^^^^^^^
+
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:113:18
+  --> $DIR/bad-reg.rs:135:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:116:18
+  --> $DIR/bad-reg.rs:138:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:119:26
+  --> $DIR/bad-reg.rs:141:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:122:26
+  --> $DIR/bad-reg.rs:144:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:126:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -103,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:128:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -111,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:130:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -119,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:132:31
+  --> $DIR/bad-reg.rs:154:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -127,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:134:31
+  --> $DIR/bad-reg.rs:156:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -135,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:136:31
+  --> $DIR/bad-reg.rs:158:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -143,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:138:31
+  --> $DIR/bad-reg.rs:160:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -151,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:140:31
+  --> $DIR/bad-reg.rs:162:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -165,7 +201,7 @@ LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: `vsx` target feature is not enabled
-  --> $DIR/bad-reg.rs:61:27
+  --> $DIR/bad-reg.rs:57:27
    |
 LL |         asm!("", in("v0") v64x2); // requires vsx
    |                           ^^^^^
@@ -173,7 +209,7 @@ LL |         asm!("", in("v0") v64x2); // requires vsx
    = note: this is required to use type `i64x2` with register class `vreg`
 
 error: `vsx` target feature is not enabled
-  --> $DIR/bad-reg.rs:64:28
+  --> $DIR/bad-reg.rs:60:28
    |
 LL |         asm!("", out("v0") v64x2); // requires vsx
    |                            ^^^^^
@@ -181,7 +217,7 @@ LL |         asm!("", out("v0") v64x2); // requires vsx
    = note: this is required to use type `i64x2` with register class `vreg`
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:67:27
+  --> $DIR/bad-reg.rs:63:27
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                           ^
@@ -189,7 +225,7 @@ LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:70:28
+  --> $DIR/bad-reg.rs:66:28
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                            ^
@@ -197,7 +233,7 @@ LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: `vsx` target feature is not enabled
-  --> $DIR/bad-reg.rs:75:35
+  --> $DIR/bad-reg.rs:71:35
    |
 LL |         asm!("/* {} */", in(vreg) v64x2); // requires vsx
    |                                   ^^^^^
@@ -205,7 +241,7 @@ LL |         asm!("/* {} */", in(vreg) v64x2); // requires vsx
    = note: this is required to use type `i64x2` with register class `vreg`
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:78:35
+  --> $DIR/bad-reg.rs:74:35
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                                   ^
@@ -213,7 +249,7 @@ LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:100:27
+  --> $DIR/bad-reg.rs:96:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -221,7 +257,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:103:28
+  --> $DIR/bad-reg.rs:99:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -229,7 +265,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:106:33
+  --> $DIR/bad-reg.rs:102:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -237,7 +273,55 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:113:28
+  --> $DIR/bad-reg.rs:109:28
+   |
+LL |         asm!("", in("ctr") x);
+   |                            ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:112:29
+   |
+LL |         asm!("", out("ctr") x);
+   |                             ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:115:34
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                                  ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:122:27
+   |
+LL |         asm!("", in("lr") x);
+   |                           ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:125:28
+   |
+LL |         asm!("", out("lr") x);
+   |                            ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:128:33
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                                 ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:135:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -245,7 +329,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:116:29
+  --> $DIR/bad-reg.rs:138:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -253,12 +337,12 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:119:34
+  --> $DIR/bad-reg.rs:141:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
    |
    = note: register class `xer` supports these types: 
 
-error: aborting due to 37 previous errors
+error: aborting due to 49 previous errors
 
diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr
index 124013f89af..82faba8d167 100644
--- a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr
@@ -28,74 +28,110 @@ error: invalid register `fp`: the frame pointer cannot be used as an operand for
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `lr`: the link register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:48:18
-   |
-LL |         asm!("", out("lr") _);
-   |                  ^^^^^^^^^^^
-
-error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:50:18
-   |
-LL |         asm!("", out("ctr") _);
-   |                  ^^^^^^^^^^^^
-
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:100:18
+  --> $DIR/bad-reg.rs:96:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:103:18
+  --> $DIR/bad-reg.rs:99:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:106:26
+  --> $DIR/bad-reg.rs:102:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:109:26
+  --> $DIR/bad-reg.rs:105:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:109:18
+   |
+LL |         asm!("", in("ctr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:112:18
+   |
+LL |         asm!("", out("ctr") x);
+   |                  ^^^^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:115:26
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                          ^^^^^^^^^
+
+error: register class `ctr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:118:26
+   |
+LL |         asm!("/* {} */", out(ctr) _);
+   |                          ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:122:18
+   |
+LL |         asm!("", in("lr") x);
+   |                  ^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:125:18
+   |
+LL |         asm!("", out("lr") x);
+   |                  ^^^^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:128:26
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                          ^^^^^^^^
+
+error: register class `lr` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:131:26
+   |
+LL |         asm!("/* {} */", out(lr) _);
+   |                          ^^^^^^^^^
+
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:113:18
+  --> $DIR/bad-reg.rs:135:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:116:18
+  --> $DIR/bad-reg.rs:138:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:119:26
+  --> $DIR/bad-reg.rs:141:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:122:26
+  --> $DIR/bad-reg.rs:144:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:126:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -103,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:128:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -111,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:130:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -119,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:132:31
+  --> $DIR/bad-reg.rs:154:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -127,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:134:31
+  --> $DIR/bad-reg.rs:156:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -135,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:136:31
+  --> $DIR/bad-reg.rs:158:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -143,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:138:31
+  --> $DIR/bad-reg.rs:160:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -151,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:140:31
+  --> $DIR/bad-reg.rs:162:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -165,7 +201,7 @@ LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:67:27
+  --> $DIR/bad-reg.rs:63:27
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                           ^
@@ -173,7 +209,7 @@ LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:70:28
+  --> $DIR/bad-reg.rs:66:28
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                            ^
@@ -181,7 +217,7 @@ LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:78:35
+  --> $DIR/bad-reg.rs:74:35
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                                   ^
@@ -189,7 +225,7 @@ LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:100:27
+  --> $DIR/bad-reg.rs:96:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -197,7 +233,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:103:28
+  --> $DIR/bad-reg.rs:99:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -205,7 +241,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:106:33
+  --> $DIR/bad-reg.rs:102:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -213,7 +249,55 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:113:28
+  --> $DIR/bad-reg.rs:109:28
+   |
+LL |         asm!("", in("ctr") x);
+   |                            ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:112:29
+   |
+LL |         asm!("", out("ctr") x);
+   |                             ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:115:34
+   |
+LL |         asm!("/* {} */", in(ctr) x);
+   |                                  ^
+   |
+   = note: register class `ctr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:122:27
+   |
+LL |         asm!("", in("lr") x);
+   |                           ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:125:28
+   |
+LL |         asm!("", out("lr") x);
+   |                            ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:128:33
+   |
+LL |         asm!("/* {} */", in(lr) x);
+   |                                 ^
+   |
+   = note: register class `lr` supports these types: 
+
+error: type `i32` cannot be used with this register class
+  --> $DIR/bad-reg.rs:135:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -221,7 +305,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:116:29
+  --> $DIR/bad-reg.rs:138:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -229,12 +313,12 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:119:34
+  --> $DIR/bad-reg.rs:141:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
    |
    = note: register class `xer` supports these types: 
 
-error: aborting due to 34 previous errors
+error: aborting due to 46 previous errors
 
diff --git a/tests/ui/asm/powerpc/bad-reg.rs b/tests/ui/asm/powerpc/bad-reg.rs
index 5598f837960..21ea451934e 100644
--- a/tests/ui/asm/powerpc/bad-reg.rs
+++ b/tests/ui/asm/powerpc/bad-reg.rs
@@ -45,10 +45,6 @@ fn f() {
         //~^ ERROR invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm
         asm!("", out("fp") _);
         //~^ ERROR invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-        asm!("", out("lr") _);
-        //~^ ERROR invalid register `lr`: the link register cannot be used as an operand for inline asm
-        asm!("", out("ctr") _);
-        //~^ ERROR invalid register `ctr`: the counter register cannot be used as an operand for inline asm
         asm!("", out("vrsave") _);
         //~^ ERROR invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
 
@@ -108,6 +104,32 @@ fn f() {
         //~| ERROR type `i32` cannot be used with this register class
         asm!("/* {} */", out(cr) _);
         //~^ ERROR can only be used as a clobber
+        // ctr
+        asm!("", out("ctr") _); // ok
+        asm!("", in("ctr") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("", out("ctr") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("/* {} */", in(ctr) x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("/* {} */", out(ctr) _);
+        //~^ ERROR can only be used as a clobber
+        // lr
+        asm!("", out("lr") _); // ok
+        asm!("", in("lr") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("", out("lr") x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("/* {} */", in(lr) x);
+        //~^ ERROR can only be used as a clobber
+        //~| ERROR type `i32` cannot be used with this register class
+        asm!("/* {} */", out(lr) _);
+        //~^ ERROR can only be used as a clobber
         // xer
         asm!("", out("xer") _); // ok
         asm!("", in("xer") x);