From d561a84d48b64dc0f23e0f0a152b72e5a8f62161 Mon Sep 17 00:00:00 2001 From: Veera Date: Sun, 3 Mar 2024 09:10:06 -0500 Subject: [PATCH 01/13] Update tests --- tests/ui/asm/bad-template.aarch64.stderr | 4 ++-- tests/ui/asm/bad-template.x86_64.stderr | 4 ++-- tests/ui/asm/x86_64/type-check-3.stderr | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/ui/asm/bad-template.aarch64.stderr b/tests/ui/asm/bad-template.aarch64.stderr index b18946d7c6d85..5023cf317d7b0 100644 --- a/tests/ui/asm/bad-template.aarch64.stderr +++ b/tests/ui/asm/bad-template.aarch64.stderr @@ -194,8 +194,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{:foo}", in(reg) foo); | ^^^^^^ --- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` - = help: or use `{0:x}` to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) = note: `#[warn(asm_sub_register)]` on by default error: aborting due to 21 previous errors; 1 warning emitted diff --git a/tests/ui/asm/bad-template.x86_64.stderr b/tests/ui/asm/bad-template.x86_64.stderr index 2f584c30a3282..1b9775636f564 100644 --- a/tests/ui/asm/bad-template.x86_64.stderr +++ b/tests/ui/asm/bad-template.x86_64.stderr @@ -194,8 +194,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{:foo}", in(reg) foo); | ^^^^^^ --- for this argument | - = help: use `{0:e}` to have the register formatted as `eax` - = help: or use `{0:r}` to keep the default formatting of `rax` + = help: use `{0:e}` to have the register formatted as `eax` (for 32-bit values) + = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values) = note: `#[warn(asm_sub_register)]` on by default error: aborting due to 21 previous errors; 1 warning emitted diff --git a/tests/ui/asm/x86_64/type-check-3.stderr b/tests/ui/asm/x86_64/type-check-3.stderr index 1baf50ff6e0c7..34bfcd71caca7 100644 --- a/tests/ui/asm/x86_64/type-check-3.stderr +++ b/tests/ui/asm/x86_64/type-check-3.stderr @@ -44,8 +44,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{0} {0}", in(reg) 0i16); | ^^^ ^^^ ---- for this argument | - = help: use `{0:x}` to have the register formatted as `ax` - = help: or use `{0:r}` to keep the default formatting of `rax` + = help: use `{0:x}` to have the register formatted as `ax` (for 16-bit values) + = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values) = note: `#[warn(asm_sub_register)]` on by default warning: formatting may not be suitable for sub-register argument @@ -54,8 +54,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{0} {0:x}", in(reg) 0i16); | ^^^ ---- for this argument | - = help: use `{0:x}` to have the register formatted as `ax` - = help: or use `{0:r}` to keep the default formatting of `rax` + = help: use `{0:x}` to have the register formatted as `ax` (for 16-bit values) + = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:38:15 @@ -63,8 +63,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(reg) 0i32); | ^^ ---- for this argument | - = help: use `{0:e}` to have the register formatted as `eax` - = help: or use `{0:r}` to keep the default formatting of `rax` + = help: use `{0:e}` to have the register formatted as `eax` (for 32-bit values) + = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:41:15 @@ -72,8 +72,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(ymm_reg) 0i64); | ^^ ---- for this argument | - = help: use `{0:x}` to have the register formatted as `xmm0` - = help: or use `{0:y}` to keep the default formatting of `ymm0` + = help: use `{0:x}` to have the register formatted as `xmm0` (for 128-bit values) + = help: or use `{0:y}` to keep the default formatting of `ymm0` (for 256-bit values) error: type `i8` cannot be used with this register class --> $DIR/type-check-3.rs:52:28 From 9aac0c9ae39de7046af35788d19e5f9310e4cbb7 Mon Sep 17 00:00:00 2001 From: Veera Date: Sun, 3 Mar 2024 09:34:26 -0500 Subject: [PATCH 02/13] Mention Register Size in `#[warn(asm_sub_register)]` Fixes #121593 --- .../src/check/intrinsicck.rs | 22 ++++++++---- compiler/rustc_target/src/asm/aarch64.rs | 26 ++++++-------- compiler/rustc_target/src/asm/arm.rs | 6 ++-- compiler/rustc_target/src/asm/avr.rs | 6 ++-- compiler/rustc_target/src/asm/bpf.rs | 6 ++-- compiler/rustc_target/src/asm/csky.rs | 6 ++-- compiler/rustc_target/src/asm/hexagon.rs | 6 ++-- compiler/rustc_target/src/asm/loongarch.rs | 6 ++-- compiler/rustc_target/src/asm/m68k.rs | 6 ++-- compiler/rustc_target/src/asm/mips.rs | 6 ++-- compiler/rustc_target/src/asm/mod.rs | 20 +++++++---- compiler/rustc_target/src/asm/msp430.rs | 6 ++-- compiler/rustc_target/src/asm/nvptx.rs | 6 ++-- compiler/rustc_target/src/asm/powerpc.rs | 6 ++-- compiler/rustc_target/src/asm/riscv.rs | 6 ++-- compiler/rustc_target/src/asm/s390x.rs | 6 ++-- compiler/rustc_target/src/asm/spirv.rs | 6 ++-- compiler/rustc_target/src/asm/wasm.rs | 6 ++-- compiler/rustc_target/src/asm/x86.rs | 34 ++++++++----------- 19 files changed, 100 insertions(+), 92 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index d03b02f028da1..c78a6004f7ac2 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -6,7 +6,9 @@ use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::Symbol; use rustc_target::abi::FieldIdx; -use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType}; +use rustc_target::asm::{ + InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo, +}; pub struct InlineAsmCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -253,8 +255,11 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } // Check whether a modifier is suggested for using this type. - if let Some((suggested_modifier, suggested_result)) = - reg_class.suggest_modifier(asm_arch, asm_ty) + if let Some(ModifierInfo { + modifier: suggested_modifier, + result: suggested_result, + size: suggested_size, + }) = reg_class.suggest_modifier(asm_arch, asm_ty) { // Search for any use of this operand without a modifier and emit // the suggestion for them. @@ -268,8 +273,11 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } } if !spans.is_empty() { - let (default_modifier, default_result) = - reg_class.default_modifier(asm_arch).unwrap(); + let ModifierInfo { + modifier: default_modifier, + result: default_result, + size: default_size, + } = reg_class.default_modifier(asm_arch).unwrap(); self.tcx.node_span_lint( lint::builtin::ASM_SUB_REGISTER, expr.hir_id, @@ -278,10 +286,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { |lint| { lint.span_label(expr.span, "for this argument"); lint.help(format!( - "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`", + "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}` (for {suggested_size}-bit values)", )); lint.help(format!( - "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`", + "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}` (for {default_size}-bit values)", )); }, ); diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index 97132311a5c9a..70528c1222c44 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use crate::spec::{RelocModel, Target}; use rustc_data_structures::fx::FxIndexSet; use rustc_macros::HashStable_Generic; @@ -27,32 +27,28 @@ impl AArch64InlineAsmRegClass { None } - pub fn suggest_modifier( - self, - _arch: InlineAsmArch, - ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + pub fn suggest_modifier(self, _arch: InlineAsmArch, ty: InlineAsmType) -> Option { match self { Self::reg => match ty.size().bits() { 64 => None, - _ => Some(('w', "w0")), + _ => Some(('w', "w0", 32).into()), }, Self::vreg | Self::vreg_low16 => match ty.size().bits() { - 8 => Some(('b', "b0")), - 16 => Some(('h', "h0")), - 32 => Some(('s', "s0")), - 64 => Some(('d', "d0")), - 128 => Some(('q', "q0")), + 8 => Some(('b', "b0", 8).into()), + 16 => Some(('h', "h0", 16).into()), + 32 => Some(('s', "s0", 32).into()), + 64 => Some(('d', "d0", 64).into()), + 128 => Some(('q', "q0", 128).into()), _ => None, }, Self::preg => None, } } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { match self { - Self::reg => Some(('x', "x0")), - Self::vreg | Self::vreg_low16 => Some(('v', "v0")), + Self::reg => Some(('x', "x0", 64).into()), + Self::vreg | Self::vreg_low16 => Some(('v', "v0", 128).into()), Self::preg => None, } } diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs index 514e30ae0204d..f56dbac708b65 100644 --- a/compiler/rustc_target/src/asm/arm.rs +++ b/compiler/rustc_target/src/asm/arm.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use crate::spec::{RelocModel, Target}; use rustc_data_structures::fx::FxIndexSet; use rustc_macros::HashStable_Generic; @@ -35,11 +35,11 @@ impl ArmInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/avr.rs b/compiler/rustc_target/src/asm/avr.rs index 9a96a61f5b2cd..eab38a4a4f4a3 100644 --- a/compiler/rustc_target/src/asm/avr.rs +++ b/compiler/rustc_target/src/asm/avr.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -29,11 +29,11 @@ impl AvrInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs index 3b03766a089b2..9bc94274675d5 100644 --- a/compiler/rustc_target/src/asm/bpf.rs +++ b/compiler/rustc_target/src/asm/bpf.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -23,11 +23,11 @@ impl BpfInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/csky.rs b/compiler/rustc_target/src/asm/csky.rs index db3d8106040b6..64607ee4b81db 100644 --- a/compiler/rustc_target/src/asm/csky.rs +++ b/compiler/rustc_target/src/asm/csky.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -23,11 +23,11 @@ impl CSKYInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs index d20270ac9e95a..19da7b8084853 100644 --- a/compiler/rustc_target/src/asm/hexagon.rs +++ b/compiler/rustc_target/src/asm/hexagon.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -22,11 +22,11 @@ impl HexagonInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs index 9d1a4f3eeeafa..15d0f54ce3b6e 100644 --- a/compiler/rustc_target/src/asm/loongarch.rs +++ b/compiler/rustc_target/src/asm/loongarch.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -23,11 +23,11 @@ impl LoongArchInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/m68k.rs b/compiler/rustc_target/src/asm/m68k.rs index 8c857550cf21a..ac94dcc03dc6b 100644 --- a/compiler/rustc_target/src/asm/m68k.rs +++ b/compiler/rustc_target/src/asm/m68k.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -24,11 +24,11 @@ impl M68kInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs index 4e7c2eb1bf88e..0ac1a43ae183b 100644 --- a/compiler/rustc_target/src/asm/mips.rs +++ b/compiler/rustc_target/src/asm/mips.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -23,11 +23,11 @@ impl MipsInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index a11884bea268f..bfb6ae0b2d9d2 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -6,6 +6,18 @@ use rustc_span::Symbol; use std::fmt; use std::str::FromStr; +pub struct ModifierInfo { + pub modifier: char, + pub result: &'static str, + pub size: u64, +} + +impl From<(char, &'static str, u64)> for ModifierInfo { + fn from(value: (char, &'static str, u64)) -> Self { + Self { modifier: value.0, result: value.1, size: value.2 } + } +} + macro_rules! def_reg_class { ($arch:ident $arch_regclass:ident { $( @@ -512,11 +524,7 @@ impl InlineAsmRegClass { /// Such suggestions are useful if a type smaller than the full register /// size is used and a modifier can be used to point to the subregister of /// the correct size. - pub fn suggest_modifier( - self, - arch: InlineAsmArch, - ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + pub fn suggest_modifier(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option { match self { Self::X86(r) => r.suggest_modifier(arch, ty), Self::Arm(r) => r.suggest_modifier(arch, ty), @@ -545,7 +553,7 @@ impl InlineAsmRegClass { /// This is only needed when the register class can suggest a modifier, so /// that the user can be shown how to get the default behavior without a /// warning. - pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, arch: InlineAsmArch) -> Option { match self { Self::X86(r) => r.default_modifier(arch), Self::Arm(r) => r.default_modifier(arch), diff --git a/compiler/rustc_target/src/asm/msp430.rs b/compiler/rustc_target/src/asm/msp430.rs index a27d6390a72e8..439f3ba0b575b 100644 --- a/compiler/rustc_target/src/asm/msp430.rs +++ b/compiler/rustc_target/src/asm/msp430.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -22,11 +22,11 @@ impl Msp430InlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/nvptx.rs b/compiler/rustc_target/src/asm/nvptx.rs index 8e1e91e7c5f1f..57aa50fceb88b 100644 --- a/compiler/rustc_target/src/asm/nvptx.rs +++ b/compiler/rustc_target/src/asm/nvptx.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; @@ -23,11 +23,11 @@ impl NvptxInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index d3ccb30350a27..4e8cbe34de948 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -26,11 +26,11 @@ impl PowerPCInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs index dea6d50fe2ba8..2505d36f5b8a4 100644 --- a/compiler/rustc_target/src/asm/riscv.rs +++ b/compiler/rustc_target/src/asm/riscv.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use crate::spec::{RelocModel, Target}; use rustc_data_structures::fx::FxIndexSet; use rustc_macros::HashStable_Generic; @@ -26,11 +26,11 @@ impl RiscVInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs index b8afeb824d847..6bc668454b191 100644 --- a/compiler/rustc_target/src/asm/s390x.rs +++ b/compiler/rustc_target/src/asm/s390x.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use std::fmt; @@ -24,11 +24,11 @@ impl S390xInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/spirv.rs b/compiler/rustc_target/src/asm/spirv.rs index 31073da10b21b..d13a6131f9ab4 100644 --- a/compiler/rustc_target/src/asm/spirv.rs +++ b/compiler/rustc_target/src/asm/spirv.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; @@ -21,11 +21,11 @@ impl SpirVInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/wasm.rs b/compiler/rustc_target/src/asm/wasm.rs index f095b7c6e118c..eb0b23ef43dd8 100644 --- a/compiler/rustc_target/src/asm/wasm.rs +++ b/compiler/rustc_target/src/asm/wasm.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; @@ -21,11 +21,11 @@ impl WasmInlineAsmRegClass { self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + ) -> Option { None } - pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option { None } diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index 3902dac7ff654..3b5da8806ccc2 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -1,4 +1,4 @@ -use super::{InlineAsmArch, InlineAsmType}; +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; use crate::spec::{RelocModel, Target}; use rustc_data_structures::fx::FxIndexSet; use rustc_macros::HashStable_Generic; @@ -53,32 +53,28 @@ impl X86InlineAsmRegClass { } } - pub fn suggest_modifier( - self, - arch: InlineAsmArch, - ty: InlineAsmType, - ) -> Option<(char, &'static str)> { + pub fn suggest_modifier(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option { match self { Self::reg => match ty.size().bits() { - 16 => Some(('x', "ax")), - 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")), + 16 => Some(('x', "ax", 16).into()), + 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", 32).into()), _ => None, }, Self::reg_abcd => match ty.size().bits() { - 16 => Some(('x', "ax")), - 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")), + 16 => Some(('x', "ax", 16).into()), + 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", 32).into()), _ => None, }, Self::reg_byte => None, Self::xmm_reg => None, Self::ymm_reg => match ty.size().bits() { 256 => None, - _ => Some(('x', "xmm0")), + _ => Some(('x', "xmm0", 128).into()), }, Self::zmm_reg => match ty.size().bits() { 512 => None, - 256 => Some(('y', "ymm0")), - _ => Some(('x', "xmm0")), + 256 => Some(('y', "ymm0", 256).into()), + _ => Some(('x', "xmm0", 128).into()), }, Self::kreg | Self::kreg0 => None, Self::mmx_reg | Self::x87_reg => None, @@ -86,19 +82,19 @@ impl X86InlineAsmRegClass { } } - pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> { + pub fn default_modifier(self, arch: InlineAsmArch) -> Option { match self { Self::reg | Self::reg_abcd => { if arch == InlineAsmArch::X86_64 { - Some(('r', "rax")) + Some(('r', "rax", 64).into()) } else { - Some(('e', "eax")) + Some(('e', "eax", 32).into()) } } Self::reg_byte => None, - Self::xmm_reg => Some(('x', "xmm0")), - Self::ymm_reg => Some(('y', "ymm0")), - Self::zmm_reg => Some(('z', "zmm0")), + Self::xmm_reg => Some(('x', "xmm0", 128).into()), + Self::ymm_reg => Some(('y', "ymm0", 256).into()), + Self::zmm_reg => Some(('z', "zmm0", 512).into()), Self::kreg | Self::kreg0 => None, Self::mmx_reg | Self::x87_reg => None, Self::tmm_reg => None, From 1bde8281415034fd76a031c5e939251ff12ea60f Mon Sep 17 00:00:00 2001 From: Veera Date: Wed, 13 Mar 2024 19:20:49 -0400 Subject: [PATCH 03/13] Improve style --- compiler/rustc_target/src/asm/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index bfb6ae0b2d9d2..2e04dca98c57b 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -13,8 +13,8 @@ pub struct ModifierInfo { } impl From<(char, &'static str, u64)> for ModifierInfo { - fn from(value: (char, &'static str, u64)) -> Self { - Self { modifier: value.0, result: value.1, size: value.2 } + fn from((modifier, result, size): (char, &'static str, u64)) -> Self { + Self { modifier, result, size } } } From a2497a96792b9fc97c93312b363174aba8f4dcc9 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sat, 27 Jan 2024 16:47:09 +0530 Subject: [PATCH 04/13] Expand sys/os for UEFI - Implement current_exe() - Cache device_path_to_text protocol Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/helpers.rs | 83 ++++++++++++++++++++++--- library/std/src/sys/pal/uefi/os.rs | 8 ++- 2 files changed, 81 insertions(+), 10 deletions(-) diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 9837cc89f2d39..a960e1c10d2fd 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -10,14 +10,16 @@ //! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles) use r_efi::efi::{self, Guid}; +use r_efi::protocols::{device_path, device_path_to_text}; +use crate::ffi::OsString; +use crate::io::{self, const_io_error}; use crate::mem::{size_of, MaybeUninit}; -use crate::os::uefi; +use crate::os::uefi::{self, env::boot_services, ffi::OsStringExt}; use crate::ptr::NonNull; -use crate::{ - io::{self, const_io_error}, - os::uefi::env::boot_services, -}; +use crate::slice; +use crate::sync::atomic::{AtomicPtr, Ordering}; +use crate::sys_common::wstr::WStrUnits; const BOOT_SERVICES_UNAVAILABLE: io::Error = const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available"); @@ -142,7 +144,72 @@ pub(crate) unsafe fn close_event(evt: NonNull) -> io::Result /// Get the Protocol for current system handle. /// Note: Some protocols need to be manually freed. It is the callers responsibility to do so. -pub(crate) fn image_handle_protocol(protocol_guid: Guid) -> Option> { - let system_handle = uefi::env::try_image_handle()?; - open_protocol(system_handle, protocol_guid).ok() +pub(crate) fn image_handle_protocol(protocol_guid: Guid) -> io::Result> { + let system_handle = uefi::env::try_image_handle().ok_or(io::const_io_error!( + io::ErrorKind::NotFound, + "Protocol not found in Image handle" + ))?; + open_protocol(system_handle, protocol_guid) +} + +pub(crate) fn device_path_to_text(path: NonNull) -> io::Result { + fn path_to_text( + protocol: NonNull, + path: NonNull, + ) -> io::Result { + let path_ptr: *mut r_efi::efi::Char16 = unsafe { + ((*protocol.as_ptr()).convert_device_path_to_text)( + path.as_ptr(), + // DisplayOnly + r_efi::efi::Boolean::FALSE, + // AllowShortcuts + r_efi::efi::Boolean::FALSE, + ) + }; + + // SAFETY: `convert_device_path_to_text` returns a pointer to a null-terminated UTF-16 + // string, and that string cannot be deallocated prior to dropping the `WStrUnits`, so + // it's safe for `WStrUnits` to use. + let path_len = unsafe { + WStrUnits::new(path_ptr) + .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))? + .count() + }; + + let path = OsString::from_wide(unsafe { slice::from_raw_parts(path_ptr.cast(), path_len) }); + + if let Some(boot_services) = crate::os::uefi::env::boot_services() { + let boot_services: NonNull = boot_services.cast(); + unsafe { + ((*boot_services.as_ptr()).free_pool)(path_ptr.cast()); + } + } + + Ok(path) + } + + static LAST_VALID_HANDLE: AtomicPtr = + AtomicPtr::new(crate::ptr::null_mut()); + + if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) { + if let Ok(protocol) = open_protocol::( + handle, + device_path_to_text::PROTOCOL_GUID, + ) { + return path_to_text(protocol, path); + } + } + + let device_path_to_text_handles = locate_handles(device_path_to_text::PROTOCOL_GUID)?; + for handle in device_path_to_text_handles { + if let Ok(protocol) = open_protocol::( + handle, + device_path_to_text::PROTOCOL_GUID, + ) { + LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release); + return path_to_text(protocol, path); + } + } + + Err(io::const_io_error!(io::ErrorKind::NotFound, "No device path to text protocol found")) } diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index e6693db68e641..58838c5876ebd 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -1,4 +1,4 @@ -use super::{unsupported, RawOsError}; +use super::{helpers, unsupported, RawOsError}; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::fmt; @@ -7,6 +7,7 @@ use crate::marker::PhantomData; use crate::os::uefi; use crate::path::{self, PathBuf}; use crate::ptr::NonNull; +use r_efi::efi::protocols::{device_path, loaded_image_device_path}; use r_efi::efi::Status; pub fn errno() -> RawOsError { @@ -164,7 +165,10 @@ impl fmt::Display for JoinPathsError { impl StdError for JoinPathsError {} pub fn current_exe() -> io::Result { - unsupported() + let protocol = helpers::image_handle_protocol::( + loaded_image_device_path::PROTOCOL_GUID, + )?; + helpers::device_path_to_text(protocol).map(PathBuf::from) } pub struct Env(!); From 0d5a3f464ff6cb5868fba0e7ca46e9e917c41ea6 Mon Sep 17 00:00:00 2001 From: RoboSchmied Date: Wed, 20 Mar 2024 04:41:32 +0100 Subject: [PATCH 05/13] Update target.rs alloc.rs event.rs simd.rs fix typos --- compiler/stable_mir/src/mir/alloc.rs | 4 ++-- compiler/stable_mir/src/target.rs | 2 +- library/core/src/intrinsics/simd.rs | 2 +- src/tools/miri/src/shims/intrinsics/simd.rs | 4 ++-- src/tools/miri/src/shims/unix/linux/fd/event.rs | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs index c780042ff261c..535808aa0ad39 100644 --- a/compiler/stable_mir/src/mir/alloc.rs +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -55,7 +55,7 @@ impl IndexedVal for AllocId { /// Utility function used to read an allocation data into a unassigned integer. pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result { let mut buf = [0u8; std::mem::size_of::()]; - match MachineInfo::target_endianess() { + match MachineInfo::target_endianness() { Endian::Little => { bytes.read(&mut buf)?; Ok(u128::from_le_bytes(buf)) @@ -70,7 +70,7 @@ pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result { /// Utility function used to read an allocation data into an assigned integer. pub(crate) fn read_target_int(mut bytes: &[u8]) -> Result { let mut buf = [0u8; std::mem::size_of::()]; - match MachineInfo::target_endianess() { + match MachineInfo::target_endianness() { Endian::Little => { bytes.read(&mut buf)?; Ok(i128::from_le_bytes(buf)) diff --git a/compiler/stable_mir/src/target.rs b/compiler/stable_mir/src/target.rs index 3a9011a2ffe15..e00a418c54039 100644 --- a/compiler/stable_mir/src/target.rs +++ b/compiler/stable_mir/src/target.rs @@ -14,7 +14,7 @@ impl MachineInfo { with(|cx| cx.target_info()) } - pub fn target_endianess() -> Endian { + pub fn target_endianness() -> Endian { with(|cx| cx.target_info().endian) } diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 2eaca3b6fe4d5..1586481b3c97e 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -474,7 +474,7 @@ extern $abi { /// No matter whether the output is an array or an unsigned integer, it is treated as a single /// contiguous list of bits. The bitmask is always packed on the least-significant side of the /// output, and padded with 0s in the most-significant bits. The order of the bits depends on - /// endianess: + /// endianness: /// /// * On little endian, the least significant bit corresponds to the first vector element. /// * On big endian, the least significant bit corresponds to the last vector element. diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index c97a052f51715..aa05414ab7989 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -427,7 +427,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let bitmask_len = u32::try_from(bitmask_len).unwrap(); // To read the mask, we transmute it to an integer. - // That does the right thing wrt endianess. + // That does the right thing wrt endianness. let mask_ty = this.machine.layouts.uint(mask.layout.size).unwrap(); let mask = mask.transmute(mask_ty, this)?; let mask: u64 = this.read_scalar(&mask)?.to_bits(mask_ty.size)?.try_into().unwrap(); @@ -479,7 +479,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } // We have to change the type of the place to be able to write `res` into it. This - // transmutes the integer to an array, which does the right thing wrt endianess. + // transmutes the integer to an array, which does the right thing wrt endianness. let dest = dest.transmute(this.machine.layouts.uint(dest.layout.size).unwrap(), this)?; this.write_int(res, &dest)?; diff --git a/src/tools/miri/src/shims/unix/linux/fd/event.rs b/src/tools/miri/src/shims/unix/linux/fd/event.rs index 1f17ffb88c886..49408fda3ae31 100644 --- a/src/tools/miri/src/shims/unix/linux/fd/event.rs +++ b/src/tools/miri/src/shims/unix/linux/fd/event.rs @@ -38,7 +38,7 @@ impl FileDescriptor for Event { } /// A write call adds the 8-byte integer value supplied in - /// its buffer (in native endianess) to the counter. The maximum value that may be + /// its buffer (in native endianness) to the counter. The maximum value that may be /// stored in the counter is the largest unsigned 64-bit value /// minus 1 (i.e., 0xfffffffffffffffe). If the addition would /// cause the counter's value to exceed the maximum, then the @@ -57,7 +57,7 @@ impl FileDescriptor for Event { ) -> InterpResult<'tcx, io::Result> { let v1 = self.val.get(); let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size - // Convert from target endianess to host endianess. + // Convert from target endianness to host endianness. let num = match tcx.sess.target.endian { Endian::Little => u64::from_le_bytes(bytes), Endian::Big => u64::from_be_bytes(bytes), From 2758435a8ed8f339d1f8a72a2676d13a3960544c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 20 Mar 2024 14:54:20 -0700 Subject: [PATCH 06/13] Fix compile of wasm64-unknown-unknown target This target is a Tier 3 target so it's not tested on CI, and it's broken since last used so this commit fixes a small unwind-related issue that cropped up in the meantime. --- library/unwind/src/lib.rs | 1 + library/unwind/src/wasm.rs | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 25bb5938b4cce..51d31a00afe91 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -4,6 +4,7 @@ #![feature(staged_api)] #![feature(c_unwind)] #![feature(strict_provenance)] +#![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))] #![cfg_attr(not(target_env = "msvc"), feature(libc))] #![cfg_attr( all(target_family = "wasm", not(target_os = "emscripten")), diff --git a/library/unwind/src/wasm.rs b/library/unwind/src/wasm.rs index b06671bcb8309..f4ffac1ba16da 100644 --- a/library/unwind/src/wasm.rs +++ b/library/unwind/src/wasm.rs @@ -59,7 +59,10 @@ pub unsafe fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwi wasm_throw(0, exception.cast()) } else { let _ = exception; - core::arch::wasm32::unreachable() + #[cfg(target_arch = "wasm32")] + core::arch::wasm32::unreachable(); + #[cfg(target_arch = "wasm64")] + core::arch::wasm64::unreachable(); } } } From afc99cc976268885da8aa0457a707306c780c6c6 Mon Sep 17 00:00:00 2001 From: Veera Date: Wed, 20 Mar 2024 19:38:36 -0400 Subject: [PATCH 07/13] Update test for `aarch64` --- tests/ui/asm/aarch64/type-check-3.stderr | 40 ++++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/ui/asm/aarch64/type-check-3.stderr b/tests/ui/asm/aarch64/type-check-3.stderr index f710df2dcde96..9e37bb4c203f5 100644 --- a/tests/ui/asm/aarch64/type-check-3.stderr +++ b/tests/ui/asm/aarch64/type-check-3.stderr @@ -4,8 +4,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(reg) 0u8); | ^^ --- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` - = help: or use `{0:x}` to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) = note: `#[warn(asm_sub_register)]` on by default warning: formatting may not be suitable for sub-register argument @@ -14,8 +14,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(reg) 0u16); | ^^ ---- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` - = help: or use `{0:x}` to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:52:15 @@ -23,8 +23,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(reg) 0i32); | ^^ ---- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` - = help: or use `{0:x}` to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:54:15 @@ -32,8 +32,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(reg) 0f32); | ^^ ---- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` - = help: or use `{0:x}` to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:57:15 @@ -41,8 +41,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(vreg) 0i16); | ^^ ---- for this argument | - = help: use `{0:h}` to have the register formatted as `h0` - = help: or use `{0:v}` to keep the default formatting of `v0` + = help: use `{0:h}` to have the register formatted as `h0` (for 16-bit values) + = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:59:15 @@ -50,8 +50,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(vreg) 0f32); | ^^ ---- for this argument | - = help: use `{0:s}` to have the register formatted as `s0` - = help: or use `{0:v}` to keep the default formatting of `v0` + = help: use `{0:s}` to have the register formatted as `s0` (for 32-bit values) + = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:61:15 @@ -59,8 +59,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(vreg) 0f64); | ^^ ---- for this argument | - = help: use `{0:d}` to have the register formatted as `d0` - = help: or use `{0:v}` to keep the default formatting of `v0` + = help: use `{0:d}` to have the register formatted as `d0` (for 64-bit values) + = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:63:15 @@ -68,8 +68,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(vreg_low16) 0f64); | ^^ ---- for this argument | - = help: use `{0:d}` to have the register formatted as `d0` - = help: or use `{0:v}` to keep the default formatting of `v0` + = help: use `{0:d}` to have the register formatted as `d0` (for 64-bit values) + = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:66:15 @@ -77,8 +77,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{0} {0}", in(reg) 0i16); | ^^^ ^^^ ---- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` - = help: or use `{0:x}` to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:68:15 @@ -86,8 +86,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{0} {0:x}", in(reg) 0i16); | ^^^ ---- for this argument | - = help: use `{0:w}` to have the register formatted as `w0` - = help: or use `{0:x}` to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values) + = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values) error: type `i128` cannot be used with this register class --> $DIR/type-check-3.rs:73:28 From dec36c3d6eca67c900b7bdf03bd8d9dd68c4aa34 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Sun, 3 Mar 2024 03:51:05 +0000 Subject: [PATCH 08/13] CFI: Support self_cell-like recursion Current `transform_ty` attempts to avoid cycles when normalizing `#[repr(transparent)]` types to their interior, but runs afoul of this pattern used in `self_cell`: ``` struct X { x: u8, p: PhantomData, } #[repr(transparent)] struct Y(X); ``` When attempting to normalize Y, it will still cycle indefinitely. By using a types-visited list, this will instead get expanded exactly one layer deep to X, and then stop, not attempting to normalize `Y` any further. --- .../src/typeid/typeid_itanium_cxx_abi.rs | 70 ++++++++++++------- ...-itanium-cxx-abi-repr-transparent-types.rs | 16 +++++ tests/ui/sanitizer/cfi-self-ref.rs | 33 +++++++++ 3 files changed, 94 insertions(+), 25 deletions(-) create mode 100644 tests/ui/sanitizer/cfi-self-ref.rs diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 07a382d161d74..dbd3c3b1f288b 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -178,14 +178,14 @@ fn encode_fnsig<'tcx>( // Encode the return type let transform_ty_options = TransformTyOptions::from_bits(options.bits()) .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits())); - let ty = transform_ty(tcx, fn_sig.output(), transform_ty_options); + let ty = transform_ty(tcx, fn_sig.output(), &mut Vec::new(), transform_ty_options); s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options)); // Encode the parameter types let tys = fn_sig.inputs(); if !tys.is_empty() { for ty in tys { - let ty = transform_ty(tcx, *ty, transform_ty_options); + let ty = transform_ty(tcx, *ty, &mut Vec::new(), transform_ty_options); s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options)); } @@ -767,11 +767,12 @@ fn transform_predicates<'tcx>( fn transform_args<'tcx>( tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, + parents: &mut Vec>, options: TransformTyOptions, ) -> GenericArgsRef<'tcx> { let args = args.iter().map(|arg| match arg.unpack() { GenericArgKind::Type(ty) if ty.is_c_void(tcx) => Ty::new_unit(tcx).into(), - GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(), + GenericArgKind::Type(ty) => transform_ty(tcx, ty, parents, options).into(), _ => arg, }); tcx.mk_args_from_iter(args) @@ -781,9 +782,12 @@ fn transform_args<'tcx>( // c_void types into unit types unconditionally, generalizes pointers if // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if // TransformTyOptions::NORMALIZE_INTEGERS option is set. -fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> { - let mut ty = ty; - +fn transform_ty<'tcx>( + tcx: TyCtxt<'tcx>, + mut ty: Ty<'tcx>, + parents: &mut Vec>, + options: TransformTyOptions, +) -> Ty<'tcx> { match ty.kind() { ty::Float(..) | ty::Str | ty::Never | ty::Foreign(..) | ty::CoroutineWitness(..) => {} @@ -843,17 +847,20 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio _ if ty.is_unit() => {} ty::Tuple(tys) => { - ty = Ty::new_tup_from_iter(tcx, tys.iter().map(|ty| transform_ty(tcx, ty, options))); + ty = Ty::new_tup_from_iter( + tcx, + tys.iter().map(|ty| transform_ty(tcx, ty, parents, options)), + ); } ty::Array(ty0, len) => { let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()); - ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, options), len); + ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, parents, options), len); } ty::Slice(ty0) => { - ty = Ty::new_slice(tcx, transform_ty(tcx, *ty0, options)); + ty = Ty::new_slice(tcx, transform_ty(tcx, *ty0, parents, options)); } ty::Adt(adt_def, args) => { @@ -862,7 +869,8 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() { ty = Ty::new_adt(tcx, *adt_def, ty::List::empty()); - } else if adt_def.repr().transparent() && adt_def.is_struct() { + } else if adt_def.repr().transparent() && adt_def.is_struct() && !parents.contains(&ty) + { // Don't transform repr(transparent) types with an user-defined CFI encoding to // preserve the user-defined CFI encoding. if let Some(_) = tcx.get_attr(adt_def.did(), sym::cfi_encoding) { @@ -881,38 +889,48 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio // Generalize any repr(transparent) user-defined type that is either a pointer // or reference, and either references itself or any other type that contains or // references itself, to avoid a reference cycle. + + // If the self reference is not through a pointer, for example, due + // to using `PhantomData`, need to skip normalizing it if we hit it again. + parents.push(ty); if ty0.is_any_ptr() && ty0.contains(ty) { ty = transform_ty( tcx, ty0, + parents, options | TransformTyOptions::GENERALIZE_POINTERS, ); } else { - ty = transform_ty(tcx, ty0, options); + ty = transform_ty(tcx, ty0, parents, options); } + parents.pop(); } else { // Transform repr(transparent) types without non-ZST field into () ty = Ty::new_unit(tcx); } } else { - ty = Ty::new_adt(tcx, *adt_def, transform_args(tcx, args, options)); + ty = Ty::new_adt(tcx, *adt_def, transform_args(tcx, args, parents, options)); } } ty::FnDef(def_id, args) => { - ty = Ty::new_fn_def(tcx, *def_id, transform_args(tcx, args, options)); + ty = Ty::new_fn_def(tcx, *def_id, transform_args(tcx, args, parents, options)); } ty::Closure(def_id, args) => { - ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, options)); + ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, parents, options)); } ty::CoroutineClosure(def_id, args) => { - ty = Ty::new_coroutine_closure(tcx, *def_id, transform_args(tcx, args, options)); + ty = Ty::new_coroutine_closure( + tcx, + *def_id, + transform_args(tcx, args, parents, options), + ); } ty::Coroutine(def_id, args) => { - ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, options)); + ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, parents, options)); } ty::Ref(region, ty0, ..) => { @@ -924,9 +942,9 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio } } else { if ty.is_mutable_ptr() { - ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, options)); + ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options)); } else { - ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, options)); + ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options)); } } } @@ -940,9 +958,9 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio } } else { if ty.is_mutable_ptr() { - ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, *ptr_ty, options)); + ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options)); } else { - ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, *ptr_ty, options)); + ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options)); } } } @@ -955,9 +973,9 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio .skip_binder() .inputs() .iter() - .map(|ty| transform_ty(tcx, *ty, options)) + .map(|ty| transform_ty(tcx, *ty, parents, options)) .collect(); - let output = transform_ty(tcx, fn_sig.skip_binder().output(), options); + let output = transform_ty(tcx, fn_sig.skip_binder().output(), parents, options); ty = Ty::new_fn_ptr( tcx, ty::Binder::bind_with_vars( @@ -987,6 +1005,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio ty = transform_ty( tcx, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty), + parents, options, ); } @@ -1037,7 +1056,7 @@ pub fn typeid_for_fnabi<'tcx>( // Encode the return type let transform_ty_options = TransformTyOptions::from_bits(options.bits()) .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); - let ty = transform_ty(tcx, fn_abi.ret.layout.ty, transform_ty_options); + let ty = transform_ty(tcx, fn_abi.ret.layout.ty, &mut Vec::new(), transform_ty_options); typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); // Encode the parameter types @@ -1049,7 +1068,7 @@ pub fn typeid_for_fnabi<'tcx>( let mut pushed_arg = false; for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) { pushed_arg = true; - let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options); + let ty = transform_ty(tcx, arg.layout.ty, &mut Vec::new(), transform_ty_options); typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); } if !pushed_arg { @@ -1062,7 +1081,8 @@ pub fn typeid_for_fnabi<'tcx>( if fn_abi.args[n].mode == PassMode::Ignore { continue; } - let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options); + let ty = + transform_ty(tcx, fn_abi.args[n].layout.ty, &mut Vec::new(), transform_ty_options); typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); } diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs index 6f47f5e335577..1332338b26ab9 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs @@ -34,6 +34,12 @@ pub struct Bar(i32); #[repr(transparent)] pub struct Type3(T); +// repr(transparent) wrapper which engages in self-reference +#[repr(transparent)] +pub struct Type4(Type4Helper); +#[repr(transparent)] +pub struct Type4Helper(*mut T); + pub fn foo1(_: Type1) { } // CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo2(_: Type1, _: Type1) { } @@ -52,6 +58,13 @@ pub fn foo8(_: Type3, _: Type3) { } // CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo9(_: Type3, _: Type3, _: Type3) { } // CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo10(_: Type4) { } +// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo11(_: Type4, _: Type4) { } +// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo12(_: Type4, _: Type4, _: Type4) { } +// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooE"} // CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3FooS_E"} @@ -62,3 +75,6 @@ pub fn foo9(_: Type3, _: Type3, _: Type3) { } // CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarE"} // CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_E"} // CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}3BarS_S_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4E"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvPu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4S0_S0_E"} diff --git a/tests/ui/sanitizer/cfi-self-ref.rs b/tests/ui/sanitizer/cfi-self-ref.rs new file mode 100644 index 0000000000000..32d0b10070265 --- /dev/null +++ b/tests/ui/sanitizer/cfi-self-ref.rs @@ -0,0 +1,33 @@ +// Check that encoding self-referential types works with #[repr(transparent)] + +//@ needs-sanitizer-cfi +// FIXME(#122848) Remove only-linux once OSX CFI binaries work +//@ only-linux +//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi +//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0 +//@ run-pass + +use std::marker::PhantomData; + +struct X { + _x: u8, + p: PhantomData, +} + +#[repr(transparent)] +struct Y(X); + +trait Fooable { + fn foo(&self, y: Y); +} + +struct Bar; + +impl Fooable for Bar { + fn foo(&self, _: Y) {} +} + +fn main() { + let x = &Bar as &dyn Fooable; + x.foo(Y(X {_x: 0, p: PhantomData})); +} From d3fc623f79d38002b3202551281488d7182049f7 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Tue, 19 Mar 2024 19:03:07 +0100 Subject: [PATCH 09/13] Introduce infrastructure for generating target docs --- Cargo.lock | 36 +++ Cargo.toml | 1 + .../src/spec/targets/aarch64_apple_tvos.rs | 6 +- .../src/spec/targets/i686_pc_windows_gnu.rs | 8 +- .../targets/loongarch64_unknown_linux_gnu.rs | 8 +- .../src/spec/targets/powerpc64_ibm_aix.rs | 8 +- src/bootstrap/src/core/build_steps/doc.rs | 31 ++- src/bootstrap/src/core/build_steps/tool.rs | 1 + src/bootstrap/src/lib.rs | 45 ++- .../host-x86_64/x86_64-gnu-llvm-17/Dockerfile | 4 + src/doc/rustc/src/SUMMARY.md | 3 + src/doc/rustc/src/platform-support.md | 13 +- src/doc/rustc/src/platform-support/aix.md | 10 + .../rustc/src/platform-support/apple-tvos.md | 10 + .../src/platform-support/loongarch-linux.md | 11 + src/doc/rustc/src/platform-support/targets.md | 7 + src/doc/rustc/target_infos/*-apple-tvos.md | 78 ++++++ .../rustc/target_infos/i686-pc-windows-gnu.md | 10 + .../loongarch*-unknown-linux-*.md | 93 +++++++ .../rustc/target_infos/powerpc64-ibm-aix.md | 18 ++ src/tools/target-docs/Cargo.toml | 14 + src/tools/target-docs/README.md | 37 +++ src/tools/target-docs/src/main.rs | 234 ++++++++++++++++ src/tools/target-docs/src/parse.rs | 135 +++++++++ src/tools/target-docs/src/parse/tests.rs | 99 +++++++ src/tools/target-docs/src/render.rs | 257 ++++++++++++++++++ 26 files changed, 1153 insertions(+), 24 deletions(-) create mode 100644 src/doc/rustc/src/platform-support/targets.md create mode 100644 src/doc/rustc/target_infos/*-apple-tvos.md create mode 100644 src/doc/rustc/target_infos/i686-pc-windows-gnu.md create mode 100644 src/doc/rustc/target_infos/loongarch*-unknown-linux-*.md create mode 100644 src/doc/rustc/target_infos/powerpc64-ibm-aix.md create mode 100644 src/tools/target-docs/Cargo.toml create mode 100644 src/tools/target-docs/README.md create mode 100644 src/tools/target-docs/src/main.rs create mode 100644 src/tools/target-docs/src/parse.rs create mode 100644 src/tools/target-docs/src/parse/tests.rs create mode 100644 src/tools/target-docs/src/render.rs diff --git a/Cargo.lock b/Cargo.lock index b8fe1ebaf8019..e20a26cda3ae3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1585,6 +1585,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "glob-match" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d" + [[package]] name = "globset" version = "0.4.13" @@ -5057,6 +5063,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha1" version = "0.10.6" @@ -5419,6 +5438,17 @@ dependencies = [ "xattr", ] +[[package]] +name = "target-docs" +version = "0.1.0" +dependencies = [ + "eyre", + "glob-match", + "serde", + "serde_json", + "serde_yaml", +] + [[package]] name = "tempfile" version = "3.10.1" @@ -6065,6 +6095,12 @@ dependencies = [ "diff", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" + [[package]] name = "unstable-book-gen" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index e12c968e205b7..90f17982f88e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ members = [ "src/tools/rustdoc-gui-test", "src/tools/opt-dist", "src/tools/coverage-dump", + "src/tools/target-docs", ] exclude = [ diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs index 0deadbdb02810..86e60ebe9fb8f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs @@ -6,9 +6,9 @@ pub fn target() -> Target { Target { llvm_target: tvos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, + description: Some("ARM64 tvOS".into()), + tier: Some(2), + host_tools: Some(false), std: None, }, pointer_width: 64, diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs index 66e09416dde90..50465d6710987 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_gnu.rs @@ -18,10 +18,10 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("32-bit MinGW (Windows 7+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs index f15a879894004..e4c3dc3492625 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs @@ -4,10 +4,10 @@ pub fn target() -> Target { Target { llvm_target: "loongarch64-unknown-linux-gnu".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36)".into()), + tier: Some(2), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs index 481df71c1a65a..227799e1f6fac 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-ibm-aix".into(), metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, + description: Some("64-bit AIX (7.2 and newer)".into()), + tier: Some(3), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:a-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 51b5cdc056577..92bd2d67c7199 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -1147,14 +1147,17 @@ impl Step for RustcBook { /// Builds the rustc book. /// - /// The lints are auto-generated by a tool, and then merged into the book + /// The lints and target docs are auto-generated by a tool, and then merged into the book /// in the "md-doc" directory in the build output directory. Then /// "rustbook" is used to convert it to HTML. fn run(self, builder: &Builder<'_>) { let out_base = builder.md_doc_out(self.target).join("rustc"); t!(fs::create_dir_all(&out_base)); - let out_listing = out_base.join("src/lints"); - builder.cp_link_r(&builder.src.join("src/doc/rustc"), &out_base); + let out_lints_listing = out_base.join("src/lints"); + let out_src_listing = out_base.join("src"); + + // target-docs will be modifying the files in-place, so we need an actual copy. + builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base); builder.info(&format!("Generating lint docs ({})", self.target)); let rustc = builder.rustc(self.compiler); @@ -1165,7 +1168,7 @@ impl Step for RustcBook { cmd.arg("--src"); cmd.arg(builder.src.join("compiler")); cmd.arg("--out"); - cmd.arg(&out_listing); + cmd.arg(&out_lints_listing); cmd.arg("--rustc"); cmd.arg(&rustc); cmd.arg("--rustc-target").arg(self.target.rustc_target_arg()); @@ -1194,6 +1197,26 @@ impl Step for RustcBook { builder.run(&mut cmd); drop(doc_generator_guard); + // Run target-docs generator + let mut cmd = builder.tool_cmd(Tool::TargetDocs); + cmd.arg(builder.src.join("src/doc/rustc/target_infos")); + cmd.arg(&out_src_listing); + cmd.env("RUSTC", &rustc); + // For now, we just check that the files are correct but do not generate output. + // Let the user override it to TARGET_CHECK_ONLY=0 for testing, but use 1 by default. + // See https://github.com/rust-lang/rust/issues/120745 for more info. + cmd.env("TARGET_CHECK_ONLY", std::env::var("TARGET_CHECK_ONLY").unwrap_or("1".to_owned())); + + let doc_generator_guard = builder.msg( + Kind::Run, + self.compiler.stage, + "target-docs", + self.compiler.host, + self.target, + ); + builder.run(&mut cmd); + drop(doc_generator_guard); + // Run rustbook/mdbook to generate the HTML pages. builder.ensure(RustbookSrc { target: self.target, diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index deab3fce54ca7..5ca0c66438206 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -301,6 +301,7 @@ bootstrap_tool!( RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes"; ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors"; LintDocs, "src/tools/lint-docs", "lint-docs"; + TargetDocs, "src/tools/target-docs", "target-docs"; JsonDocCk, "src/tools/jsondocck", "jsondocck"; JsonDocLint, "src/tools/jsondoclint", "jsondoclint"; HtmlChecker, "src/tools/html-checker", "html-checker"; diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index d8397ab51de3c..412d309fb799a 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1668,10 +1668,23 @@ impl Build { /// You can neither rely on this being a copy nor it being a link, /// so do not write to dst. pub fn copy_link(&self, src: &Path, dst: &Path) { - self.copy_link_internal(src, dst, false); + self.copy_internal(src, dst, false, true); } - fn copy_link_internal(&self, src: &Path, dst: &Path, dereference_symlinks: bool) { + /// Links a file from `src` to `dst`. + /// Unlike, [`Build::copy_link`], this makes an actual copy, which is usually not required, + /// so `copy_link` should be used instead if possible. + pub fn copy(&self, src: &Path, dst: &Path) { + self.copy_internal(src, dst, false, false); + } + + fn copy_internal( + &self, + src: &Path, + dst: &Path, + dereference_symlinks: bool, + link_if_possible: bool, + ) { if self.config.dry_run() { return; } @@ -1691,7 +1704,7 @@ impl Build { return; } } - if let Ok(()) = fs::hard_link(&src, dst) { + if link_if_possible && fs::hard_link(&src, dst).is_ok() { // Attempt to "easy copy" by creating a hard link // (symlinks don't work on windows), but if that fails // just fall back to a slow `copy` operation. @@ -1726,6 +1739,28 @@ impl Build { } } + /// Copies the `src` directory recursively to `dst`. Both are assumed to exist + /// when this function is called. + /// Unlike, [`Build::cp_link_r`], this makes an actual copy, which is usually not required, + /// so `cp_link_r` should be used instead if possible. + pub fn cp_r(&self, src: &Path, dst: &Path) { + if self.config.dry_run() { + return; + } + for f in self.read_dir(src) { + let path = f.path(); + let name = path.file_name().unwrap(); + let dst = dst.join(name); + if t!(f.file_type()).is_dir() { + t!(fs::create_dir_all(&dst)); + self.cp_r(&path, &dst); + } else { + let _ = fs::remove_file(&dst); + self.copy(&path, &dst); + } + } + } + /// Copies the `src` directory recursively to `dst`. Both are assumed to exist /// when this function is called. /// Will attempt to use hard links if possible and fall back to copying. @@ -1779,7 +1814,9 @@ impl Build { if !src.exists() { panic!("ERROR: File \"{}\" not found!", src.display()); } - self.copy_link_internal(src, &dst, true); + + self.copy_internal(src, &dst, true, true); + chmod(&dst, perms); } diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile index 538962802c96f..9fa1afcf811b8 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile @@ -49,6 +49,10 @@ ENV EXTERNAL_LLVM 1 # be missing. ENV IS_NOT_LATEST_LLVM 1 + +# Ubuntu LLVM 17 does not have support for experimental targets like csky. +ENV TARGET_DOCS_SKIP_TARGETS "csky-unknown-linux-gnuabiv2,csky-unknown-linux-gnuabiv2hf" + # Using llvm-link-shared due to libffi issues -- see #34486 ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 83acce80f969d..a1ee671170669 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -69,6 +69,9 @@ - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md) - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) - [x86_64h-apple-darwin](platform-support/x86_64h-apple-darwin.md) + + + - [Targets](targets/index.md) - [Built-in Targets](targets/built-in.md) - [Custom Targets](targets/custom.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 75d38dd20bdeb..b1fb2b196bbf2 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -40,6 +40,9 @@ target | notes `x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 10+) `x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+) `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+) + + + [^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. See [issue #114479][x86-32-float-issue]. @@ -102,7 +105,9 @@ target | notes `x86_64-unknown-illumos` | illumos `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3 [`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64 - + + + ## Tier 2 without Host Tools Tier 2 targets can be thought of as "guaranteed to build". The Rust project @@ -201,6 +206,9 @@ target | std | notes [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat `x86_64-unknown-redox` | ✓ | Redox OS [`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 64-bit UEFI + + + [^x86_32-floats-x87]: Floating-point support on `i586` targets is non-compliant: the `x87` registers and instructions used for these targets do not provide IEEE-754-compliant behavior, in particular when it comes to rounding and NaN payload bits. See [issue #114479][x86-32-float-issue]. [wasi-rename]: https://github.com/rust-lang/compiler-team/issues/607 @@ -379,5 +387,8 @@ target | std | host | notes [`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 64-bit Windows 7 support `x86_64-wrs-vxworks` | ? | | [`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell) + + + [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets diff --git a/src/doc/rustc/src/platform-support/aix.md b/src/doc/rustc/src/platform-support/aix.md index c3ce71a183568..bbde0daa179fc 100644 --- a/src/doc/rustc/src/platform-support/aix.md +++ b/src/doc/rustc/src/platform-support/aix.md @@ -1,5 +1,15 @@ # `powerpc64-ibm-aix` + + **Tier: 3** Rust for AIX operating system, currently only 64-bit PowerPC is supported. diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md index e7ea109df1ba1..4a42779bb3464 100644 --- a/src/doc/rustc/src/platform-support/apple-tvos.md +++ b/src/doc/rustc/src/platform-support/apple-tvos.md @@ -2,6 +2,16 @@ - aarch64-apple-tvos - x86_64-apple-tvos + + **Tier: 3** Apple tvOS targets: diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md index e8f55b8bfce10..3cda4eaf4b07c 100644 --- a/src/doc/rustc/src/platform-support/loongarch-linux.md +++ b/src/doc/rustc/src/platform-support/loongarch-linux.md @@ -1,5 +1,16 @@ # loongarch\*-unknown-linux-\* + + + **Tier: 2** [LoongArch] is a new RISC ISA developed by Loongson Technology Corporation Limited. diff --git a/src/doc/rustc/src/platform-support/targets.md b/src/doc/rustc/src/platform-support/targets.md new file mode 100644 index 0000000000000..2a34bac74b377 --- /dev/null +++ b/src/doc/rustc/src/platform-support/targets.md @@ -0,0 +1,7 @@ +# List of all targets + +An alphabetical list of all targets. + + + + diff --git a/src/doc/rustc/target_infos/*-apple-tvos.md b/src/doc/rustc/target_infos/*-apple-tvos.md new file mode 100644 index 0000000000000..1701dc42f9855 --- /dev/null +++ b/src/doc/rustc/target_infos/*-apple-tvos.md @@ -0,0 +1,78 @@ +--- +maintainers: ["@thomcc"] +--- + +## Overview + +Apple tvOS targets: +- Apple tvOS on aarch64 +- Apple tvOS Simulator on x86_64 + +## Requirements + +These targets are cross-compiled. You will need appropriate versions of Xcode +and the SDKs for tvOS (`AppleTVOS.sdk`) and/or the tvOS Simulator +(`AppleTVSimulator.sdk`) to build a toolchain and target these platforms. + +The targets support most (see below) of the standard library including the +allocator to the best of my knowledge, however they are very new, not yet +well-tested, and it is possible that there are various bugs. + +In theory we support back to tvOS version 7.0, although the actual minimum +version you can target may be newer than this, for example due to the versions +of Xcode and your SDKs. + +As with the other Apple targets, `rustc` respects the common environment +variables used by Xcode to configure this, in this case +`TVOS_DEPLOYMENT_TARGET`. + +As mentioned, "most" of the standard library is supported, which means that some portions +are known to be unsupported. The following APIs are currently known to have +missing or incomplete support: + +- `std::process::Command`'s API will return an error if it is configured in a + manner which cannot be performed using `posix_spawn` -- this is because the + more flexible `fork`/`exec`-based approach is prohibited on these platforms in + favor of `posix_spawn{,p}` (which still probably will get you rejected from + app stores, so is likely sideloading-only). A concrete set of cases where this + will occur is difficult to enumerate (and would quickly become stale), but in + some cases it may be worked around by tweaking the manner in which `Command` + is invoked. + +## Building the target + +The targets can be built by enabling them for a `rustc` build in `config.toml`, by adding, for example: + +```toml +[build] +build-stage = 1 +target = ["aarch64-apple-tvos", "x86_64-apple-tvos", "aarch64-apple-tvos-sim"] +``` + +It's possible that cargo under `-Zbuild-std` may also be used to target them. + +## Building Rust programs + +*Note: Building for this target requires the corresponding TVOS SDK, as provided by Xcode.* + +Rust programs can be built for these targets + +```text +$ rustc --target aarch64-apple-tvos your-code.rs +... +$ rustc --target x86_64-apple-tvos your-code.rs +... +$ rustc --target aarch64-apple-tvos-sim your-code.rs +``` + +## Testing + +There is no support for running the Rust or standard library testsuite on tvOS or the simulators at the moment. Testing has mostly been done manually with builds of static libraries called from Xcode or a simulator. + +It hopefully will be possible to improve this in the future. + +## Cross compilation + +This target can be cross-compiled from x86_64 or aarch64 macOS hosts. + +Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK. diff --git a/src/doc/rustc/target_infos/i686-pc-windows-gnu.md b/src/doc/rustc/target_infos/i686-pc-windows-gnu.md new file mode 100644 index 0000000000000..02fe6df687e12 --- /dev/null +++ b/src/doc/rustc/target_infos/i686-pc-windows-gnu.md @@ -0,0 +1,10 @@ +--- +footnotes: + i686-pc-windows-gnu: + - "x86_32-floats-return-ABI" + - "windows-support" +--- + +## Overview + +32-bit Windows using MinGW. diff --git a/src/doc/rustc/target_infos/loongarch*-unknown-linux-*.md b/src/doc/rustc/target_infos/loongarch*-unknown-linux-*.md new file mode 100644 index 0000000000000..b2156caa749bc --- /dev/null +++ b/src/doc/rustc/target_infos/loongarch*-unknown-linux-*.md @@ -0,0 +1,93 @@ +--- +maintainers: + - "[WANG Rui](https://github.com/heiher) `wangrui@loongson.cn`" + - "[ZHAI Xiang](https://github.com/xiangzhai) `zhaixiang@loongson.cn`" + - "[ZHAI Xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn`" + - "[WANG Xuerui](https://github.com/xen0n) `git@xen0n.name`" +--- + +## Overview + +[LoongArch] is a new RISC ISA developed by Loongson Technology Corporation Limited. + +[LoongArch]: https://loongson.github.io/LoongArch-Documentation/README-EN.html + +The target name follow this format: `--`, where `` specifies the CPU family/model, `` specifies the vendor and `` the operating system name. +While the integer base ABI is implied by the machine field, the floating point base ABI type is encoded into the os field of the specifier using the string suffix ``. + +| `` | `Description` | +|------------------------|--------------------------------------------------------------------| +| f64 | The base ABI use 64-bits FPRs for parameter passing. (lp64d)| +| f32 | The base ABI uses 32-bit FPRs for parameter passing. (lp64f)| +| sf | The base ABI uses no FPR for parameter passing. (lp64s) | + +
+ +|`ABI type(Base ABI/ABI extension)`| `C library` | `kernel` | `target tuple` | +|----------------------------------|-------------|----------|----------------------------------| +| lp64d/base | glibc | linux | loongarch64-unknown-linux-gnu | +| lp64f/base | glibc | linux | loongarch64-unknown-linux-gnuf32 | +| lp64s/base | glibc | linux | loongarch64-unknown-linux-gnusf | +| lp64d/base | musl libc | linux | loongarch64-unknown-linux-musl| +| lp64f/base | musl libc | linux | loongarch64-unknown-linux-muslf32| +| lp64s/base | musl libc | linux | loongarch64-unknown-linux-muslsf | + +## Requirements + +This target is cross-compiled. +A GNU toolchain for LoongArch target is required. It can be downloaded from https://github.com/loongson/build-tools/releases, or built from the source code of GCC (12.1.0 or later) and Binutils (2.40 or later). + +## Building the target + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["loongarch64-unknown-linux-gnu"] +``` + +Make sure `loongarch64-unknown-linux-gnu-gcc` can be searched from the directories specified in`$PATH`. Alternatively, you can use GNU LoongArch Toolchain by adding the following to `config.toml`: + +```toml +[target.loongarch64-unknown-linux-gnu] +# ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN +cc = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc" +cxx = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-g++" +ar = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-ar" +ranlib = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-ranlib" +linker = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc" +``` + +## Cross compilation + +This target can be cross-compiled on a `x86_64-unknown-linux-gnu` host. Cross-compilation on other hosts may work but is not tested. + +## Testing +To test a cross-compiled binary on your build system, install the qemu binary that supports the LoongArch architecture and execute the following commands. +```text +CC_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc \ +CXX_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-g++ \ +AR_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc-ar \ +CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNUN_LINKER=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc \ +# SET TARGET SYSTEM LIBRARY PATH +CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNUN_RUNNER="qemu-loongarch64 -L /TOOLCHAIN_PATH/TARGET_LIBRARY_PATH" \ +cargo run --target loongarch64-unknown-linux-gnu --release +``` +Tested on x86 architecture, other architectures not tested. + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of `std` by using `build-std` or similar. + +If `rustc` has support for that target and the library artifacts are available, then Rust static libraries can be built for that target: + +```shell +$ rustc --target loongarch64-unknown-linux-gnu your-code.rs --crate-type staticlib +$ ls libyour_code.a +``` + +On Rust Nightly it's possible to build without the target artifacts available: + +```text +cargo build -Z build-std --target loongarch64-unknown-linux-gnu +``` diff --git a/src/doc/rustc/target_infos/powerpc64-ibm-aix.md b/src/doc/rustc/target_infos/powerpc64-ibm-aix.md new file mode 100644 index 0000000000000..ac070cb92f7f6 --- /dev/null +++ b/src/doc/rustc/target_infos/powerpc64-ibm-aix.md @@ -0,0 +1,18 @@ +--- +maintainers: [ + "QIU Chaofan `qiucofan@cn.ibm.com`, https://github.com/ecnelises", + "Kai LUO, `lkail@cn.ibm.com`, https://github.com/bzEq", +] +--- + +## Requirements + +This target supports host tools, std and alloc. This target cannot be cross-compiled as for now, mainly because of the unavailability of system linker on other platforms. + +Binary built for this target is expected to run on Power7 or newer CPU, and AIX 7.2 or newer version. + +Binary format of this platform is XCOFF. Archive file format is 'AIX big format'. + +## Testing + +This target supports running test suites natively, but it's not available to cross-compile and execute in emulator. diff --git a/src/tools/target-docs/Cargo.toml b/src/tools/target-docs/Cargo.toml new file mode 100644 index 0000000000000..78741710dcbb7 --- /dev/null +++ b/src/tools/target-docs/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "target-docs" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +eyre = "0.6.12" +glob-match = "0.2.1" +serde = { version = "1.0.185", features = ["derive"] } +serde_json = "1.0.114" +serde_yaml = "0.9.31" diff --git a/src/tools/target-docs/README.md b/src/tools/target-docs/README.md new file mode 100644 index 0000000000000..d7717a2ced8e8 --- /dev/null +++ b/src/tools/target-docs/README.md @@ -0,0 +1,37 @@ +# target-docs + +This tool generates target documentation for all targets in the rustc book. + +To achieve this, it uses a list of input markdown files provided in `src/doc/rustc/target_infos`. These files follow a strict format. +Every file covers a glob pattern of targets according to its file name. + +For every rustc target, we iterate through all the target infos and find matching globs. +When a glob matches, it extracts the h2 markdown sections and saves them for the target. + +In the end, a page is generated for every target using these sections. +Sections that are not provided are stubbed out. Currently, the sections are + +- Overview +- Requirements +- Testing +- Building the target +- Cross compilation +- Building Rust programs + +In addition to the markdown sections, we also have extra data about the targets. +This is achieved through YAML frontmatter. + +The frontmatter follows the following format: + +```yaml +maintainers: ["@someone"] +footnotes: + i686-pc-windows-gnu: + - "x86_32-floats-return-ABI" + - "windows-support" +``` + +The top level keys are: + +- `maintainers` (optional): list of strings +- `footnotes` (optional): for every *specific* target a list of footnotes. The footnotes have to be defined manually below the correct table in platform-support. diff --git a/src/tools/target-docs/src/main.rs b/src/tools/target-docs/src/main.rs new file mode 100644 index 0000000000000..73d8b3f4fbc47 --- /dev/null +++ b/src/tools/target-docs/src/main.rs @@ -0,0 +1,234 @@ +mod parse; +mod render; + +use std::{ + collections::HashMap, + path::{Path, PathBuf}, + process::Command, +}; + +use eyre::{bail, Context, OptionExt, Result}; +use parse::ParsedTargetInfoFile; +use serde::Deserialize; + +/// Information about a target obtained from the markdown and rustc. +struct TargetInfo { + name: String, + maintainers: Vec, + sections: Vec<(String, String)>, + footnotes: Vec, + target_cfgs: Vec<(String, String)>, + metadata: RustcTargetMetadata, +} + +/// All the sections that we want every doc page to have. +/// It may make sense to relax this into two kinds of sections, "required" sections +/// and "optional" sections, where required sections will get stubbed out when not found +/// while optional sections will just not exist when not found. +// IMPORTANT: This is also documented in the README, keep it in sync. +const SECTIONS: &[&str] = &[ + "Overview", + "Requirements", + "Testing", + "Building the target", + "Cross compilation", + "Building Rust programs", +]; + +fn main() -> Result<()> { + let args = std::env::args().collect::>(); + let input_dir = args + .get(1) + .ok_or_eyre("first argument must be path to target_infos directory containing target source md files (src/doc/rustc/target_infos/)")?; + let output_src = args.get(2).ok_or_eyre( + "second argument must be path to `src` output directory (build/$target/md-doc/rustc/src)", + )?; + + println!("Loading target info docs from {input_dir}"); + println!("Writing output to {output_src}"); + + let targets_to_skip = std::env::var("TARGET_DOCS_SKIP_TARGETS"); + let targets_to_skip = + targets_to_skip.as_deref().map(|s| s.split(",").collect::>()).unwrap_or_default(); + + let rustc = + PathBuf::from(std::env::var("RUSTC").expect("must pass RUSTC env var pointing to rustc")); + let check_only = std::env::var("TARGET_CHECK_ONLY") == Ok("1".to_owned()); + + let targets = rustc_stdout(&rustc, &["--print", "target-list"]); + let targets = + targets.lines().filter(|target| !targets_to_skip.contains(target)).collect::>(); + + let mut info_patterns = parse::load_target_infos(Path::new(input_dir)) + .wrap_err("failed loading target_info")? + .into_iter() + .map(|info| { + let footnotes_used = + info.footnotes.keys().map(|target| (target.clone(), false)).collect(); + TargetPatternEntry { info, used: false, footnotes_used } + }) + .collect::>(); + + eprintln!("Collecting rustc information"); + let rustc_infos = + targets.iter().map(|target| rustc_target_info(&rustc, target)).collect::>(); + + let targets = targets + .into_iter() + .map(|target| target_doc_info(&mut info_patterns, target)) + .zip(rustc_infos) + .map(|(md, rustc)| TargetInfo { + name: md.name, + maintainers: md.maintainers, + sections: md.sections, + footnotes: md.footnotes, + target_cfgs: rustc.target_cfgs, + metadata: rustc.metadata, + }) + .collect::>(); + + eprintln!("Rendering targets check_only={check_only}"); + let targets_dir = Path::new(output_src).join("platform-support").join("targets"); + if !check_only { + std::fs::create_dir_all(&targets_dir).wrap_err("creating platform-support/targets dir")?; + } + for info in &targets { + let doc = render::render_target_md(info); + + if !check_only { + std::fs::write(targets_dir.join(format!("{}.md", info.name)), doc) + .wrap_err("writing target file")?; + } + } + + for target_pattern in info_patterns { + if !target_pattern.used { + bail!("target pattern `{}` was never used", target_pattern.info.pattern); + } + + for footnote_target in target_pattern.info.footnotes.keys() { + let used = target_pattern.footnotes_used[footnote_target]; + if !used { + bail!( + "in target pattern `{}`, the footnotes for target `{}` were never used", + target_pattern.info.pattern, + footnote_target, + ); + } + } + } + + render::render_static(check_only, Path::new(output_src), &targets)?; + + eprintln!("Finished generating target docs"); + Ok(()) +} + +struct TargetPatternEntry { + info: ParsedTargetInfoFile, + used: bool, + footnotes_used: HashMap, +} + +/// Information about a target obtained from the target_info markdown file. +struct TargetInfoMd { + name: String, + maintainers: Vec, + sections: Vec<(String, String)>, + footnotes: Vec, +} + +fn target_doc_info(info_patterns: &mut [TargetPatternEntry], target: &str) -> TargetInfoMd { + let mut maintainers = Vec::new(); + let mut sections = Vec::new(); + + let mut footnotes = Vec::new(); + + for target_pattern_entry in info_patterns { + if glob_match::glob_match(&target_pattern_entry.info.pattern, target) { + target_pattern_entry.used = true; + let target_pattern = &target_pattern_entry.info; + + maintainers.extend_from_slice(&target_pattern.maintainers); + + for (section_name, content) in &target_pattern.sections { + if sections.iter().any(|(name, _)| name == section_name) { + panic!( + "target {target} inherits the section {section_name} from multiple patterns, create a more specific pattern and add it there" + ); + } + sections.push((section_name.clone(), content.clone())); + } + + if let Some(target_footnotes) = target_pattern.footnotes.get(target) { + target_pattern_entry.footnotes_used.insert(target.to_owned(), true); + + if !footnotes.is_empty() { + panic!("target {target} is assigned metadata from more than one pattern"); + } + footnotes = target_footnotes.clone(); + } + } + } + + TargetInfoMd { name: target.to_owned(), maintainers, sections, footnotes } +} + +/// Information about a target obtained from rustc. +struct RustcTargetInfo { + target_cfgs: Vec<(String, String)>, + metadata: RustcTargetMetadata, +} + +#[derive(Deserialize)] +struct RustcTargetMetadata { + description: Option, + tier: Option, + host_tools: Option, + std: Option, +} + +/// Get information about a target from rustc. +fn rustc_target_info(rustc: &Path, target: &str) -> RustcTargetInfo { + let cfgs = rustc_stdout(rustc, &["--print", "cfg", "--target", target]); + let target_cfgs = cfgs + .lines() + .filter_map(|line| { + if line.starts_with("target_") { + let Some((key, value)) = line.split_once('=') else { + // For example `unix` + return None; + }; + Some((key.to_owned(), value.to_owned())) + } else { + None + } + }) + .collect(); + + #[derive(Deserialize)] + struct TargetJson { + metadata: RustcTargetMetadata, + } + + let json_spec = rustc_stdout( + rustc, + &["-Zunstable-options", "--print", "target-spec-json", "--target", target], + ); + let spec = serde_json::from_str::(&json_spec) + .expect("parsing --print target-spec-json for metadata"); + + RustcTargetInfo { target_cfgs, metadata: spec.metadata } +} + +fn rustc_stdout(rustc: &Path, args: &[&str]) -> String { + let output = Command::new(rustc).args(args).output().unwrap(); + if !output.status.success() { + panic!( + "rustc failed: {}, {}", + output.status, + String::from_utf8(output.stderr).unwrap_or_default() + ) + } + String::from_utf8(output.stdout).unwrap() +} diff --git a/src/tools/target-docs/src/parse.rs b/src/tools/target-docs/src/parse.rs new file mode 100644 index 0000000000000..b771c8840209b --- /dev/null +++ b/src/tools/target-docs/src/parse.rs @@ -0,0 +1,135 @@ +//! Suboptimal half-markdown parser that's just good-enough for this. + +use eyre::{bail, OptionExt, Result, WrapErr}; +use serde::Deserialize; +use std::{collections::HashMap, fs::DirEntry, path::Path}; + +#[derive(Debug)] +pub struct ParsedTargetInfoFile { + pub pattern: String, + pub maintainers: Vec, + pub sections: Vec<(String, String)>, + pub footnotes: HashMap>, +} + +// IMPORTANT: This is also documented in the README, keep it in sync. +#[derive(Deserialize)] +#[serde(deny_unknown_fields)] +struct Frontmatter { + #[serde(default)] + maintainers: Vec, + #[serde(default)] + footnotes: HashMap>, +} + +// IMPORTANT: This is also documented in the README, keep it in sync. +#[derive(Debug, Clone, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct TargetFootnotes { + pub target: String, + #[serde(default)] + pub footnotes: Vec, +} + +// IMPORTANT: This is also documented in the README, keep it in sync. +#[derive(Debug, PartialEq, Clone, Copy, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum TriStateBool { + True, + False, + Unknown, +} + +pub fn load_target_infos(directory: &Path) -> Result> { + let dir = std::fs::read_dir(directory).unwrap(); + let mut infos = Vec::new(); + + for entry in dir { + let entry = entry?; + infos.push( + load_single_target_info(&entry) + .wrap_err_with(|| format!("loading {}", entry.path().display()))?, + ) + } + + Ok(infos) +} + +fn load_single_target_info(entry: &DirEntry) -> Result { + let pattern = entry.file_name(); + let name = pattern + .to_str() + .ok_or_eyre("file name is invalid utf8")? + .strip_suffix(".md") + .ok_or_eyre("target_info files must end with .md")?; + let content: String = std::fs::read_to_string(entry.path()).wrap_err("reading content")?; + + parse_file(name, &content) +} + +fn parse_file(name: &str, content: &str) -> Result { + let mut frontmatter_splitter = content.split("---\n"); + + let frontmatter = frontmatter_splitter.nth(1).ok_or_eyre("missing frontmatter")?; + + let frontmatter_line_count = frontmatter.lines().count() + 2; // 2 from --- + + let frontmatter = + serde_yaml::from_str::(frontmatter).wrap_err("invalid frontmatter")?; + + let body = frontmatter_splitter.next().ok_or_eyre("no body")?; + + let mut sections = Vec::<(String, String)>::new(); + let mut in_codeblock = false; + + for (idx, line) in body.lines().enumerate() { + let number = frontmatter_line_count + idx + 1; // 1 because "line numbers" are off by 1 + + let push_line = |sections: &mut Vec<(String, String)>, line| { + match sections.last_mut() { + Some((_, content)) => { + content.push_str(line); + content.push('\n'); + } + None if line.trim().is_empty() => {} + None => { + bail!("line {number} with content not allowed before the first heading") + } + } + Ok(()) + }; + + if line.starts_with("```") { + in_codeblock ^= true; // toggle + push_line(&mut sections, line)?; + } else if line.starts_with('#') { + if in_codeblock { + push_line(&mut sections, line)?; + } else if let Some(header) = line.strip_prefix("## ") { + if !crate::SECTIONS.contains(&header) { + bail!( + "on line {number}, `{header}` is not an allowed section name, must be one of {:?}", + super::SECTIONS + ); + } + sections.push((header.to_owned(), String::new())); + } else { + bail!("on line {number}, the only allowed headings are `## `: `{line}`"); + } + } else { + push_line(&mut sections, line)?; + } + } + + sections.iter_mut().for_each(|section| section.1 = section.1.trim().to_owned()); + + Ok(ParsedTargetInfoFile { + pattern: name.to_owned(), + maintainers: frontmatter.maintainers, + sections, + footnotes: frontmatter.footnotes, + }) +} + +#[cfg(test)] +mod tests; diff --git a/src/tools/target-docs/src/parse/tests.rs b/src/tools/target-docs/src/parse/tests.rs new file mode 100644 index 0000000000000..5b0530ba52656 --- /dev/null +++ b/src/tools/target-docs/src/parse/tests.rs @@ -0,0 +1,99 @@ +#[test] +fn no_frontmatter() { + let name = "archlinux-unknown-linux-gnu.md"; // arch linux is an arch, right? + let content = ""; + assert!(super::parse_file(name, content).is_err()); +} + +#[test] +fn invalid_section() { + let name = "6502-nintendo-nes.md"; + let content = " +--- +--- + +## Not A Real Section +"; + + assert!(super::parse_file(name, content).is_err()); +} + +#[test] +fn wrong_header() { + let name = "x86_64-known-linux-gnu.md"; + let content = " +--- +--- + +# x86_64-known-linux-gnu +"; + + assert!(super::parse_file(name, content).is_err()); +} + +#[test] +fn parse_correctly() { + let name = "cat-unknown-linux-gnu.md"; + let content = r#" +--- +maintainers: ["who maintains the cat?"] +--- +## Requirements + +This target mostly just meows and doesn't do much. + +## Testing + +You can pet the cat and it might respond positively. + +## Cross compilation + +If you're on a dog system, there might be conflicts with the cat, be careful. +But it should be possible. + "#; + + let info = super::parse_file(name, content).unwrap(); + + assert_eq!(info.maintainers, vec!["who maintains the cat?"]); + assert_eq!(info.pattern, name); + assert_eq!( + info.sections, + vec![ + ( + "Requirements".to_owned(), + "This target mostly just meows and doesn't do much.".to_owned(), + ), + ( + "Testing".to_owned(), + "You can pet the cat and it might respond positively.".to_owned(), + ), + ( + "Cross compilation".to_owned(), + "If you're on a dog system, there might be conflicts with the cat, be careful.\nBut it should be possible.".to_owned(), + ), + ] + ); +} + +#[test] +fn backticks() { + let name = "microservices-unknown-linux-gnu"; // microservices are my favourite architecture + let content = r#" +--- +--- + +## Testing + +```text +# hello world +``` + "#; + + let info = super::parse_file(name, content).unwrap(); + + assert_eq!(info.pattern, name); + assert_eq!( + info.sections, + vec![("Testing".to_owned(), "```text\n# hello world\n```".to_owned(),),] + ); +} diff --git a/src/tools/target-docs/src/render.rs b/src/tools/target-docs/src/render.rs new file mode 100644 index 0000000000000..ecb18049a2b33 --- /dev/null +++ b/src/tools/target-docs/src/render.rs @@ -0,0 +1,257 @@ +use eyre::{Context, OptionExt, Result}; +use std::{fs, path::Path}; + +use crate::TargetInfo; + +/// Renders a single target markdown file from the information obtained. +pub fn render_target_md(target: &TargetInfo) -> String { + let render_header_option_bool = |bool| match bool { + Some(true) => "Yes", + Some(false) => "No", + None => "?", + }; + + let mut doc = format!( + "# {}\n\n**Tier: {}**\n\n**std: {}**\n\n**host tools: {}**\n\n", + target.name, + match target.metadata.tier { + Some(1) => "1", + Some(2) => "2", + Some(3) => "3", + _ => "UNKNOWN", + }, + render_header_option_bool(target.metadata.std), + render_header_option_bool(target.metadata.host_tools), + ); + + let mut section = |name: &str, content: &str| { + doc.push_str("## "); + doc.push_str(name.trim()); + doc.push('\n'); + doc.push_str(content.trim()); + doc.push_str("\n\n"); + }; + + let maintainers_content = if target.maintainers.is_empty() { + "This target does not have any maintainers!".to_owned() + } else { + format!( + "This target is maintained by:\n{}", + target + .maintainers + .iter() + .map(|maintainer| { + let maintainer = if maintainer.starts_with('@') && !maintainer.contains(' ') { + format!( + "[@{0}](https://github.com/{0})", + maintainer.strip_prefix("@").unwrap() + ) + } else { + maintainer.to_owned() + }; + + format!("- {maintainer}") + }) + .collect::>() + .join("\n") + ) + }; + + section("Maintainers", &maintainers_content); + + for section_name in crate::SECTIONS { + let value = target.sections.iter().find(|(name, _)| name == section_name); + + let section_content = match value { + Some((_, value)) => value.clone(), + None => "Unknown.".to_owned(), + }; + section(section_name, §ion_content); + } + + let cfg_text = target + .target_cfgs + .iter() + .map(|(key, value)| format!("- `{key}` = `{value}`")) + .collect::>() + .join("\n"); + let cfg_content = + format!("This target defines the following target-specific cfg values:\n{cfg_text}\n"); + + section("cfg", &cfg_content); + + doc +} + +/// Replaces inner part of the form +/// `` +/// with replacement`. +fn replace_section(prev_content: &str, section_name: &str, replacement: &str) -> Result { + let magic_summary_start = format!(""); + let magic_summary_end = format!(""); + + let (pre_target, target_and_after) = prev_content + .split_once(&magic_summary_start) + .ok_or_eyre(" not found")?; + + let (_, post_target) = target_and_after + .split_once(&magic_summary_end) + .ok_or_eyre(" not found")?; + + let new = format!("{pre_target}{replacement}{post_target}"); + Ok(new) +} + +/// Renders the non-target files like `SUMMARY.md` that depend on the target. +pub fn render_static(check_only: bool, src_output: &Path, targets: &[TargetInfo]) -> Result<()> { + let targets_file = src_output.join("platform-support").join("targets.md"); + let old_targets = fs::read_to_string(&targets_file).wrap_err("reading summary file")?; + + let target_list = targets + .iter() + .map(|target| format!("- [{0}](platform-support/targets/{0}.md)", target.name)) + .collect::>() + .join("\n"); + + let new_targets = + replace_section(&old_targets, "TARGET", &target_list).wrap_err("replacing targets.md")?; + + if !check_only { + fs::write(targets_file, new_targets).wrap_err("writing targets.md")?; + } + + let platform_support_main = src_output.join("platform-support.md"); + let platform_support_main_old = + fs::read_to_string(&platform_support_main).wrap_err("reading platform-support.md")?; + let platform_support_main_new = + render_platform_support_tables(&platform_support_main_old, targets)?; + + if !check_only { + fs::write(platform_support_main, platform_support_main_new) + .wrap_err("writing platform-support.md")?; + } + + let summary = src_output.join("SUMMARY.md"); + let summary_old = fs::read_to_string(&summary).wrap_err("reading SUMMARY.md")?; + // indent the list + let summary_new = + replace_section(&summary_old, "TARGET_LIST", &target_list.replace("- ", " - ")) + .wrap_err("replacig SUMMARY.md")?; + if !check_only { + fs::write(summary, summary_new).wrap_err("writing SUMAMRY.md")?; + } + + Ok(()) +} + +impl TargetInfo { + fn has_host_tools(&self) -> bool { + self.metadata.host_tools.unwrap_or(false) + } +} + +fn render_platform_support_tables(content: &str, targets: &[TargetInfo]) -> Result { + let replace_table = |content, name, tier_table| -> Result { + let section_string = render_table(targets, tier_table)?; + replace_section(content, name, §ion_string).wrap_err("replacing platform support.md") + }; + + let content = replace_table( + content, + "TIER1HOST", + TierTable { + filter: |target| target.metadata.tier == Some(1), + include_host: false, + include_std: false, + }, + )?; + let content = replace_table( + &content, + "TIER2HOST", + TierTable { + filter: |target| target.metadata.tier == Some(2) && target.has_host_tools(), + include_host: false, + include_std: false, + }, + )?; + let content = replace_table( + &content, + "TIER2", + TierTable { + filter: |target| target.metadata.tier == Some(2) && !target.has_host_tools(), + include_host: false, + include_std: true, + }, + )?; + let content = replace_table( + &content, + "TIER3", + TierTable { + filter: |target| target.metadata.tier == Some(3), + include_host: true, + include_std: true, + }, + )?; + + Ok(content) +} + +fn render_table_option_bool(bool: Option) -> &'static str { + match bool { + Some(true) => "✓", + Some(false) => " ", + None => "?", + } +} + +struct TierTable { + filter: fn(&TargetInfo) -> bool, + include_std: bool, + include_host: bool, +} + +fn render_table(targets: &[TargetInfo], table: TierTable) -> Result { + let mut rows = Vec::new(); + + let targets = targets.iter().filter(|target| (table.filter)(target)); + + for target in targets { + let meta = &target.metadata; + + let mut notes = meta.description.as_deref().unwrap_or("unknown").to_owned(); + + if !target.footnotes.is_empty() { + let footnotes_str = target + .footnotes + .iter() + .map(|footnote| format!("[^{}]", footnote)) + .collect::>() + .join(" "); + + notes = format!("{notes} {footnotes_str}"); + } + + let std = if table.include_std { + let std = render_table_option_bool(meta.std); + format!(" | {std}") + } else { + String::new() + }; + + let host = if table.include_host { + let host = render_table_option_bool(meta.host_tools); + format!(" | {host}") + } else { + String::new() + }; + + rows.push(format!( + "[`{0}`](platform-support/targets/{0}.md){std}{host} | {notes}", + target.name + )); + } + + let result = rows.join("\n"); + + Ok(result) +} From 7967915c7b456d59fd963260822d3cf583969948 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Fri, 15 Mar 2024 19:45:46 +0000 Subject: [PATCH 10/13] CFI: Use Instance at callsites We already use `Instance` at declaration sites when available to glean additional information about possible abstractions of the type in use. This does the same when possible at callsites as well. The primary purpose of this change is to allow CFI to alter how it generates type information for indirect calls through `Virtual` instances. --- compiler/rustc_codegen_gcc/src/asm.rs | 2 +- compiler/rustc_codegen_gcc/src/builder.rs | 6 ++- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 11 ++--- compiler/rustc_codegen_llvm/src/asm.rs | 6 +-- compiler/rustc_codegen_llvm/src/builder.rs | 41 +++++++++++++------ compiler/rustc_codegen_llvm/src/intrinsic.rs | 39 ++++++++++-------- compiler/rustc_codegen_ssa/src/base.rs | 19 ++++++--- compiler/rustc_codegen_ssa/src/mir/block.rs | 19 ++++++--- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- compiler/rustc_codegen_ssa/src/size_of_val.rs | 10 ++++- .../rustc_codegen_ssa/src/traits/builder.rs | 4 +- 11 files changed, 105 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 9b679019e96ce..06b14a1f118a3 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -541,7 +541,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) }; - self.call(self.type_void(), None, None, builtin_unreachable, &[], None); + self.call(self.type_void(), None, None, builtin_unreachable, &[], None, None); } // Write results to outputs. diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index f5cda81f6ab86..43cc46cfe682f 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -25,7 +25,7 @@ use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout, }; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Instance}; use rustc_span::def_id::DefId; use rustc_span::Span; use rustc_target::abi::{ @@ -592,12 +592,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>, + instance: Option>, ) -> RValue<'gcc> { let try_block = self.current_func().new_block("try"); let current_block = self.block.clone(); self.block = try_block; - let call = self.call(typ, fn_attrs, None, func, args, None); // TODO(antoyo): use funclet here? + let call = self.call(typ, fn_attrs, None, func, args, None, instance); // TODO(antoyo): use funclet here? self.block = current_block; let return_value = @@ -1667,6 +1668,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { func: RValue<'gcc>, args: &[RValue<'gcc>], funclet: Option<&Funclet>, + _instance: Option>, ) -> RValue<'gcc> { // FIXME(antoyo): remove when having a proper API. let gcc_func = unsafe { std::mem::transmute(func) }; diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index a6c8b72e851b2..cebd45c09aa39 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -133,6 +133,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { func, &args.iter().map(|arg| arg.immediate()).collect::>(), None, + None, ) } sym::likely => self.expect(args[0].immediate(), true), @@ -401,7 +402,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { fn abort(&mut self) { let func = self.context.get_builtin_function("abort"); let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; - self.call(self.type_void(), None, None, func, &[], None); + self.call(self.type_void(), None, None, func, &[], None, None); } fn assume(&mut self, value: Self::Value) { @@ -1103,7 +1104,7 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( dest: RValue<'gcc>, ) { if bx.sess().panic_strategy() == PanicStrategy::Abort { - bx.call(bx.type_void(), None, None, try_func, &[data], None); + bx.call(bx.type_void(), None, None, try_func, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. let ret_align = bx.tcx.data_layout.i32_align.abi; @@ -1177,21 +1178,21 @@ fn codegen_gnu_try<'gcc>( let zero = bx.cx.context.new_rvalue_zero(bx.int_type); let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]); let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], None); + bx.call(catch_ty, None, None, catch_func, &[data, ptr], None, None); bx.ret(bx.const_i32(1)); // NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not // generate a try/catch. // FIXME(antoyo): add a check in the libgccjit API to prevent this. bx.switch_to_block(current_block); - bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None); + bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None); }); let func = unsafe { std::mem::transmute(func) }; // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None); + let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None, None); let i32_align = bx.tcx().data_layout.i32_align.abi; bx.store(ret, dest, i32_align); } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 74539d4d49570..500904ce18805 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -466,11 +466,11 @@ pub(crate) fn inline_asm_call<'ll>( let call = if !labels.is_empty() { assert!(catch_funclet.is_none()); - bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None) + bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) } else if let Some((catch, funclet)) = catch_funclet { - bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet) + bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None) } else { - bx.call(fty, None, None, v, inputs, None) + bx.call(fty, None, None, v, inputs, None, None) }; // Store mark in a metadata node so we can map LLVM errors diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 63e59ea13fc35..a5a5ae73d77a1 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -19,9 +19,12 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout, }; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_span::Span; -use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi, TypeIdOptions}; +use rustc_symbol_mangling::typeid::{ + kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance, + TypeIdOptions, +}; use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange}; use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target}; use smallvec::SmallVec; @@ -221,6 +224,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { then: &'ll BasicBlock, catch: &'ll BasicBlock, funclet: Option<&Funclet<'ll>>, + instance: Option>, ) -> &'ll Value { debug!("invoke {:?} with args ({:?})", llfn, args); @@ -233,10 +237,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } // Emit CFI pointer type membership test - self.cfi_type_test(fn_attrs, fn_abi, llfn); + self.cfi_type_test(fn_attrs, fn_abi, instance, llfn); // Emit KCFI operand bundle - let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn); + let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); if let Some(kcfi_bundle) = kcfi_bundle { bundles.push(kcfi_bundle); @@ -1231,6 +1235,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { llfn: &'ll Value, args: &[&'ll Value], funclet: Option<&Funclet<'ll>>, + instance: Option>, ) -> &'ll Value { debug!("call {:?} with args ({:?})", llfn, args); @@ -1243,10 +1248,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } // Emit CFI pointer type membership test - self.cfi_type_test(fn_attrs, fn_abi, llfn); + self.cfi_type_test(fn_attrs, fn_abi, instance, llfn); // Emit KCFI operand bundle - let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn); + let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); if let Some(kcfi_bundle) = kcfi_bundle { bundles.push(kcfi_bundle); @@ -1468,7 +1473,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value { let (ty, f) = self.cx.get_intrinsic(intrinsic); - self.call(ty, None, None, f, args, None) + self.call(ty, None, None, f, args, None, None) } fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) { @@ -1526,7 +1531,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { format!("llvm.{instr}.sat.i{int_width}.f{float_width}") }; let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty)); - self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None) + self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None, None) } pub(crate) fn landing_pad( @@ -1554,6 +1559,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { default_dest: &'ll BasicBlock, indirect_dest: &[&'ll BasicBlock], funclet: Option<&Funclet<'ll>>, + instance: Option>, ) -> &'ll Value { debug!("invoke {:?} with args ({:?})", llfn, args); @@ -1566,10 +1572,10 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } // Emit CFI pointer type membership test - self.cfi_type_test(fn_attrs, fn_abi, llfn); + self.cfi_type_test(fn_attrs, fn_abi, instance, llfn); // Emit KCFI operand bundle - let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn); + let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); if let Some(kcfi_bundle) = kcfi_bundle { bundles.push(kcfi_bundle); @@ -1601,6 +1607,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { &mut self, fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, + instance: Option>, llfn: &'ll Value, ) { let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) }; @@ -1622,7 +1629,11 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { options.insert(TypeIdOptions::NORMALIZE_INTEGERS); } - let typeid = typeid_for_fnabi(self.tcx, fn_abi, options); + let typeid = if let Some(instance) = instance { + typeid_for_instance(self.tcx, &instance, options) + } else { + typeid_for_fnabi(self.tcx, fn_abi, options) + }; let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap(); // Test whether the function pointer is associated with the type identifier. @@ -1644,6 +1655,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { &mut self, fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, + instance: Option>, llfn: &'ll Value, ) -> Option> { let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) }; @@ -1665,7 +1677,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { options.insert(TypeIdOptions::NORMALIZE_INTEGERS); } - let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options); + let kcfi_typeid = if let Some(instance) = instance { + kcfi_typeid_for_instance(self.tcx, &instance, options) + } else { + kcfi_typeid_for_fnabi(self.tcx, fn_abi, options) + }; + Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)])) } else { None diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 2409b2e78d736..ab135e3ed6444 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -181,6 +181,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { simple_fn, &args.iter().map(|arg| arg.immediate()).collect::>(), None, + Some(instance), ) } sym::likely => { @@ -539,7 +540,7 @@ fn catch_unwind_intrinsic<'ll>( ) { if bx.sess().panic_strategy() == PanicStrategy::Abort { let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.call(try_func_ty, None, None, try_func, &[data], None); + bx.call(try_func_ty, None, None, try_func, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. let ret_align = bx.tcx().data_layout.i32_align.abi; @@ -640,7 +641,7 @@ fn codegen_msvc_try<'ll>( let ptr_align = bx.tcx().data_layout.pointer_align.abi; let slot = bx.alloca(bx.type_ptr(), ptr_align); let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None); + bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None); bx.switch_to_block(normal); bx.ret(bx.const_i32(0)); @@ -684,7 +685,7 @@ fn codegen_msvc_try<'ll>( let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]); let ptr = bx.load(bx.type_ptr(), slot, ptr_align); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet)); + bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None); bx.catch_ret(&funclet, caught); // The flag value of 64 indicates a "catch-all". @@ -692,7 +693,7 @@ fn codegen_msvc_try<'ll>( let flags = bx.const_i32(64); let null = bx.const_null(bx.type_ptr()); let funclet = bx.catch_pad(cs, &[null, flags, null]); - bx.call(catch_ty, None, None, catch_func, &[data, null], Some(&funclet)); + bx.call(catch_ty, None, None, catch_func, &[data, null], Some(&funclet), None); bx.catch_ret(&funclet, caught); bx.switch_to_block(caught); @@ -701,7 +702,7 @@ fn codegen_msvc_try<'ll>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None); + let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); let i32_align = bx.tcx().data_layout.i32_align.abi; bx.store(ret, dest, i32_align); } @@ -750,7 +751,7 @@ fn codegen_wasm_try<'ll>( // } // let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None); + bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None); bx.switch_to_block(normal); bx.ret(bx.const_i32(0)); @@ -766,7 +767,7 @@ fn codegen_wasm_try<'ll>( let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[funclet.cleanuppad()]); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet)); + bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None); bx.catch_ret(&funclet, caught); bx.switch_to_block(caught); @@ -775,7 +776,7 @@ fn codegen_wasm_try<'ll>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None); + let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); let i32_align = bx.tcx().data_layout.i32_align.abi; bx.store(ret, dest, i32_align); } @@ -818,7 +819,7 @@ fn codegen_gnu_try<'ll>( let data = llvm::get_param(bx.llfn(), 1); let catch_func = llvm::get_param(bx.llfn(), 2); let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None); + bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None); bx.switch_to_block(then); bx.ret(bx.const_i32(0)); @@ -836,13 +837,13 @@ fn codegen_gnu_try<'ll>( bx.add_clause(vals, tydesc); let ptr = bx.extract_value(vals, 0); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], None); + bx.call(catch_ty, None, None, catch_func, &[data, ptr], None, None); bx.ret(bx.const_i32(1)); }); // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None); + let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); let i32_align = bx.tcx().data_layout.i32_align.abi; bx.store(ret, dest, i32_align); } @@ -882,7 +883,7 @@ fn codegen_emcc_try<'ll>( let data = llvm::get_param(bx.llfn(), 1); let catch_func = llvm::get_param(bx.llfn(), 2); let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None); + bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None); bx.switch_to_block(then); bx.ret(bx.const_i32(0)); @@ -920,13 +921,13 @@ fn codegen_emcc_try<'ll>( bx.store(is_rust_panic, catch_data_1, i8_align); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, catch_data], None); + bx.call(catch_ty, None, None, catch_func, &[data, catch_data], None, None); bx.ret(bx.const_i32(1)); }); // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None); + let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); let i32_align = bx.tcx().data_layout.i32_align.abi; bx.store(ret, dest, i32_align); } @@ -1439,6 +1440,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( f, &args.iter().map(|arg| arg.immediate()).collect::>(), None, + None, ); Ok(c) } @@ -1607,6 +1609,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( f, &[args[1].immediate(), alignment, mask, args[0].immediate()], None, + None, ); return Ok(v); } @@ -1706,6 +1709,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( f, &[args[1].immediate(), alignment, mask, args[2].immediate()], None, + None, ); return Ok(v); } @@ -1799,6 +1803,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( f, &[args[2].immediate(), args[1].immediate(), alignment, mask], None, + None, ); return Ok(v); } @@ -1904,6 +1909,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( f, &[args[0].immediate(), args[1].immediate(), alignment, mask], None, + None, ); return Ok(v); } @@ -2352,11 +2358,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>( f, &[args[0].immediate(), bx.const_int(bx.type_i1(), 0)], None, + None, )) } else { let fn_ty = bx.type_func(&[vec_ty], vec_ty); let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None)) + Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None, None)) }; } @@ -2409,7 +2416,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty); let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); - let v = bx.call(fn_ty, None, None, f, &[lhs, rhs], None); + let v = bx.call(fn_ty, None, None, f, &[lhs, rhs], None, None); return Ok(v); } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 13809ef72ec7b..f7f2bfca838ea 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -462,27 +462,34 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let ptr_ty = cx.type_ptr(); let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx); - let (start_fn, start_ty, args) = if let EntryFnType::Main { sigpipe } = entry_type { + let (start_fn, start_ty, args, instance) = if let EntryFnType::Main { sigpipe } = entry_type + { let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None); - let start_fn = cx.get_fn_addr(ty::Instance::expect_resolve( + let start_instance = ty::Instance::expect_resolve( cx.tcx(), ty::ParamEnv::reveal_all(), start_def_id, cx.tcx().mk_args(&[main_ret_ty.into()]), - )); + ); + let start_fn = cx.get_fn_addr(start_instance); let i8_ty = cx.type_i8(); let arg_sigpipe = bx.const_u8(sigpipe); let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, ptr_ty, i8_ty], isize_ty); - (start_fn, start_ty, vec![rust_main, arg_argc, arg_argv, arg_sigpipe]) + ( + start_fn, + start_ty, + vec![rust_main, arg_argc, arg_argv, arg_sigpipe], + Some(start_instance), + ) } else { debug!("using user-defined start fn"); let start_ty = cx.type_func(&[isize_ty, ptr_ty], isize_ty); - (rust_main, start_ty, vec![arg_argc, arg_argv]) + (rust_main, start_ty, vec![arg_argc, arg_argv], None) }; - let result = bx.call(start_ty, None, None, start_fn, &args, None); + let result = bx.call(start_ty, None, None, start_fn, &args, None, instance); if cx.sess().target.os.contains("uefi") { bx.ret(result); } else { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index dcc27a4f0e568..8c668597a43b3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -232,6 +232,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { ret_llbb, unwind_block, self.funclet(fx), + instance, ); if fx.mir[self.bb].is_cleanup { bx.apply_attrs_to_cleanup_callsite(invokeret); @@ -247,7 +248,8 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } MergingSucc::False } else { - let llret = bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx)); + let llret = + bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx), instance); if fx.mir[self.bb].is_cleanup { bx.apply_attrs_to_cleanup_callsite(llret); } @@ -502,7 +504,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = location.ty(self.mir, bx.tcx()).ty; let ty = self.monomorphize(ty); let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty); - let instance = drop_fn.clone(); if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { // we don't actually need to drop anything. @@ -518,7 +519,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args1 = [place.llval]; &args1[..] }; - let (drop_fn, fn_abi) = + let (drop_fn, fn_abi, drop_instance) = match ty.kind() { // FIXME(eddyb) perhaps move some of this logic into // `Instance::resolve_drop_in_place`? @@ -550,6 +551,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) .get_fn(bx, vtable, ty, fn_abi), fn_abi, + virtual_drop, ) } ty::Dynamic(_, _, ty::DynStar) => { @@ -592,9 +594,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) .get_fn(bx, meta.immediate(), ty, fn_abi), fn_abi, + virtual_drop, ) } - _ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())), + _ => ( + bx.get_fn_addr(drop_fn), + bx.fn_abi_of_instance(drop_fn, ty::List::empty()), + drop_fn, + ), }; helper.do_call( self, @@ -605,7 +612,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some((ReturnDest::Nothing, target)), unwind, &[], - Some(instance), + Some(drop_instance), mergeable_succ, ) } @@ -1699,7 +1706,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { let fn_ty = bx.fn_decl_backend_type(fn_abi); - let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref()); + let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref(), None); bx.apply_attrs_to_cleanup_callsite(llret); } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 15f2e0e56d86d..8abbbe2bfb9e0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -710,7 +710,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { None }; - bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None) + bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None, Some(instance)) } else { bx.get_static(def_id) }; diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index e2e95cede60a5..c250cc2682323 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -70,7 +70,15 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // (But we are in good company, this code is duplicated plenty of times.) let fn_ty = bx.fn_decl_backend_type(fn_abi); - bx.call(fn_ty, /* fn_attrs */ None, Some(fn_abi), llfn, &[msg.0, msg.1], None); + bx.call( + fn_ty, + /* fn_attrs */ None, + Some(fn_abi), + llfn, + &[msg.0, msg.1], + None, + None, + ); // This function does not return so we can now return whatever we want. let size = bx.const_usize(layout.size.bytes()); diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 7bc9dee3a8955..6c8dcc5b69001 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -17,7 +17,7 @@ use crate::MemFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{Instance, Ty}; use rustc_session::config::OptLevel; use rustc_span::Span; use rustc_target::abi::call::FnAbi; @@ -82,6 +82,7 @@ pub trait BuilderMethods<'a, 'tcx>: then: Self::BasicBlock, catch: Self::BasicBlock, funclet: Option<&Self::Funclet>, + instance: Option>, ) -> Self::Value; fn unreachable(&mut self); @@ -389,6 +390,7 @@ pub trait BuilderMethods<'a, 'tcx>: llfn: Self::Value, args: &[Self::Value], funclet: Option<&Self::Funclet>, + instance: Option>, ) -> Self::Value; fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; From f434c27067085d72c7770da3b6d4e0bc316fd267 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Fri, 15 Mar 2024 18:44:40 +0000 Subject: [PATCH 11/13] CFI: Strip auto traits off Self for virtual calls Additional trait bounds beyond the principal trait and its implications are not possible in the vtable. This means that if a receiver is `&dyn Foo + Send`, the function will only be expecting `&dyn Foo`. This strips those auto traits off before CFI encoding. --- compiler/rustc_symbol_mangling/src/typeid.rs | 4 +-- .../src/typeid/typeid_itanium_cxx_abi.rs | 28 +++++++++++++++++-- tests/ui/sanitizer/cfi-virtual-auto.rs | 22 +++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 tests/ui/sanitizer/cfi-virtual-auto.rs diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs index e8763e49e624b..3bf564a4a16dd 100644 --- a/compiler/rustc_symbol_mangling/src/typeid.rs +++ b/compiler/rustc_symbol_mangling/src/typeid.rs @@ -36,7 +36,7 @@ pub fn typeid_for_instance<'tcx>( instance: &Instance<'tcx>, options: TypeIdOptions, ) -> String { - typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options) + typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options) } /// Returns a KCFI type metadata identifier for the specified FnAbi. @@ -61,6 +61,6 @@ pub fn kcfi_typeid_for_instance<'tcx>( // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) let mut hash: XxHash64 = Default::default(); - hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes()); + hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options).as_bytes()); hash.finish() as u32 } diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 07a382d161d74..813d641995531 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -1088,11 +1088,15 @@ pub fn typeid_for_fnabi<'tcx>( /// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary. pub fn typeid_for_instance<'tcx>( tcx: TyCtxt<'tcx>, - instance: &Instance<'tcx>, + mut instance: Instance<'tcx>, options: TypeIdOptions, ) -> String { + if matches!(instance.def, ty::InstanceDef::Virtual(..)) { + instance.args = strip_receiver_auto(tcx, instance.args) + } + let fn_abi = tcx - .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, ty::List::empty()))) + .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty()))) .unwrap_or_else(|instance| { bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance) }); @@ -1138,3 +1142,23 @@ pub fn typeid_for_instance<'tcx>( typeid_for_fnabi(tcx, fn_abi, options) } + +fn strip_receiver_auto<'tcx>( + tcx: TyCtxt<'tcx>, + args: ty::GenericArgsRef<'tcx>, +) -> ty::GenericArgsRef<'tcx> { + let ty = args.type_at(0); + let ty::Dynamic(preds, lifetime, kind) = ty.kind() else { + bug!("Tried to strip auto traits from non-dynamic type {ty}"); + }; + let filtered_preds = + if preds.principal().is_some() { + tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| { + !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..)) + })) + } else { + ty::List::empty() + }; + let new_rcvr = Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind); + tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1)) +} diff --git a/tests/ui/sanitizer/cfi-virtual-auto.rs b/tests/ui/sanitizer/cfi-virtual-auto.rs new file mode 100644 index 0000000000000..7a0c246a41221 --- /dev/null +++ b/tests/ui/sanitizer/cfi-virtual-auto.rs @@ -0,0 +1,22 @@ +// Tests that calling a trait object method on a trait object with additional auto traits works. + +//@ needs-sanitizer-cfi +// FIXME(#122848) Remove only-linux once OSX CFI binaries work +//@ only-linux +//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi +//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0 +//@ run-pass + +trait Foo { + fn foo(&self); +} + +struct Bar; +impl Foo for Bar { + fn foo(&self) {} +} + +pub fn main() { + let x: &(dyn Foo + Send) = &Bar; + x.foo(); +} From b6b5745c3f7d2bff02738782a618fdb9e5922243 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Fri, 22 Mar 2024 17:43:53 -0700 Subject: [PATCH 12/13] In `pretty_print_type()`, print `async fn` futures' paths instead of spans. This makes `-Zprint-type-sizes`'s output easier to read, because the name of an `async fn` is more immediately recognizable than its span. I also deleted the comment "FIXME(eddyb) should use `def_span`." because it appears to have already been fixed by commit 67727aa7c31a24ea73a91a9134c3653fae8209ab. --- compiler/rustc_middle/src/ty/print/pretty.rs | 18 ++++-- ...await.a-{closure#0}.coroutine_resume.0.mir | 6 +- ...await.b-{closure#0}.coroutine_resume.0.mir | 62 +++++++++---------- .../future-sizes/async-awaiting-fut.stdout | 28 ++++----- .../async-await/future-sizes/large-arg.stdout | 26 ++++---- .../trait-bounds/future.current.stderr | 2 +- tests/ui/print_type_sizes/async.stdout | 10 +-- .../hkl_forbidden4.stderr | 2 +- 8 files changed, 81 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 3f0a3a1a7bfb1..914b19efc7e85 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -804,7 +804,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } ty::Str => p!("str"), ty::Coroutine(did, args) => { - p!(write("{{")); + p!("{{"); let coroutine_kind = self.tcx().coroutine_kind(did).unwrap(); let should_print_movability = self.should_print_verbose() || matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_)); @@ -818,9 +818,17 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { if !self.should_print_verbose() { p!(write("{}", coroutine_kind)); - // FIXME(eddyb) should use `def_span`. - if let Some(did) = did.as_local() { - let span = self.tcx().def_span(did); + if coroutine_kind.is_fn_like() { + // If we are printing an `async fn` coroutine type, then give the path + // of the fn, instead of its span, because that will in most cases be + // more helpful for the reader than just a source location. + // + // This will look like: + // {async fn body of some_fn()} + let did_of_the_fn_item = self.tcx().parent(did); + p!(" of ", print_def_path(did_of_the_fn_item, args), "()"); + } else if let Some(local_did) = did.as_local() { + let span = self.tcx().def_span(local_did); p!(write( "@{}", // This may end up in stderr diagnostics but it may also be emitted @@ -828,7 +836,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { self.tcx().sess.source_map().span_to_embeddable_string(span) )); } else { - p!(write("@"), print_def_path(did, args)); + p!("@", print_def_path(did, args)); } } else { p!(print_def_path(did, args)); diff --git a/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir index 8b22743d2b066..7480324b17791 100644 --- a/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir @@ -9,7 +9,7 @@ storage_conflicts: BitMatrix(0x0) {}, } */ -fn a::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}>, _2: &mut Context<'_>) -> Poll<()> { +fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) -> Poll<()> { debug _task_context => _4; let mut _0: std::task::Poll<()>; let mut _3: (); @@ -17,7 +17,7 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}> let mut _5: u32; bb0: { - _5 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}))); + _5 = discriminant((*(_1.0: &mut {async fn body of a()}))); switchInt(move _5) -> [0: bb1, 1: bb4, otherwise: bb5]; } @@ -29,7 +29,7 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}> bb2: { _0 = Poll::<()>::Ready(move _3); - discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}))) = 1; + discriminant((*(_1.0: &mut {async fn body of a()}))) = 1; return; } diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir index 2f7c4f7d40221..d697ea4923167 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir @@ -51,19 +51,19 @@ }, } */ -fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, _2: &mut Context<'_>) -> Poll<()> { +fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> Poll<()> { debug _task_context => _38; let mut _0: std::task::Poll<()>; let _3: (); - let mut _4: {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _5: {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _6: {async fn body@$DIR/async_await.rs:12:14: 12:16}; + let mut _4: {async fn body of a()}; + let mut _5: {async fn body of a()}; + let mut _6: {async fn body of a()}; let mut _7: (); let _8: (); let mut _9: std::task::Poll<()>; - let mut _10: std::pin::Pin<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}>; - let mut _11: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _12: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}; + let mut _10: std::pin::Pin<&mut {async fn body of a()}>; + let mut _11: &mut {async fn body of a()}; + let mut _12: &mut {async fn body of a()}; let mut _13: &mut std::task::Context<'_>; let mut _14: &mut std::task::Context<'_>; let mut _15: &mut std::task::Context<'_>; @@ -71,14 +71,14 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, let mut _18: !; let mut _19: &mut std::task::Context<'_>; let mut _20: (); - let mut _21: {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _22: {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _23: {async fn body@$DIR/async_await.rs:12:14: 12:16}; + let mut _21: {async fn body of a()}; + let mut _22: {async fn body of a()}; + let mut _23: {async fn body of a()}; let _24: (); let mut _25: std::task::Poll<()>; - let mut _26: std::pin::Pin<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}>; - let mut _27: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _28: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}; + let mut _26: std::pin::Pin<&mut {async fn body of a()}>; + let mut _27: &mut {async fn body of a()}; + let mut _28: &mut {async fn body of a()}; let mut _29: &mut std::task::Context<'_>; let mut _30: &mut std::task::Context<'_>; let mut _31: &mut std::task::Context<'_>; @@ -90,7 +90,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, let mut _38: &mut std::task::Context<'_>; let mut _39: u32; scope 1 { - debug __awaitee => (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#3).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}); + debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()}); let _17: (); scope 2 { } @@ -99,7 +99,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, } } scope 4 { - debug __awaitee => (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#4).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}); + debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()}); let _33: (); scope 5 { } @@ -109,7 +109,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, } bb0: { - _39 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2}))); + _39 = discriminant((*(_1.0: &mut {async fn body of b()}))); switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb8]; } @@ -122,14 +122,14 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, } bb2: { - _4 = <{async fn body@$DIR/async_await.rs:12:14: 12:16} as IntoFuture>::into_future(move _5) -> [return: bb3, unwind unreachable]; + _4 = <{async fn body of a()} as IntoFuture>::into_future(move _5) -> [return: bb3, unwind unreachable]; } bb3: { StorageDead(_5); PlaceMention(_4); nop; - (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#3).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}) = move _4; + (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()}) = move _4; goto -> bb4; } @@ -139,9 +139,9 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageLive(_10); StorageLive(_11); StorageLive(_12); - _12 = &mut (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#3).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}); + _12 = &mut (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()}); _11 = &mut (*_12); - _10 = Pin::<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}>::new_unchecked(move _11) -> [return: bb5, unwind unreachable]; + _10 = Pin::<&mut {async fn body of a()}>::new_unchecked(move _11) -> [return: bb5, unwind unreachable]; } bb5: { @@ -157,7 +157,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb6: { _13 = &mut (*_14); StorageDead(_15); - _9 = <{async fn body@$DIR/async_await.rs:12:14: 12:16} as Future>::poll(move _10, move _13) -> [return: bb7, unwind unreachable]; + _9 = <{async fn body of a()} as Future>::poll(move _10, move _13) -> [return: bb7, unwind unreachable]; } bb7: { @@ -186,7 +186,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageDead(_4); StorageDead(_19); StorageDead(_20); - discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2}))) = 3; + discriminant((*(_1.0: &mut {async fn body of b()}))) = 3; return; } @@ -199,7 +199,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageDead(_12); StorageDead(_9); StorageDead(_8); - drop((((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#3).0: {async fn body@$DIR/async_await.rs:12:14: 12:16})) -> [return: bb12, unwind unreachable]; + drop((((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()})) -> [return: bb12, unwind unreachable]; } bb11: { @@ -224,14 +224,14 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, } bb14: { - _21 = <{async fn body@$DIR/async_await.rs:12:14: 12:16} as IntoFuture>::into_future(move _22) -> [return: bb15, unwind unreachable]; + _21 = <{async fn body of a()} as IntoFuture>::into_future(move _22) -> [return: bb15, unwind unreachable]; } bb15: { StorageDead(_22); PlaceMention(_21); nop; - (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#4).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}) = move _21; + (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()}) = move _21; goto -> bb16; } @@ -241,9 +241,9 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageLive(_26); StorageLive(_27); StorageLive(_28); - _28 = &mut (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#4).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}); + _28 = &mut (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()}); _27 = &mut (*_28); - _26 = Pin::<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}>::new_unchecked(move _27) -> [return: bb17, unwind unreachable]; + _26 = Pin::<&mut {async fn body of a()}>::new_unchecked(move _27) -> [return: bb17, unwind unreachable]; } bb17: { @@ -259,7 +259,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb18: { _29 = &mut (*_30); StorageDead(_31); - _25 = <{async fn body@$DIR/async_await.rs:12:14: 12:16} as Future>::poll(move _26, move _29) -> [return: bb19, unwind unreachable]; + _25 = <{async fn body of a()} as Future>::poll(move _26, move _29) -> [return: bb19, unwind unreachable]; } bb19: { @@ -283,7 +283,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageDead(_21); StorageDead(_35); StorageDead(_36); - discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2}))) = 4; + discriminant((*(_1.0: &mut {async fn body of b()}))) = 4; return; } @@ -296,7 +296,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageDead(_28); StorageDead(_25); StorageDead(_24); - drop((((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#4).0: {async fn body@$DIR/async_await.rs:12:14: 12:16})) -> [return: bb23, unwind unreachable]; + drop((((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()})) -> [return: bb23, unwind unreachable]; } bb22: { @@ -319,7 +319,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb25: { _0 = Poll::<()>::Ready(move _37); - discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2}))) = 1; + discriminant((*(_1.0: &mut {async fn body of b()}))) = 1; return; } diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout index d6fb643702c56..def967ba195ef 100644 --- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout +++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout @@ -1,17 +1,17 @@ -print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:21:21: 24:2}`: 3078 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of test()}`: 3078 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Suspend0`: 3077 bytes -print-type-size local `.__awaitee`: 3077 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2} +print-type-size local `.__awaitee`: 3077 bytes, type: {async fn body of calls_fut<{async fn body of big_fut()}>()} print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}>`: 3077 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes print-type-size field `.value`: 3077 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}>`: 3077 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 3077 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 3077 bytes -print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}`: 3077 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of calls_fut<{async fn body of big_fut()}>()}`: 3077 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 1025 bytes print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes @@ -20,29 +20,29 @@ print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 print-type-size padding: 1 bytes print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes print-type-size local `..coroutine_field4`: 1 bytes, type: bool -print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19} +print-type-size local `.__awaitee`: 1 bytes, type: {async fn body of wait()} print-type-size variant `Suspend1`: 3076 bytes print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes print-type-size padding: 1026 bytes print-type-size local `..coroutine_field4`: 1 bytes, alignment: 1 bytes, type: bool -print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37} +print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body of big_fut()} print-type-size variant `Suspend2`: 2052 bytes print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes print-type-size padding: 1 bytes print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes print-type-size local `..coroutine_field4`: 1 bytes, type: bool -print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19} +print-type-size local `.__awaitee`: 1 bytes, type: {async fn body of wait()} print-type-size variant `Returned`: 1025 bytes print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes print-type-size variant `Panicked`: 1025 bytes print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37}>`: 1025 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes print-type-size field `.value`: 1025 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37}>`: 1025 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1025 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1025 bytes -print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37}`: 1025 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of big_fut()}`: 1025 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 1024 bytes print-type-size upvar `.arg`: 1024 bytes @@ -52,13 +52,13 @@ print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.arg`: 1024 bytes print-type-size type: `std::mem::ManuallyDrop`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::MaybeUninit`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1 bytes @@ -67,7 +67,7 @@ print-type-size discriminant: 1 bytes print-type-size variant `Ready`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Pending`: 0 bytes -print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}`: 1 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of wait()}`: 1 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Returned`: 0 bytes diff --git a/tests/ui/async-await/future-sizes/large-arg.stdout b/tests/ui/async-await/future-sizes/large-arg.stdout index 589df102af4bd..67168a3d6ef74 100644 --- a/tests/ui/async-await/future-sizes/large-arg.stdout +++ b/tests/ui/async-await/future-sizes/large-arg.stdout @@ -1,47 +1,47 @@ -print-type-size type: `{async fn body@$DIR/large-arg.rs:6:21: 8:2}`: 3076 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of test()}`: 3076 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Suspend0`: 3075 bytes -print-type-size local `.__awaitee`: 3075 bytes, type: {async fn body@$DIR/large-arg.rs:10:30: 12:2} +print-type-size local `.__awaitee`: 3075 bytes, type: {async fn body of a<[u8; 1024]>()} print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/large-arg.rs:10:30: 12:2}>`: 3075 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes print-type-size field `.value`: 3075 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/large-arg.rs:10:30: 12:2}>`: 3075 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 3075 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 3075 bytes -print-type-size type: `{async fn body@$DIR/large-arg.rs:10:30: 12:2}`: 3075 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of a<[u8; 1024]>()}`: 3075 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size variant `Suspend0`: 3074 bytes print-type-size upvar `.t`: 1024 bytes -print-type-size local `.__awaitee`: 2050 bytes, type: {async fn body@$DIR/large-arg.rs:13:26: 15:2} +print-type-size local `.__awaitee`: 2050 bytes, type: {async fn body of b<[u8; 1024]>()} print-type-size variant `Returned`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.t`: 1024 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/large-arg.rs:13:26: 15:2}>`: 2050 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes print-type-size field `.value`: 2050 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/large-arg.rs:13:26: 15:2}>`: 2050 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 2050 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 2050 bytes -print-type-size type: `{async fn body@$DIR/large-arg.rs:13:26: 15:2}`: 2050 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of b<[u8; 1024]>()}`: 2050 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size variant `Suspend0`: 2049 bytes print-type-size upvar `.t`: 1024 bytes -print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/large-arg.rs:16:26: 18:2} +print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body of c<[u8; 1024]>()} print-type-size variant `Returned`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.t`: 1024 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/large-arg.rs:16:26: 18:2}>`: 1025 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes print-type-size field `.value`: 1025 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/large-arg.rs:16:26: 18:2}>`: 1025 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1025 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1025 bytes @@ -50,7 +50,7 @@ print-type-size discriminant: 1 bytes print-type-size variant `Ready`: 1024 bytes print-type-size field `.0`: 1024 bytes print-type-size variant `Pending`: 0 bytes -print-type-size type: `{async fn body@$DIR/large-arg.rs:16:26: 18:2}`: 1025 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of c<[u8; 1024]>()}`: 1025 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 1024 bytes print-type-size upvar `.t`: 1024 bytes diff --git a/tests/ui/higher-ranked/trait-bounds/future.current.stderr b/tests/ui/higher-ranked/trait-bounds/future.current.stderr index 5a6381ad28eb3..673bc48a424e7 100644 --- a/tests/ui/higher-ranked/trait-bounds/future.current.stderr +++ b/tests/ui/higher-ranked/trait-bounds/future.current.stderr @@ -1,6 +1,6 @@ error: the compiler unexpectedly panicked. this is a bug. query stack during panic: -#0 [evaluate_obligation] evaluating trait selection obligation `for<'a> {async fn body@$DIR/future.rs:33:35: 35:2}: core::future::future::Future` +#0 [evaluate_obligation] evaluating trait selection obligation `for<'a> {async fn body of strlen()}: core::future::future::Future` #1 [codegen_select_candidate] computing candidate for `` end of query stack diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout index 1df4d85d09e33..83a6962e4cd13 100644 --- a/tests/ui/print_type_sizes/async.stdout +++ b/tests/ui/print_type_sizes/async.stdout @@ -1,11 +1,11 @@ -print-type-size type: `{async fn body@$DIR/async.rs:10:36: 13:2}`: 16386 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of test()}`: 16386 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 8192 bytes print-type-size upvar `.arg`: 8192 bytes print-type-size variant `Suspend0`: 16385 bytes print-type-size upvar `.arg`: 8192 bytes print-type-size local `.arg`: 8192 bytes -print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async.rs:8:17: 8:19} +print-type-size local `.__awaitee`: 1 bytes, type: {async fn body of wait()} print-type-size variant `Returned`: 8192 bytes print-type-size upvar `.arg`: 8192 bytes print-type-size variant `Panicked`: 8192 bytes @@ -16,9 +16,9 @@ print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment print-type-size variant `MaybeUninit`: 8192 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 8192 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async.rs:8:17: 8:19}>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/async.rs:8:17: 8:19}>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1 bytes @@ -27,7 +27,7 @@ print-type-size discriminant: 1 bytes print-type-size variant `Ready`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Pending`: 0 bytes -print-type-size type: `{async fn body@$DIR/async.rs:8:17: 8:19}`: 1 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of wait()}`: 1 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Returned`: 0 bytes diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr index d7a0452727e83..cd4982b24809a 100644 --- a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr @@ -10,7 +10,7 @@ error: concrete type differs from previous defining opaque type use --> $DIR/hkl_forbidden4.rs:13:1 | LL | async fn operation(_: &mut ()) -> () { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `FutNothing<'_>`, got `{async fn body@$DIR/hkl_forbidden4.rs:13:38: 16:2}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `FutNothing<'_>`, got `{async fn body of operation()}` | note: previous use here --> $DIR/hkl_forbidden4.rs:15:5 From 66f1e14cc3fa48aa29ecd19274207bfd3fb08fa8 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 23 Mar 2024 17:24:13 -0700 Subject: [PATCH 13/13] Simplify an iterator search in borrowck diag Rather than `.into_iter().rev().find_position(...)`, this case can simply call `.iter().rposition(...)`. --- .../rustc_borrowck/src/diagnostics/mod.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 11561539f6ddb..0106e285604d6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -4,7 +4,6 @@ use crate::session_diagnostics::{ CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause, CaptureVarKind, CaptureVarPathUseCause, OnClosureNote, }; -use itertools::Itertools; use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, Namespace}; @@ -226,16 +225,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } else { if autoderef_index.is_none() { - autoderef_index = - match place.projection.into_iter().rev().find_position(|elem| { - !matches!( - elem, - ProjectionElem::Deref | ProjectionElem::Downcast(..) - ) - }) { - Some((index, _)) => Some(place.projection.len() - index), - None => Some(0), - }; + autoderef_index = match place.projection.iter().rposition(|elem| { + !matches!( + elem, + ProjectionElem::Deref | ProjectionElem::Downcast(..) + ) + }) { + Some(index) => Some(index + 1), + None => Some(0), + }; } if index >= autoderef_index.unwrap() { buf.insert(0, '*');