From d561a84d48b64dc0f23e0f0a152b72e5a8f62161 Mon Sep 17 00:00:00 2001 From: Veera Date: Sun, 3 Mar 2024 09:10:06 -0500 Subject: [PATCH 01/32] 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/32] 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 d3299af26d8e884c484c5d06991b4cbf7fced590 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Mar 2024 13:29:15 +0100 Subject: [PATCH 03/32] transmute: caution against int2ptr transmutation --- library/core/src/intrinsics.rs | 37 ++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 86b9a39d68a67..ce498561eeb12 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1169,14 +1169,6 @@ extern "rust-intrinsic" { /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly /// unsafe**. `transmute` should be the absolute last resort. /// - /// Transmuting pointers *to* integers in a `const` context is [undefined behavior][ub], - /// unless the pointer was originally created *from* an integer. - /// (That includes this function specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::dangling], - /// but also semantically-equivalent conversions such as punning through `repr(C)` union fields.) - /// Any attempt to use the resulting value for integer operations will abort const-evaluation. - /// (And even outside `const`, such transmutation is touching on many unspecified aspects of the - /// Rust memory model and should be avoided. See below for alternatives.) - /// /// Because `transmute` is a by-value operation, alignment of the *transmuted values /// themselves* is not a concern. As with any other function, the compiler already ensures /// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point @@ -1187,6 +1179,35 @@ extern "rust-intrinsic" { /// /// [ub]: ../../reference/behavior-considered-undefined.html /// + /// # Transmutation between pointers and integers + /// + /// Special care has to be taken when transmuting between pointers and integers, e.g. + /// transmuting between `*const ()` and `usize`. + /// + /// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless + /// the pointer was originally created *from* an integer. (That includes this function + /// specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::dangling], + /// but also semantically-equivalent conversions such as punning through `repr(C)` union + /// fields.) Any attempt to use the resulting value for integer operations will abort + /// const-evaluation. (And even outside `const`, such transmutation is touching on many + /// unspecified aspects of the Rust memory model and should be avoided. See below for + /// alternatives.) + /// + /// Transmuting *integers to pointers* is a largely unspecified operation. It is likely *not* + /// equivalent to an `as` cast. Doing non-zero-sized memory accesses with a pointer constructed + /// this way is currently considered undefined behavior. + /// + /// All this also applies when the integer is nested inside an array, tuple, struct, or enum. + /// However, `MaybeUninit` is not considered an integer type for the purpose of this + /// section. Transmuting `*const ()` to `MaybeUninit` is fine---but then calling + /// `assume_init()` on that result is considered as completing the pointer-to-integer transmute + /// and thus runs into the issues discussed above. + /// + /// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a + /// lossless process. If you want to round-trip a pointer through an integer in a way that you + /// can get back the original pointer, you need to use `as` casts, or replace the integer type + /// by `MaybeUninit<$int>` (and never call `assume_init()`). + /// /// # Examples /// /// There are a few things that `transmute` is really useful for. From 1bde8281415034fd76a031c5e939251ff12ea60f Mon Sep 17 00:00:00 2001 From: Veera Date: Wed, 13 Mar 2024 19:20:49 -0400 Subject: [PATCH 04/32] 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 982918f4935fd4677af06d42e0d0b298bfb1c243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 9 Mar 2024 00:35:57 +0000 Subject: [PATCH 05/32] Handle str literals written with `'` lexed as lifetime Given `'hello world'` and `'1 str', provide a structured suggestion for a valid string literal: ``` error[E0762]: unterminated character literal --> $DIR/lex-bad-str-literal-as-char-3.rs:2:26 | LL | println!('hello world'); | ^^^^ | help: if you meant to write a `str` literal, use double quotes | LL | println!("hello world"); | ~ ~ ``` ``` error[E0762]: unterminated character literal --> $DIR/lex-bad-str-literal-as-char-1.rs:2:20 | LL | println!('1 + 1'); | ^^^^ | help: if you meant to write a `str` literal, use double quotes | LL | println!("1 + 1"); | ~ ~ ``` Fix #119685. --- compiler/rustc_lexer/src/cursor.rs | 2 +- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 11 +++++ compiler/rustc_parse/src/lexer/mod.rs | 46 +++++++++++++++++-- .../lexer/lex-bad-str-literal-as-char-1.fixed | 6 +++ .../ui/lexer/lex-bad-str-literal-as-char-1.rs | 6 +++ .../lex-bad-str-literal-as-char-1.stderr | 20 ++++++++ .../lexer/lex-bad-str-literal-as-char-2.fixed | 4 ++ .../ui/lexer/lex-bad-str-literal-as-char-2.rs | 4 ++ .../lex-bad-str-literal-as-char-2.stderr | 13 ++++++ .../lexer/lex-bad-str-literal-as-char-3.fixed | 4 ++ .../ui/lexer/lex-bad-str-literal-as-char-3.rs | 4 ++ .../lex-bad-str-literal-as-char-3.stderr | 14 ++++++ 13 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-1.rs create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-2.rs create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.rs create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs index aba7f95487e9d..8d8cc9ecc3e9f 100644 --- a/compiler/rustc_lexer/src/cursor.rs +++ b/compiler/rustc_lexer/src/cursor.rs @@ -46,7 +46,7 @@ impl<'a> Cursor<'a> { /// If requested position doesn't exist, `EOF_CHAR` is returned. /// However, getting `EOF_CHAR` doesn't always mean actual end of file, /// it should be checked with `is_eof` method. - pub(crate) fn first(&self) -> char { + pub fn first(&self) -> char { // `.next()` optimizes better than `.nth(0)` self.chars.clone().next().unwrap_or(EOF_CHAR) } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index a100e2d47bbbb..888c621f02afd 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -835,6 +835,7 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown .label = unknown prefix .note = prefixed identifiers and literals are reserved since Rust 2021 .suggestion_br = use `br` for a raw byte string + .suggestion_str = if you meant to write a `str` literal, use double quotes .suggestion_whitespace = consider inserting whitespace here parse_unknown_start_of_token = unknown start of token: {$escaped} diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 32b56bb7e877e..140eb6cd18752 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1994,6 +1994,17 @@ pub enum UnknownPrefixSugg { style = "verbose" )] Whitespace(#[primary_span] Span), + #[multipart_suggestion( + parse_suggestion_str, + applicability = "maybe-incorrect", + style = "verbose" + )] + MeantStr { + #[suggestion_part(code = "\"")] + start: Span, + #[suggestion_part(code = "\"")] + end: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index f57945a52df37..659e0b63d2ed8 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -63,6 +63,7 @@ pub(crate) fn parse_token_trees<'psess, 'src>( cursor, override_span, nbsp_is_whitespace: false, + last_lifetime: None, }; let (stream, res, unmatched_delims) = tokentrees::TokenTreesReader::parse_all_token_trees(string_reader); @@ -105,6 +106,10 @@ struct StringReader<'psess, 'src> { /// in this file, it's safe to treat further occurrences of the non-breaking /// space character as whitespace. nbsp_is_whitespace: bool, + + /// Track the `Span` for the leading `'` of the last lifetime. Used for + /// diagnostics to detect possible typo where `"` was meant. + last_lifetime: Option, } impl<'psess, 'src> StringReader<'psess, 'src> { @@ -130,6 +135,18 @@ impl<'psess, 'src> StringReader<'psess, 'src> { debug!("next_token: {:?}({:?})", token.kind, self.str_from(start)); + if let rustc_lexer::TokenKind::Semi + | rustc_lexer::TokenKind::LineComment { .. } + | rustc_lexer::TokenKind::BlockComment { .. } + | rustc_lexer::TokenKind::CloseParen + | rustc_lexer::TokenKind::CloseBrace + | rustc_lexer::TokenKind::CloseBracket = token.kind + { + // Heuristic: we assume that it is unlikely we're dealing with an unterminated + // string surrounded by single quotes. + self.last_lifetime = None; + } + // Now "cook" the token, converting the simple `rustc_lexer::TokenKind` enum into a // rich `rustc_ast::TokenKind`. This turns strings into interned symbols and runs // additional validation. @@ -247,6 +264,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { // expansion purposes. See #12512 for the gory details of why // this is necessary. let lifetime_name = self.str_from(start); + self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); if starts_with_number { let span = self.mk_sp(start, self.pos); self.dcx().struct_err("lifetimes cannot start with a number") @@ -395,10 +413,21 @@ impl<'psess, 'src> StringReader<'psess, 'src> { match kind { rustc_lexer::LiteralKind::Char { terminated } => { if !terminated { - self.dcx() + let mut err = self + .dcx() .struct_span_fatal(self.mk_sp(start, end), "unterminated character literal") - .with_code(E0762) - .emit() + .with_code(E0762); + if let Some(lt_sp) = self.last_lifetime { + err.multipart_suggestion( + "if you meant to write a `str` literal, use double quotes", + vec![ + (lt_sp, "\"".to_string()), + (self.mk_sp(start, start + BytePos(1)), "\"".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } + err.emit() } self.cook_unicode(token::Char, Mode::Char, start, end, 1, 1) // ' ' } @@ -673,7 +702,16 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let sugg = if prefix == "rb" { Some(errors::UnknownPrefixSugg::UseBr(prefix_span)) } else if expn_data.is_root() { - Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi())) + if self.cursor.first() == '\'' + && let Some(start) = self.last_lifetime + { + Some(errors::UnknownPrefixSugg::MeantStr { + start, + end: self.mk_sp(self.pos, self.pos + BytePos(1)), + }) + } else { + Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi())) + } } else { None }; diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed new file mode 100644 index 0000000000000..b12139b0b40e9 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed @@ -0,0 +1,6 @@ +//@ run-rustfix +fn main() { + println!("1 + 1"); + //~^ ERROR unterminated character literal + //~| ERROR lifetimes cannot start with a number +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs new file mode 100644 index 0000000000000..6548792f33b4f --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs @@ -0,0 +1,6 @@ +//@ run-rustfix +fn main() { + println!('1 + 1'); + //~^ ERROR unterminated character literal + //~| ERROR lifetimes cannot start with a number +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr new file mode 100644 index 0000000000000..675624cfa9415 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr @@ -0,0 +1,20 @@ +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-1.rs:3:20 + | +LL | println!('1 + 1'); + | ^^^ + | +help: if you meant to write a `str` literal, use double quotes + | +LL | println!("1 + 1"); + | ~ ~ + +error: lifetimes cannot start with a number + --> $DIR/lex-bad-str-literal-as-char-1.rs:3:14 + | +LL | println!('1 + 1'); + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0762`. diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed new file mode 100644 index 0000000000000..3ccec537c6c34 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!(" 1 + 1"); //~ ERROR character literal may only contain one codepoint +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs new file mode 100644 index 0000000000000..8af72e47dbb4b --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!(' 1 + 1'); //~ ERROR character literal may only contain one codepoint +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr new file mode 100644 index 0000000000000..8445d0595f3ed --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr @@ -0,0 +1,13 @@ +error: character literal may only contain one codepoint + --> $DIR/lex-bad-str-literal-as-char-2.rs:3:14 + | +LL | println!(' 1 + 1'); + | ^^^^^^^^ + | +help: if you meant to write a `str` literal, use double quotes + | +LL | println!(" 1 + 1"); + | ~~~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed new file mode 100644 index 0000000000000..3fbe0ea1dabef --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!("hello world"); //~ ERROR unterminated character literal +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs new file mode 100644 index 0000000000000..289f3f1d6570f --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!('hello world'); //~ ERROR unterminated character literal +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr new file mode 100644 index 0000000000000..ebfbeac02600b --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr @@ -0,0 +1,14 @@ +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-3.rs:3:26 + | +LL | println!('hello world'); + | ^^^^ + | +help: if you meant to write a `str` literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0762`. From 4a10b01f9504f8ad2ffb9b357845341f4fba6bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 9 Mar 2024 01:07:23 +0000 Subject: [PATCH 06/32] Use shorter span for existing `'` -> `"` structured suggestion --- compiler/rustc_infer/src/errors/mod.rs | 13 +++++------- .../src/infer/error_reporting/mod.rs | 14 ++++--------- compiler/rustc_parse/src/errors.rs | 11 +++++++++- .../src/lexer/unescape_error_reporting.rs | 20 ++++++++++++++----- tests/ui/inference/str-as-char.stderr | 4 ++-- tests/ui/issues/issue-23589.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-2.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-3.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-5.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-6.stderr | 6 +++--- .../lex-bad-str-literal-as-char-2.stderr | 2 +- tests/ui/parser/issues/issue-64732.stderr | 4 ++-- .../parser/unicode-character-literal.stderr | 4 ++-- tests/ui/str/str-as-char.stderr | 2 +- 14 files changed, 51 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index a3cf0d8e5208a..d0b1f2848ff3f 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1339,15 +1339,12 @@ pub enum TypeErrorAdditionalDiags { span: Span, code: String, }, - #[suggestion( - infer_meant_str_literal, - code = "\"{code}\"", - applicability = "machine-applicable" - )] + #[multipart_suggestion(infer_meant_str_literal, applicability = "machine-applicable")] MeantStrLiteral { - #[primary_span] - span: Span, - code: String, + #[suggestion_part(code = "\"")] + start: Span, + #[suggestion_part(code = "\"")] + end: Span, }, #[suggestion( infer_consider_specifying_length, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 5d2a95593cd25..4b104756b181f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2078,16 +2078,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // If a string was expected and the found expression is a character literal, // perhaps the user meant to write `"s"` to specify a string literal. (ty::Ref(_, r, _), ty::Char) if r.is_str() => { - if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { - if let Some(code) = - code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) - { - suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { - span, - code: escape_literal(code), - }) - } - } + suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { + start: span.with_hi(span.lo() + BytePos(1)), + end: span.with_lo(span.hi() - BytePos(1)), + }) } // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`, // we try to suggest to add the missing `let` for `if let Some(..) = expr` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 140eb6cd18752..d12818444fc5f 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2216,12 +2216,21 @@ pub enum MoreThanOneCharSugg { ch: String, }, #[suggestion(parse_use_double_quotes, code = "{sugg}", applicability = "machine-applicable")] - Quotes { + QuotesFull { #[primary_span] span: Span, is_byte: bool, sugg: String, }, + #[multipart_suggestion(parse_use_double_quotes, applicability = "machine-applicable")] + Quotes { + #[suggestion_part(code = "{prefix}\"")] + start: Span, + #[suggestion_part(code = "\"")] + end: Span, + is_byte: bool, + prefix: &'static str, + }, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 3ebad6a9fd73e..1ac6b6fe11566 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -95,11 +95,21 @@ pub(crate) fn emit_unescape_error( } escaped.push(c); } - let sugg = format!("{prefix}\"{escaped}\""); - MoreThanOneCharSugg::Quotes { - span: full_lit_span, - is_byte: mode == Mode::Byte, - sugg, + if escaped.len() != lit.len() { + let sugg = format!("{prefix}\"{escaped}\""); + MoreThanOneCharSugg::QuotesFull { + span: full_lit_span, + is_byte: mode == Mode::Byte, + sugg, + } + } else { + MoreThanOneCharSugg::Quotes { + start: full_lit_span + .with_hi(full_lit_span.lo() + BytePos((prefix.len() + 1) as u32)), + end: full_lit_span.with_lo(full_lit_span.hi() - BytePos(1)), + is_byte: mode == Mode::Byte, + prefix, + } } }); dcx.emit_err(UnescapeError::MoreThanOneChar { diff --git a/tests/ui/inference/str-as-char.stderr b/tests/ui/inference/str-as-char.stderr index 216f4cda69888..42302435c91bf 100644 --- a/tests/ui/inference/str-as-char.stderr +++ b/tests/ui/inference/str-as-char.stderr @@ -18,7 +18,7 @@ LL | let _: &str = '\"\"\"'; help: if you meant to write a `str` literal, use double quotes | LL | let _: &str = "\"\"\""; - | ~~~~~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/str-as-char.rs:10:19 @@ -42,7 +42,7 @@ LL | let _: &str = 'a'; help: if you meant to write a `str` literal, use double quotes | LL | let _: &str = "a"; - | ~~~ + | ~ ~ error: aborting due to 4 previous errors diff --git a/tests/ui/issues/issue-23589.stderr b/tests/ui/issues/issue-23589.stderr index 1a91f5e04dbce..bf055a7e31c59 100644 --- a/tests/ui/issues/issue-23589.stderr +++ b/tests/ui/issues/issue-23589.stderr @@ -18,7 +18,7 @@ LL | let v: Vec(&str) = vec!['1', '2']; help: if you meant to write a `str` literal, use double quotes | LL | let v: Vec(&str) = vec!["1", '2']; - | ~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/lexer/lex-bad-char-literals-2.stderr b/tests/ui/lexer/lex-bad-char-literals-2.stderr index 1518a37ab53f3..af64e6efe45ff 100644 --- a/tests/ui/lexer/lex-bad-char-literals-2.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-2.stderr @@ -7,7 +7,7 @@ LL | 'nope' help: if you meant to write a `str` literal, use double quotes | LL | "nope" - | ~~~~~~ + | ~ ~ error: aborting due to 1 previous error diff --git a/tests/ui/lexer/lex-bad-char-literals-3.stderr b/tests/ui/lexer/lex-bad-char-literals-3.stderr index 62a5e424cb469..312b42fc83174 100644 --- a/tests/ui/lexer/lex-bad-char-literals-3.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-3.stderr @@ -7,7 +7,7 @@ LL | static c: char = '●●'; help: if you meant to write a `str` literal, use double quotes | LL | static c: char = "●●"; - | ~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-3.rs:5:20 @@ -18,7 +18,7 @@ LL | let ch: &str = '●●'; help: if you meant to write a `str` literal, use double quotes | LL | let ch: &str = "●●"; - | ~~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/lexer/lex-bad-char-literals-5.stderr b/tests/ui/lexer/lex-bad-char-literals-5.stderr index 184817a6579d0..185f460b10def 100644 --- a/tests/ui/lexer/lex-bad-char-literals-5.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-5.stderr @@ -7,7 +7,7 @@ LL | static c: char = '\x10\x10'; help: if you meant to write a `str` literal, use double quotes | LL | static c: char = "\x10\x10"; - | ~~~~~~~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-5.rs:5:20 @@ -18,7 +18,7 @@ LL | let ch: &str = '\x10\x10'; help: if you meant to write a `str` literal, use double quotes | LL | let ch: &str = "\x10\x10"; - | ~~~~~~~~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/lexer/lex-bad-char-literals-6.stderr b/tests/ui/lexer/lex-bad-char-literals-6.stderr index 2fe30304a50d6..f49e5a095b34a 100644 --- a/tests/ui/lexer/lex-bad-char-literals-6.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-6.stderr @@ -7,7 +7,7 @@ LL | let x: &str = 'ab'; help: if you meant to write a `str` literal, use double quotes | LL | let x: &str = "ab"; - | ~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-6.rs:4:19 @@ -18,7 +18,7 @@ LL | let y: char = 'cd'; help: if you meant to write a `str` literal, use double quotes | LL | let y: char = "cd"; - | ~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-6.rs:6:13 @@ -29,7 +29,7 @@ LL | let z = 'ef'; help: if you meant to write a `str` literal, use double quotes | LL | let z = "ef"; - | ~~~~ + | ~ ~ error[E0308]: mismatched types --> $DIR/lex-bad-char-literals-6.rs:13:20 diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr index 8445d0595f3ed..06b38522ad2dd 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr @@ -7,7 +7,7 @@ LL | println!(' 1 + 1'); help: if you meant to write a `str` literal, use double quotes | LL | println!(" 1 + 1"); - | ~~~~~~~~ + | ~ ~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-64732.stderr b/tests/ui/parser/issues/issue-64732.stderr index 8046254937763..8893fa8aae239 100644 --- a/tests/ui/parser/issues/issue-64732.stderr +++ b/tests/ui/parser/issues/issue-64732.stderr @@ -7,7 +7,7 @@ LL | let _foo = b'hello\0'; help: if you meant to write a byte string literal, use double quotes | LL | let _foo = b"hello\0"; - | ~~~~~~~~~~ + | ~~ ~ error: character literal may only contain one codepoint --> $DIR/issue-64732.rs:6:16 @@ -18,7 +18,7 @@ LL | let _bar = 'hello'; help: if you meant to write a `str` literal, use double quotes | LL | let _bar = "hello"; - | ~~~~~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/unicode-character-literal.stderr b/tests/ui/parser/unicode-character-literal.stderr index 5cd3bd0fe69d7..1104eaeb8d478 100644 --- a/tests/ui/parser/unicode-character-literal.stderr +++ b/tests/ui/parser/unicode-character-literal.stderr @@ -12,7 +12,7 @@ LL | let _spade = '♠️'; help: if you meant to write a `str` literal, use double quotes | LL | let _spade = "♠️"; - | ~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/unicode-character-literal.rs:12:14 @@ -28,7 +28,7 @@ LL | let _s = 'ṩ̂̊'; help: if you meant to write a `str` literal, use double quotes | LL | let _s = "ṩ̂̊"; - | ~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/unicode-character-literal.rs:17:14 diff --git a/tests/ui/str/str-as-char.stderr b/tests/ui/str/str-as-char.stderr index 44ec079e92918..03b2309a3171a 100644 --- a/tests/ui/str/str-as-char.stderr +++ b/tests/ui/str/str-as-char.stderr @@ -7,7 +7,7 @@ LL | println!('●●'); help: if you meant to write a `str` literal, use double quotes | LL | println!("●●"); - | ~~~~ + | ~ ~ error: aborting due to 1 previous error From 999a0dc300b7f95eb7d83666514c4ceae76020f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Mar 2024 23:52:04 +0000 Subject: [PATCH 07/32] review comment: `str` -> string in messages --- compiler/rustc_infer/messages.ftl | 2 +- compiler/rustc_parse/messages.ftl | 4 ++-- compiler/rustc_parse/src/lexer/mod.rs | 2 +- tests/ui/inference/str-as-char.stderr | 8 ++++---- tests/ui/issues/issue-23589.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-2.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-3.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-5.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-6.stderr | 6 +++--- tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr | 2 +- tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr | 2 +- tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr | 2 +- tests/ui/parser/issues/issue-64732.rs | 2 +- tests/ui/parser/issues/issue-64732.stderr | 2 +- tests/ui/parser/unicode-character-literal.fixed | 4 ++-- tests/ui/parser/unicode-character-literal.rs | 4 ++-- tests/ui/parser/unicode-character-literal.stderr | 4 ++-- tests/ui/str/str-as-char.stderr | 2 +- 18 files changed, 29 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index e44a6ae3b3f2e..521c65c600918 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -169,7 +169,7 @@ infer_lifetime_param_suggestion_elided = each elided lifetime in input position infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b` infer_meant_char_literal = if you meant to write a `char` literal, use single quotes -infer_meant_str_literal = if you meant to write a `str` literal, use double quotes +infer_meant_str_literal = if you meant to write a string literal, use double quotes infer_mismatched_static_lifetime = incompatible lifetime on type infer_more_targeted = {$has_param_name -> [true] `{$param_name}` diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 888c621f02afd..7f828c0274361 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -570,7 +570,7 @@ parse_more_than_one_char = character literal may only contain one codepoint .remove_non = consider removing the non-printing characters .use_double_quotes = if you meant to write a {$is_byte -> [true] byte string - *[false] `str` + *[false] string } literal, use double quotes parse_multiple_skipped_lines = multiple lines skipped by escaped newline @@ -835,7 +835,7 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown .label = unknown prefix .note = prefixed identifiers and literals are reserved since Rust 2021 .suggestion_br = use `br` for a raw byte string - .suggestion_str = if you meant to write a `str` literal, use double quotes + .suggestion_str = if you meant to write a string literal, use double quotes .suggestion_whitespace = consider inserting whitespace here parse_unknown_start_of_token = unknown start of token: {$escaped} diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 659e0b63d2ed8..5583e49ba6011 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -419,7 +419,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { .with_code(E0762); if let Some(lt_sp) = self.last_lifetime { err.multipart_suggestion( - "if you meant to write a `str` literal, use double quotes", + "if you meant to write a string literal, use double quotes", vec![ (lt_sp, "\"".to_string()), (self.mk_sp(start, start + BytePos(1)), "\"".to_string()), diff --git a/tests/ui/inference/str-as-char.stderr b/tests/ui/inference/str-as-char.stderr index 42302435c91bf..4ca71c5f067fd 100644 --- a/tests/ui/inference/str-as-char.stderr +++ b/tests/ui/inference/str-as-char.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | let _: &str = '"""'; | ^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "\"\"\""; | ~~~~~~~~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let _: &str = '\"\"\"'; | ^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "\"\"\""; | ~ ~ @@ -26,7 +26,7 @@ error: character literal may only contain one codepoint LL | let _: &str = '"\"\"\\"\\"'; | ^^^^^^^^^^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "\"\"\\"\\"\\\""; | ~~~~~~~~~~~~~~~~~~~~ @@ -39,7 +39,7 @@ LL | let _: &str = 'a'; | | | expected due to this | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "a"; | ~ ~ diff --git a/tests/ui/issues/issue-23589.stderr b/tests/ui/issues/issue-23589.stderr index bf055a7e31c59..21d383b0e8ce2 100644 --- a/tests/ui/issues/issue-23589.stderr +++ b/tests/ui/issues/issue-23589.stderr @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | let v: Vec(&str) = vec!['1', '2']; | ^^^ expected `&str`, found `char` | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let v: Vec(&str) = vec!["1", '2']; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-2.stderr b/tests/ui/lexer/lex-bad-char-literals-2.stderr index af64e6efe45ff..76cde00404a15 100644 --- a/tests/ui/lexer/lex-bad-char-literals-2.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-2.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | 'nope' | ^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | "nope" | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-3.stderr b/tests/ui/lexer/lex-bad-char-literals-3.stderr index 312b42fc83174..3f339b2ef7d93 100644 --- a/tests/ui/lexer/lex-bad-char-literals-3.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-3.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | static c: char = '●●'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | static c: char = "●●"; | ~ ~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let ch: &str = '●●'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let ch: &str = "●●"; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-5.stderr b/tests/ui/lexer/lex-bad-char-literals-5.stderr index 185f460b10def..8004157e87f7a 100644 --- a/tests/ui/lexer/lex-bad-char-literals-5.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-5.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | static c: char = '\x10\x10'; | ^^^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | static c: char = "\x10\x10"; | ~ ~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let ch: &str = '\x10\x10'; | ^^^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let ch: &str = "\x10\x10"; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-6.stderr b/tests/ui/lexer/lex-bad-char-literals-6.stderr index f49e5a095b34a..96d409d59bb25 100644 --- a/tests/ui/lexer/lex-bad-char-literals-6.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-6.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | let x: &str = 'ab'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let x: &str = "ab"; | ~ ~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let y: char = 'cd'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let y: char = "cd"; | ~ ~ @@ -26,7 +26,7 @@ error: character literal may only contain one codepoint LL | let z = 'ef'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let z = "ef"; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr index 675624cfa9415..57c5f82704ec7 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr @@ -4,7 +4,7 @@ error[E0762]: unterminated character literal LL | println!('1 + 1'); | ^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!("1 + 1"); | ~ ~ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr index 06b38522ad2dd..f64761af64193 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | println!(' 1 + 1'); | ^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!(" 1 + 1"); | ~ ~ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr index ebfbeac02600b..262f78569839d 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr @@ -4,7 +4,7 @@ error[E0762]: unterminated character literal LL | println!('hello world'); | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!("hello world"); | ~ ~ diff --git a/tests/ui/parser/issues/issue-64732.rs b/tests/ui/parser/issues/issue-64732.rs index 2db51ea6042aa..ff0f97ea211dc 100644 --- a/tests/ui/parser/issues/issue-64732.rs +++ b/tests/ui/parser/issues/issue-64732.rs @@ -5,5 +5,5 @@ fn main() { //~| HELP if you meant to write a byte string literal, use double quotes let _bar = 'hello'; //~^ ERROR character literal may only contain one codepoint - //~| HELP if you meant to write a `str` literal, use double quotes + //~| HELP if you meant to write a string literal, use double quotes } diff --git a/tests/ui/parser/issues/issue-64732.stderr b/tests/ui/parser/issues/issue-64732.stderr index 8893fa8aae239..7ec2df6d3bf7e 100644 --- a/tests/ui/parser/issues/issue-64732.stderr +++ b/tests/ui/parser/issues/issue-64732.stderr @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let _bar = 'hello'; | ^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _bar = "hello"; | ~ ~ diff --git a/tests/ui/parser/unicode-character-literal.fixed b/tests/ui/parser/unicode-character-literal.fixed index 9e31890151cc1..e401ecaf5da77 100644 --- a/tests/ui/parser/unicode-character-literal.fixed +++ b/tests/ui/parser/unicode-character-literal.fixed @@ -7,12 +7,12 @@ fn main() { let _spade = "♠️"; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `♠` is followed by the combining mark `\u{fe0f}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _s = "ṩ̂̊"; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _a = 'Å'; //~^ ERROR: character literal may only contain one codepoint diff --git a/tests/ui/parser/unicode-character-literal.rs b/tests/ui/parser/unicode-character-literal.rs index d886e5b26a56b..428e4e1ac5a08 100644 --- a/tests/ui/parser/unicode-character-literal.rs +++ b/tests/ui/parser/unicode-character-literal.rs @@ -7,12 +7,12 @@ fn main() { let _spade = '♠️'; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `♠` is followed by the combining mark `\u{fe0f}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _s = 'ṩ̂̊'; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _a = 'Å'; //~^ ERROR: character literal may only contain one codepoint diff --git a/tests/ui/parser/unicode-character-literal.stderr b/tests/ui/parser/unicode-character-literal.stderr index 1104eaeb8d478..726cde2b413e2 100644 --- a/tests/ui/parser/unicode-character-literal.stderr +++ b/tests/ui/parser/unicode-character-literal.stderr @@ -9,7 +9,7 @@ note: this `♠` is followed by the combining mark `\u{fe0f}` | LL | let _spade = '♠️'; | ^ -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _spade = "♠️"; | ~ ~ @@ -25,7 +25,7 @@ note: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` | LL | let _s = 'ṩ̂̊'; | ^ -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _s = "ṩ̂̊"; | ~ ~ diff --git a/tests/ui/str/str-as-char.stderr b/tests/ui/str/str-as-char.stderr index 03b2309a3171a..0638d371c173b 100644 --- a/tests/ui/str/str-as-char.stderr +++ b/tests/ui/str/str-as-char.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | println!('●●'); | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!("●●"); | ~ ~ From 6f388ef1fb3964fb83bae5c277f9c83bbde4c76b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Mar 2024 00:22:52 +0000 Subject: [PATCH 08/32] Extend test to trigger on 2015, 2018 and 2021 editions --- .../lexer/lex-bad-str-literal-as-char-3.fixed | 4 --- .../ui/lexer/lex-bad-str-literal-as-char-3.rs | 8 ++++-- ...bad-str-literal-as-char-3.rust2015.stderr} | 4 +-- ...-bad-str-literal-as-char-3.rust2018.stderr | 14 ++++++++++ ...-bad-str-literal-as-char-3.rust2021.stderr | 26 +++++++++++++++++++ 5 files changed, 48 insertions(+), 8 deletions(-) delete mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed rename tests/ui/lexer/{lex-bad-str-literal-as-char-3.stderr => lex-bad-str-literal-as-char-3.rust2015.stderr} (79%) create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed deleted file mode 100644 index 3fbe0ea1dabef..0000000000000 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed +++ /dev/null @@ -1,4 +0,0 @@ -//@ run-rustfix -fn main() { - println!("hello world"); //~ ERROR unterminated character literal -} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs index 289f3f1d6570f..2c0eda97853b0 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs @@ -1,4 +1,8 @@ -//@ run-rustfix +//@ revisions: rust2015 rust2018 rust2021 +//@[rust2018] edition:2018 +//@[rust2021] edition:2021 fn main() { - println!('hello world'); //~ ERROR unterminated character literal + println!('hello world'); + //[rust2015,rust2018,rust2021]~^ ERROR unterminated character literal + //[rust2021]~^^ ERROR prefix `world` is unknown } diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr similarity index 79% rename from tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr rename to tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr index 262f78569839d..06f127426679f 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr @@ -1,8 +1,8 @@ error[E0762]: unterminated character literal - --> $DIR/lex-bad-str-literal-as-char-3.rs:3:26 + --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 | LL | println!('hello world'); - | ^^^^ + | ^^^ | help: if you meant to write a string literal, use double quotes | diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr new file mode 100644 index 0000000000000..06f127426679f --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr @@ -0,0 +1,14 @@ +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 + | +LL | println!('hello world'); + | ^^^ + | +help: if you meant to write a string literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0762`. diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr new file mode 100644 index 0000000000000..4170560cfcb04 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr @@ -0,0 +1,26 @@ +error: prefix `world` is unknown + --> $DIR/lex-bad-str-literal-as-char-3.rs:5:21 + | +LL | println!('hello world'); + | ^^^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: if you meant to write a string literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 + | +LL | println!('hello world'); + | ^^^ + | +help: if you meant to write a string literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0762`. From ea1883d7b2207d1a0f08046f11ca493803bc8a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Mar 2024 00:40:25 +0000 Subject: [PATCH 09/32] Silence redundant error on char literal that was meant to be a string in 2021 edition --- compiler/rustc_lexer/src/cursor.rs | 9 +++++++++ compiler/rustc_parse/src/lexer/mod.rs | 11 ++++++++++- tests/ui/lexer/lex-bad-str-literal-as-char-3.rs | 1 - .../lex-bad-str-literal-as-char-3.rust2021.stderr | 14 +------------- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs index 8d8cc9ecc3e9f..d173c3ac0327b 100644 --- a/compiler/rustc_lexer/src/cursor.rs +++ b/compiler/rustc_lexer/src/cursor.rs @@ -59,6 +59,15 @@ impl<'a> Cursor<'a> { iter.next().unwrap_or(EOF_CHAR) } + /// Peeks the third symbol from the input stream without consuming it. + pub fn third(&self) -> char { + // `.next()` optimizes better than `.nth(1)` + let mut iter = self.chars.clone(); + iter.next(); + iter.next(); + iter.next().unwrap_or(EOF_CHAR) + } + /// Checks if there is nothing more to consume. pub(crate) fn is_eof(&self) -> bool { self.chars.as_str().is_empty() diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 5583e49ba6011..63b2b47630b29 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -698,13 +698,17 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let expn_data = prefix_span.ctxt().outer_expn_data(); if expn_data.edition >= Edition::Edition2021 { + let mut silence = false; // In Rust 2021, this is a hard error. let sugg = if prefix == "rb" { Some(errors::UnknownPrefixSugg::UseBr(prefix_span)) } else if expn_data.is_root() { if self.cursor.first() == '\'' && let Some(start) = self.last_lifetime + && self.cursor.third() != '\'' { + // An "unclosed `char`" error will be emitted already, silence redundant error. + silence = true; Some(errors::UnknownPrefixSugg::MeantStr { start, end: self.mk_sp(self.pos, self.pos + BytePos(1)), @@ -715,7 +719,12 @@ impl<'psess, 'src> StringReader<'psess, 'src> { } else { None }; - self.dcx().emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg }); + let err = errors::UnknownPrefix { span: prefix_span, prefix, sugg }; + if silence { + self.dcx().create_err(err).delay_as_bug(); + } else { + self.dcx().emit_err(err); + } } else { // Before Rust 2021, only emit a lint for migration. self.psess.buffer_lint_with_diagnostic( diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs index 2c0eda97853b0..0ae227da5f1e6 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs @@ -4,5 +4,4 @@ fn main() { println!('hello world'); //[rust2015,rust2018,rust2021]~^ ERROR unterminated character literal - //[rust2021]~^^ ERROR prefix `world` is unknown } diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr index 4170560cfcb04..06f127426679f 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr @@ -1,15 +1,3 @@ -error: prefix `world` is unknown - --> $DIR/lex-bad-str-literal-as-char-3.rs:5:21 - | -LL | println!('hello world'); - | ^^^^^ unknown prefix - | - = note: prefixed identifiers and literals are reserved since Rust 2021 -help: if you meant to write a string literal, use double quotes - | -LL | println!("hello world"); - | ~ ~ - error[E0762]: unterminated character literal --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 | @@ -21,6 +9,6 @@ help: if you meant to write a string literal, use double quotes LL | println!("hello world"); | ~ ~ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0762`. From f4d30b156b2958ba01b59a1751e16b5f6e157fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 17 Mar 2024 23:46:39 +0000 Subject: [PATCH 10/32] fix rustdoc test --- compiler/rustc_parse/src/lexer/unescape_error_reporting.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 1ac6b6fe11566..fa242a32a1814 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -95,7 +95,7 @@ pub(crate) fn emit_unescape_error( } escaped.push(c); } - if escaped.len() != lit.len() { + if escaped.len() != lit.len() || full_lit_span.is_empty() { let sugg = format!("{prefix}\"{escaped}\""); MoreThanOneCharSugg::QuotesFull { span: full_lit_span, From f4adb1e6bdaef12d8b5776f74dadab0ddc11694d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Mar 2024 21:29:21 +0100 Subject: [PATCH 11/32] add notes on how to store 'ptr or int' --- library/core/src/intrinsics.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index ce498561eeb12..27ed26fdcf16d 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1186,7 +1186,7 @@ extern "rust-intrinsic" { /// /// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless /// the pointer was originally created *from* an integer. (That includes this function - /// specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::dangling], + /// specifically, integer-to-pointer casts, and helpers like [`dangling`][crate::ptr::dangling], /// but also semantically-equivalent conversions such as punning through `repr(C)` union /// fields.) Any attempt to use the resulting value for integer operations will abort /// const-evaluation. (And even outside `const`, such transmutation is touching on many @@ -1206,7 +1206,11 @@ extern "rust-intrinsic" { /// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a /// lossless process. If you want to round-trip a pointer through an integer in a way that you /// can get back the original pointer, you need to use `as` casts, or replace the integer type - /// by `MaybeUninit<$int>` (and never call `assume_init()`). + /// by `MaybeUninit<$int>` (and never call `assume_init()`). If you are looking for a way to + /// store data of arbitrary type, also use `MaybeUninit` (that will also handle uninitialized + /// memory due to padding). If you specifically need to store something that is "either an + /// integer or a pointer", use `*mut ()`: integers can be converted to pointers and back without + /// any loss (via `as` casts or via `transmute`). /// /// # Examples /// From 2758435a8ed8f339d1f8a72a2676d13a3960544c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 20 Mar 2024 14:54:20 -0700 Subject: [PATCH 12/32] 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 13/32] 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 1fcf2eaa9f5ff9336e9b43f017eaf261acfdc2d3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 22 Mar 2024 16:35:44 -0400 Subject: [PATCH 14/32] Uniquify ReError on input mode in canonicalizer --- .../src/canonicalizer.rs | 3 +- .../next-solver/dont-canonicalize-re-error.rs | 28 +++++++++++++++++++ .../dont-canonicalize-re-error.stderr | 21 ++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/next-solver/dont-canonicalize-re-error.rs create mode 100644 tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 95b3006666202..2dbb44bdee207 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -239,7 +239,7 @@ impl, I: Interner> TypeFolder // FIXME: We should investigate the perf implications of not uniquifying // `ReErased`. We may be able to short-circuit registering region // obligations if we encounter a `ReErased` on one side, for example. - ty::ReStatic | ty::ReErased => match self.canonicalize_mode { + ty::ReStatic | ty::ReErased | ty::ReError(_) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => return r, }, @@ -277,7 +277,6 @@ impl, I: Interner> TypeFolder } } } - ty::ReError(_) => return r, }; let existing_bound_var = match self.canonicalize_mode { diff --git a/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs b/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs new file mode 100644 index 0000000000000..57f814bc81ec2 --- /dev/null +++ b/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Znext-solver + +trait Tr<'a> {} + +// Fulfillment in the new solver relies on an invariant to hold: Either +// `has_changed` is true, or computing a goal's certainty is idempotent. +// This isn't true for `ReError`, which we used to pass through in the +// canonicalizer even on input mode, which can cause a goal to go from +// ambig => pass, but we don't consider `has_changed` when the response +// only contains region constraints (since we usually uniquify regions). +// +// In this test: +// Implicit negative coherence tries to prove `W: Constrain<'?1>`, +// which will then match with the impl below. This constrains `'?1` to +// `ReError`, but still bails w/ ambiguity bc we can't prove `?0: Sized`. +// Then, when we recompute the goal `W: Constrain<'error>`, when +// collecting ambiguities and overflows, we end up assembling a default +// error candidate w/o ambiguity, which causes the goal to pass, and ICE. +impl<'a, A: ?Sized> Tr<'a> for W {} +struct W(A); +impl<'a, A: ?Sized> Tr<'a> for A where A: Constrain<'a> {} +//~^ ERROR conflicting implementations of trait `Tr<'_>` for type `W<_>` + +trait Constrain<'a> {} +impl Constrain<'missing> for W {} +//~^ ERROR use of undeclared lifetime name `'missing` + +fn main() {} diff --git a/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr b/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr new file mode 100644 index 0000000000000..cf85c52fb42ee --- /dev/null +++ b/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr @@ -0,0 +1,21 @@ +error[E0261]: use of undeclared lifetime name `'missing` + --> $DIR/dont-canonicalize-re-error.rs:25:26 + | +LL | impl Constrain<'missing> for W {} + | - ^^^^^^^^ undeclared lifetime + | | + | help: consider introducing lifetime `'missing` here: `'missing,` + +error[E0119]: conflicting implementations of trait `Tr<'_>` for type `W<_>` + --> $DIR/dont-canonicalize-re-error.rs:21:1 + | +LL | impl<'a, A: ?Sized> Tr<'a> for W {} + | ----------------------------------- first implementation here +LL | struct W(A); +LL | impl<'a, A: ?Sized> Tr<'a> for A where A: Constrain<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0119, E0261. +For more information about an error, try `rustc --explain E0119`. From dec36c3d6eca67c900b7bdf03bd8d9dd68c4aa34 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Sun, 3 Mar 2024 03:51:05 +0000 Subject: [PATCH 15/32] 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 12e362989b59469f8bbabe6b93f787b8127609a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 11:57:26 +0100 Subject: [PATCH 16/32] add test for #99945 Fixes #99945 --- .../failed-to-normalize-ice-99945.rs | 36 +++++++++++++++++++ .../failed-to-normalize-ice-99945.stderr | 25 +++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs create mode 100644 tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr diff --git a/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs new file mode 100644 index 0000000000000..023991c29d090 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs @@ -0,0 +1,36 @@ +// issue: rust-lang/rust#99945 +// ICE Failed to normalize + +#![feature(type_alias_impl_trait)] + +trait Widget { + type State; + + fn make_state(&self) -> Self::State; +} + +impl Widget for () { + type State = (); + + fn make_state(&self) -> Self::State {} +} + +struct StatefulWidget(F); + +type StateWidget<'a> = impl Widget<&'a ()>; + +impl Fn(&'a ()) -> StateWidget<'a>> Widget<()> for StatefulWidget { + type State = (); + + fn make_state(&self) -> Self::State {} +} + +fn new_stateful_widget Fn(&'a ()) -> StateWidget<'a>>(build: F) -> impl Widget<()> { + StatefulWidget(build) + //~^ ERROR expected generic lifetime parameter, found `'a` +} + +fn main() { + new_stateful_widget(|_| ()).make_state(); + //~^ ERROR mismatched types +} diff --git a/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr new file mode 100644 index 0000000000000..0c76feae198ba --- /dev/null +++ b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/failed-to-normalize-ice-99945.rs:34:29 + | +LL | type StateWidget<'a> = impl Widget<&'a ()>; + | ------------------- the expected opaque type +... +LL | new_stateful_widget(|_| ()).make_state(); + | ^^ expected opaque type, found `()` + | + = note: expected opaque type `StateWidget<'_>` + found unit type `()` + +error[E0792]: expected generic lifetime parameter, found `'a` + --> $DIR/failed-to-normalize-ice-99945.rs:29:5 + | +LL | type StateWidget<'a> = impl Widget<&'a ()>; + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | StatefulWidget(build) + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0792. +For more information about an error, try `rustc --explain E0308`. From 2f9a240b91f766f158b652f537b828c9909bfdd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:01:39 +0100 Subject: [PATCH 17/32] add test for opaque type with non-universal region substs #101852 Fixes #101852 --- tests/ui/impl-trait/recursive-ice-101862.rs | 12 ++++++++++ .../ui/impl-trait/recursive-ice-101862.stderr | 24 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/ui/impl-trait/recursive-ice-101862.rs create mode 100644 tests/ui/impl-trait/recursive-ice-101862.stderr diff --git a/tests/ui/impl-trait/recursive-ice-101862.rs b/tests/ui/impl-trait/recursive-ice-101862.rs new file mode 100644 index 0000000000000..02f95fe5604b2 --- /dev/null +++ b/tests/ui/impl-trait/recursive-ice-101862.rs @@ -0,0 +1,12 @@ +// issue: rust-lang/rust#101852 +// ICE opaque type with non-universal region substs + +pub fn ice(x: impl AsRef) -> impl IntoIterator { +//~^ WARN function cannot return without recursing + vec![].append(&mut ice(x.as_ref())); + //~^ ERROR expected generic type parameter, found `&str` + + Vec::new() +} + +fn main() {} diff --git a/tests/ui/impl-trait/recursive-ice-101862.stderr b/tests/ui/impl-trait/recursive-ice-101862.stderr new file mode 100644 index 0000000000000..f4148720c3331 --- /dev/null +++ b/tests/ui/impl-trait/recursive-ice-101862.stderr @@ -0,0 +1,24 @@ +warning: function cannot return without recursing + --> $DIR/recursive-ice-101862.rs:4:1 + | +LL | pub fn ice(x: impl AsRef) -> impl IntoIterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | +LL | vec![].append(&mut ice(x.as_ref())); + | --------------- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +error[E0792]: expected generic type parameter, found `&str` + --> $DIR/recursive-ice-101862.rs:6:5 + | +LL | pub fn ice(x: impl AsRef) -> impl IntoIterator { + | --------------- this generic parameter must be used with a generic type parameter +LL | +LL | vec![].append(&mut ice(x.as_ref())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0792`. From e54bff71091e7c3a16c96e2f79328eb73815d7cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:19:05 +0100 Subject: [PATCH 18/32] add test for #104779 opaque types, patterns and subtyping ICE: IndexMap: key not found Fixes #104779 --- ...que-types-patterns-subtyping-ice-104779.rs | 26 ++++++++++++ ...types-patterns-subtyping-ice-104779.stderr | 42 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs create mode 100644 tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr diff --git a/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs new file mode 100644 index 0000000000000..b9e729bff62a0 --- /dev/null +++ b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs @@ -0,0 +1,26 @@ +// issue: rust-lang/rust#104779 +// ICE region infer, IndexMap: key not found + +struct Inv<'a>(&'a mut &'a ()); +enum Foo { + Bar, + Var(T), +} +type Subtype = Foo fn(Inv<'a>, Inv<'b>)>; +type Supertype = Foo fn(Inv<'a>, Inv<'a>)>; + +fn foo() -> impl Sized { +//~^ WARN function cannot return without recursing + loop { + match foo() { + //~^ ERROR higher-ranked subtype error + //~^^ ERROR higher-ranked subtype error + Subtype::Bar => (), + //~^ ERROR higher-ranked subtype error + //~^^ ERROR higher-ranked subtype error + Supertype::Var(x) => {} + } + } +} + +pub fn main() {} diff --git a/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr new file mode 100644 index 0000000000000..887cb14a76935 --- /dev/null +++ b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr @@ -0,0 +1,42 @@ +warning: function cannot return without recursing + --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:12:1 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +... +LL | match foo() { + | ----- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +error: higher-ranked subtype error + --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:15:15 + | +LL | match foo() { + | ^^^^^ + +error: higher-ranked subtype error + --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:15:15 + | +LL | match foo() { + | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: higher-ranked subtype error + --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:18:13 + | +LL | Subtype::Bar => (), + | ^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:18:13 + | +LL | Subtype::Bar => (), + | ^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors; 1 warning emitted + From f1f287fadb91451b116ff00a2f8b9c32c5e1571b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:24:40 +0100 Subject: [PATCH 19/32] add test for ICE "raw ptr comparison should already be caught in the trait system" #105047 Fixes #105047 --- .../const-eval-compare-ice-105047.rs | 15 +++++++++ .../const-eval-compare-ice-105047.stderr | 31 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs create mode 100644 tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr diff --git a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs new file mode 100644 index 0000000000000..0a736a5a8e21b --- /dev/null +++ b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs @@ -0,0 +1,15 @@ +// issue: rust-lang/rust#105047 +// ICE raw ptr comparison should already be caught in the trait systems + +#![feature(raw_ref_op)] + +const RCZ: *const i32 = &raw const *&0; + +const fn f() { + if let RCZ = &raw const *&0 { } + //~^ WARN function pointers and raw pointers not derived from integers in patterns + //~^^ ERROR pointers cannot be reliably compared during const eval + //~^^^ WARN this was previously accepted by the compiler but is being phased out +} + +fn main() {} diff --git a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr new file mode 100644 index 0000000000000..9c472cda2442c --- /dev/null +++ b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr @@ -0,0 +1,31 @@ +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/const-eval-compare-ice-105047.rs:9:12 + | +LL | if let RCZ = &raw const *&0 { } + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + +error: pointers cannot be reliably compared during const eval + --> $DIR/const-eval-compare-ice-105047.rs:9:12 + | +LL | if let RCZ = &raw const *&0 { } + | ^^^ + | + = note: see issue #53020 for more information + +error: aborting due to 1 previous error; 1 warning emitted + +Future incompatibility report: Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/const-eval-compare-ice-105047.rs:9:12 + | +LL | if let RCZ = &raw const *&0 { } + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + From f8aeac8a3692b1a02002a1293c231de73149e676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:32:32 +0100 Subject: [PATCH 20/32] add test for #106423 Fixes #106423 --- .../poly-const-uneval-ice-106423.rs | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs diff --git a/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs b/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs new file mode 100644 index 0000000000000..ed5ba32b62105 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs @@ -0,0 +1,57 @@ +// issue: rust-lang/rust#106423 +// ICE collection encountered polymorphic constant: UnevaluatedConst {..} +//@ edition:2021 +//@ check-pass + +#![feature(generic_const_exprs, generic_arg_infer)] +#![allow(incomplete_features)] +#![allow(unused)] + +use core::mem::MaybeUninit; + +pub struct Arr { + v: [MaybeUninit; N], +} + +impl Arr { + const ELEM: MaybeUninit = MaybeUninit::uninit(); + const INIT: [MaybeUninit; N] = [Self::ELEM; N]; // important for optimization of `new` + + fn new() -> Self { + Arr { v: Self::INIT } + } +} + +pub struct BaFormatFilter {} + +pub enum DigitalFilter +where + [(); N * 2 + 1]: Sized, + [(); N * 2]: Sized, +{ + Ba(BaFormatFilter<{ N * 2 + 1 }>), +} + +pub fn iirfilter_st_copy(_: [f32; M]) -> DigitalFilter +where + [(); N * 2 + 1]: Sized, + [(); N * 2]: Sized, +{ + let zpk = zpk2tf_st(&Arr::::new(), &Arr::::new()); + DigitalFilter::Ba(zpk) +} + +pub fn zpk2tf_st( + _z: &Arr, + _p: &Arr, +) -> BaFormatFilter<{ N + 1 }> +where + [(); N + 1]: Sized, +{ + BaFormatFilter {} +} + + +fn main() { + iirfilter_st_copy::<4, 2>([10., 50.,]); +} From cc422cee97e53195ac75b25d221f192b6a3a200b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:38:50 +0100 Subject: [PATCH 21/32] add test for ICE #106444 Fixes #106444 --- tests/ui/drop/norm-ice-106444.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/ui/drop/norm-ice-106444.rs diff --git a/tests/ui/drop/norm-ice-106444.rs b/tests/ui/drop/norm-ice-106444.rs new file mode 100644 index 0000000000000..b248bc73bbefa --- /dev/null +++ b/tests/ui/drop/norm-ice-106444.rs @@ -0,0 +1,16 @@ +// issue: rust-lang/rust#106444 +// ICE failed to normalize +//@ compile-flags: -Zmir-opt-level=3 +//@ check-pass + +#![crate_type="lib"] + +pub trait A { + type B; +} + +pub struct S(T::B); + +pub fn foo(p: *mut S) { + unsafe { core::ptr::drop_in_place(p) }; +} From f2bc9c5997a3647a61cfb5045866314088c6befa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:50:21 +0100 Subject: [PATCH 22/32] add test for #106874 ICE BoundUniversalRegionError Fixes #106874 --- tests/ui/nll/ice-106874.rs | 48 ++++++++++++++++++ tests/ui/nll/ice-106874.stderr | 90 ++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 tests/ui/nll/ice-106874.rs create mode 100644 tests/ui/nll/ice-106874.stderr diff --git a/tests/ui/nll/ice-106874.rs b/tests/ui/nll/ice-106874.rs new file mode 100644 index 0000000000000..77a91d6d823a2 --- /dev/null +++ b/tests/ui/nll/ice-106874.rs @@ -0,0 +1,48 @@ +// issue: rust-lang/rust#106874 +// ICE BoundUniversalRegionError + +use std::marker::PhantomData; +use std::rc::Rc; + +pub fn func(f: F) -> A { + A(B(C::new(D::new(move |st| f(st))))) + //~^ ERROR implementation of `FnOnce` is not general enough + //~^^ ERROR implementation of `Fn` is not general enough + //~^^^ ERROR implementation of `FnOnce` is not general enough + //~^^^^ ERROR implementation of `FnOnce` is not general enough + //~^^^^^ ERROR implementation of `Fn` is not general enough + //~^^^^^^ ERROR implementation of `FnOnce` is not general enough + //~^^^^^^^ ERROR implementation of `Fn` is not general enough + //~^^^^^^^^ ERROR implementation of `FnOnce` is not general enough + //~^^^^^^^^^ ERROR higher-ranked subtype error + //~^^^^^^^^^^ ERROR higher-ranked subtype error +} + +trait X {} +trait Y { + type V; +} + +struct A(T); + +struct B(Rc); +impl X for B {} + +struct C(T::V); +impl C { + fn new(_: T) -> Rc { + todo!() + } +} +struct D(F, PhantomData); + +impl D { + fn new(_: F) -> Self { + todo!() + } +} +impl Y for D { + type V = V; +} + +pub fn main() {} diff --git a/tests/ui/nll/ice-106874.stderr b/tests/ui/nll/ice-106874.stderr new file mode 100644 index 0000000000000..ead4d490a6248 --- /dev/null +++ b/tests/ui/nll/ice-106874.stderr @@ -0,0 +1,90 @@ +error: implementation of `FnOnce` is not general enough + --> $DIR/ice-106874.rs:8:5 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... + = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` + +error: implementation of `FnOnce` is not general enough + --> $DIR/ice-106874.rs:8:5 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... + = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: implementation of `Fn` is not general enough + --> $DIR/ice-106874.rs:8:7 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` + +error: implementation of `FnOnce` is not general enough + --> $DIR/ice-106874.rs:8:7 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` + +error: implementation of `Fn` is not general enough + --> $DIR/ice-106874.rs:8:7 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: implementation of `FnOnce` is not general enough + --> $DIR/ice-106874.rs:8:9 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` + +error: implementation of `Fn` is not general enough + --> $DIR/ice-106874.rs:8:9 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` + +error: implementation of `FnOnce` is not general enough + --> $DIR/ice-106874.rs:8:9 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` + +error: higher-ranked subtype error + --> $DIR/ice-106874.rs:8:41 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^ + +error: higher-ranked subtype error + --> $DIR/ice-106874.rs:8:41 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 10 previous errors + From 368bfb2c10541129f9e6af98d88125d9bfc77820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 13:05:22 +0100 Subject: [PATCH 23/32] add test for #107228 Fixes #107228 --- .../broken-mir-drop-glue-107228.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/ui/specialization/broken-mir-drop-glue-107228.rs diff --git a/tests/ui/specialization/broken-mir-drop-glue-107228.rs b/tests/ui/specialization/broken-mir-drop-glue-107228.rs new file mode 100644 index 0000000000000..5a6dbf9ffc761 --- /dev/null +++ b/tests/ui/specialization/broken-mir-drop-glue-107228.rs @@ -0,0 +1,28 @@ +// issue: rust-lang/rust#107228 +// ICE broken MIR in DropGlue +//@ compile-flags: -Zvalidate-mir +//@ check-pass + +#![feature(specialization)] +#![crate_type="lib"] +#![allow(incomplete_features)] + +pub(crate) trait SpecTrait { + type Assoc; +} + +impl SpecTrait for C { + default type Assoc = Vec; +} + +pub(crate) struct AssocWrap { + _assoc: C::Assoc, +} + +fn instantiate() -> AssocWrap { + loop {} +} + +pub fn main() { + instantiate::<()>(); +} From 9aea37d3c114395219a85115f2fd19c249ccf105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 16:14:42 +0100 Subject: [PATCH 24/32] address review feedback --- tests/ui/nll/ice-106874.rs | 18 +++++++++--------- .../const-eval-compare-ice-105047.rs | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/ui/nll/ice-106874.rs b/tests/ui/nll/ice-106874.rs index 77a91d6d823a2..9337eee961bfb 100644 --- a/tests/ui/nll/ice-106874.rs +++ b/tests/ui/nll/ice-106874.rs @@ -7,15 +7,15 @@ use std::rc::Rc; pub fn func(f: F) -> A { A(B(C::new(D::new(move |st| f(st))))) //~^ ERROR implementation of `FnOnce` is not general enough - //~^^ ERROR implementation of `Fn` is not general enough - //~^^^ ERROR implementation of `FnOnce` is not general enough - //~^^^^ ERROR implementation of `FnOnce` is not general enough - //~^^^^^ ERROR implementation of `Fn` is not general enough - //~^^^^^^ ERROR implementation of `FnOnce` is not general enough - //~^^^^^^^ ERROR implementation of `Fn` is not general enough - //~^^^^^^^^ ERROR implementation of `FnOnce` is not general enough - //~^^^^^^^^^ ERROR higher-ranked subtype error - //~^^^^^^^^^^ ERROR higher-ranked subtype error + //~| ERROR implementation of `Fn` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `Fn` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `Fn` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR higher-ranked subtype error + //~| ERROR higher-ranked subtype error } trait X {} diff --git a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs index 0a736a5a8e21b..87ce4f1e14d94 100644 --- a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs +++ b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs @@ -8,8 +8,8 @@ const RCZ: *const i32 = &raw const *&0; const fn f() { if let RCZ = &raw const *&0 { } //~^ WARN function pointers and raw pointers not derived from integers in patterns - //~^^ ERROR pointers cannot be reliably compared during const eval - //~^^^ WARN this was previously accepted by the compiler but is being phased out + //~| ERROR pointers cannot be reliably compared during const eval + //~| WARN this was previously accepted by the compiler but is being phased out } fn main() {} From 4e8753b26d8203feb10164a8d212967870e4bcb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 13 Mar 2024 21:52:23 +0000 Subject: [PATCH 25/32] Rework rmake support library to have a weakly-typed API with helper methods --- src/tools/run-make-support/src/lib.rs | 187 +++++++++--------- src/tools/run-make-support/src/run.rs | 67 +++++++ tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs | 21 +- tests/run-make/a-b-a-linker-guard/rmake.rs | 44 ++--- tests/run-make/wasm-abi/rmake.rs | 3 +- tests/run-make/wasm-custom-section/rmake.rs | 6 +- .../wasm-custom-sections-opt/rmake.rs | 5 +- .../run-make/wasm-export-all-symbols/rmake.rs | 9 +- tests/run-make/wasm-import-module/rmake.rs | 11 +- tests/run-make/wasm-panic-small/rmake.rs | 10 +- tests/run-make/wasm-spurious-import/rmake.rs | 9 +- .../wasm-stringify-ints-small/rmake.rs | 7 +- .../wasm-symbols-different-module/rmake.rs | 4 +- .../wasm-symbols-not-exported/rmake.rs | 10 +- .../wasm-symbols-not-imported/rmake.rs | 10 +- 15 files changed, 240 insertions(+), 163 deletions(-) create mode 100644 src/tools/run-make-support/src/run.rs diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index e5e7b559c9292..7f7e364d7c9c0 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -1,3 +1,5 @@ +pub mod run; + use std::env; use std::path::{Path, PathBuf}; use std::process::{Command, Output}; @@ -5,6 +7,8 @@ use std::process::{Command, Output}; pub use object; pub use wasmparser; +pub use run::{run, run_fail}; + pub fn out_dir() -> PathBuf { env::var_os("TMPDIR").unwrap().into() } @@ -25,65 +29,122 @@ fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! std::process::exit(1) } -pub fn rustc() -> RustcInvocationBuilder { - RustcInvocationBuilder::new() +/// Construct a new `rustc` invocation. +pub fn rustc() -> Rustc { + Rustc::new() } -pub fn aux_build() -> AuxBuildInvocationBuilder { - AuxBuildInvocationBuilder::new() +/// Construct a new `rustc` aux-build invocation. +pub fn aux_build() -> Rustc { + Rustc::new_aux_build() } +/// A `rustc` invocation builder. #[derive(Debug)] -pub struct RustcInvocationBuilder { +pub struct Rustc { cmd: Command, } -impl RustcInvocationBuilder { - fn new() -> Self { +impl Rustc { + // `rustc` invocation constructor methods + + /// Construct a new `rustc` invocation. + pub fn new() -> Self { let cmd = setup_common_build_cmd(); Self { cmd } } - pub fn arg(&mut self, arg: &str) -> &mut RustcInvocationBuilder { - self.cmd.arg(arg); + /// Construct a new `rustc` invocation with `aux_build` preset (setting `--crate-type=lib`). + pub fn new_aux_build() -> Self { + let mut cmd = setup_common_build_cmd(); + cmd.arg("--crate-type=lib"); + Self { cmd } + } + + // Argument provider methods + + /// Configure the compilation environment. + pub fn cfg(&mut self, s: &str) -> &mut Self { + self.cmd.arg("--cfg"); + self.cmd.arg(s); self } - pub fn args(&mut self, args: &[&str]) -> &mut RustcInvocationBuilder { - self.cmd.args(args); + /// Specify default optimization level `-O` (alias for `-C opt-level=2`). + pub fn opt(&mut self) -> &mut Self { + self.cmd.arg("-O"); self } - #[track_caller] - pub fn run(&mut self) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); + /// Specify type(s) of output files to generate. + pub fn emit(&mut self, kinds: &str) -> &mut Self { + self.cmd.arg(format!("--emit={kinds}")); + self + } - let output = self.cmd.output().unwrap(); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); - } - output + /// Specify where an external library is located. + pub fn extern_>(&mut self, crate_name: &str, path: P) -> &mut Self { + assert!( + !crate_name.contains(|c: char| c.is_whitespace() || c == '\\' || c == '/'), + "crate name cannot contain whitespace or path separators" + ); + + let path = path.as_ref().to_string_lossy(); + + self.cmd.arg("--extern"); + self.cmd.arg(format!("{crate_name}={path}")); + + self } -} -#[derive(Debug)] -pub struct AuxBuildInvocationBuilder { - cmd: Command, -} + /// Specify path to the input file. + pub fn input>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } -impl AuxBuildInvocationBuilder { - fn new() -> Self { - let mut cmd = setup_common_build_cmd(); - cmd.arg("--crate-type=lib"); - Self { cmd } + /// Specify target triple. + pub fn target(&mut self, target: &str) -> &mut Self { + assert!(!target.contains(char::is_whitespace), "target triple cannot contain spaces"); + self.cmd.arg(format!("--target={target}")); + self } - pub fn arg(&mut self, arg: &str) -> &mut AuxBuildInvocationBuilder { + /// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`. + /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z ` or `-C ` + /// is passed (note the space). + pub fn arg(&mut self, arg: &str) -> &mut Self { + assert!( + !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")), + "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`" + ); self.cmd.arg(arg); self } + /// Generic command arguments provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`. + /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z ` or `-C ` + /// is passed (note the space). + pub fn args(&mut self, args: &[&str]) -> &mut Self { + for arg in args { + assert!( + !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")), + "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`" + ); + } + + self.cmd.args(args); + self + } + + // Command inspection, output and running helper methods + + /// Get the [`Output`][std::process::Output] of the finished `rustc` process. + pub fn output(&mut self) -> Output { + self.cmd.output().unwrap() + } + + /// Run the constructed `rustc` command and assert that it is successfully run. #[track_caller] pub fn run(&mut self) -> Output { let caller_location = std::panic::Location::caller(); @@ -95,66 +156,10 @@ impl AuxBuildInvocationBuilder { } output } -} - -fn run_common(bin_name: &str) -> (Command, Output) { - let target = env::var("TARGET").unwrap(); - - let bin_name = - if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() }; - - let mut bin_path = PathBuf::new(); - bin_path.push(env::var("TMPDIR").unwrap()); - bin_path.push(&bin_name); - let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap(); - let mut cmd = Command::new(bin_path); - cmd.env(&ld_lib_path_envvar, { - let mut paths = vec![]; - paths.push(PathBuf::from(env::var("TMPDIR").unwrap())); - for p in env::split_paths(&env::var("TARGET_RPATH_ENV").unwrap()) { - paths.push(p.to_path_buf()); - } - for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) { - paths.push(p.to_path_buf()); - } - env::join_paths(paths.iter()).unwrap() - }); - if target.contains("windows") { - let mut paths = vec![]; - for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) { - paths.push(p.to_path_buf()); - } - paths.push(Path::new(&std::env::var("TARGET_RPATH_DIR").unwrap()).to_path_buf()); - cmd.env("PATH", env::join_paths(paths.iter()).unwrap()); - } - - let output = cmd.output().unwrap(); - (cmd, output) -} - -/// Run a built binary and make sure it succeeds. -#[track_caller] -pub fn run(bin_name: &str) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let (cmd, output) = run_common(bin_name); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); - } - output -} - -/// Run a built binary and make sure it fails. -#[track_caller] -pub fn run_fail(bin_name: &str) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let (cmd, output) = run_common(bin_name); - if output.status.success() { - handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); + /// Inspect what the underlying [`Command`] is up to the current construction. + pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self { + f(&self.cmd); + self } - output } diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs new file mode 100644 index 0000000000000..42dcf54da22e0 --- /dev/null +++ b/src/tools/run-make-support/src/run.rs @@ -0,0 +1,67 @@ +use std::env; +use std::path::{Path, PathBuf}; +use std::process::{Command, Output}; + +use super::handle_failed_output; + +fn run_common(bin_name: &str) -> (Command, Output) { + let target = env::var("TARGET").unwrap(); + + let bin_name = + if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() }; + + let mut bin_path = PathBuf::new(); + bin_path.push(env::var("TMPDIR").unwrap()); + bin_path.push(&bin_name); + let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap(); + let mut cmd = Command::new(bin_path); + cmd.env(&ld_lib_path_envvar, { + let mut paths = vec![]; + paths.push(PathBuf::from(env::var("TMPDIR").unwrap())); + for p in env::split_paths(&env::var("TARGET_RPATH_ENV").unwrap()) { + paths.push(p.to_path_buf()); + } + for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) { + paths.push(p.to_path_buf()); + } + env::join_paths(paths.iter()).unwrap() + }); + + if target.contains("windows") { + let mut paths = vec![]; + for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) { + paths.push(p.to_path_buf()); + } + paths.push(Path::new(&std::env::var("TARGET_RPATH_DIR").unwrap()).to_path_buf()); + cmd.env("PATH", env::join_paths(paths.iter()).unwrap()); + } + + let output = cmd.output().unwrap(); + (cmd, output) +} + +/// Run a built binary and make sure it succeeds. +#[track_caller] +pub fn run(bin_name: &str) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let (cmd, output) = run_common(bin_name); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); + } + output +} + +/// Run a built binary and make sure it fails. +#[track_caller] +pub fn run_fail(bin_name: &str) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let (cmd, output) = run_common(bin_name); + if output.status.success() { + handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); + } + output +} diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs index 586f4e4095fc3..1204260a2f46f 100644 --- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs +++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs @@ -1,24 +1,25 @@ // ignore-tidy-linelength +// Check that the `CURRENT_RUSTC_VERSION` placeholder is correctly replaced by the current +// `rustc` version and the `since` property in feature stability gating is properly respected. + extern crate run_make_support; use std::path::PathBuf; -use run_make_support::{aux_build, rustc}; +use run_make_support::{rustc, aux_build}; fn main() { - aux_build() - .arg("--emit=metadata") - .arg("stable.rs") - .run(); + aux_build().input("stable.rs").emit("metadata").run(); + let mut stable_path = PathBuf::from(env!("TMPDIR")); stable_path.push("libstable.rmeta"); + let output = rustc() - .arg("--emit=metadata") - .arg("--extern") - .arg(&format!("stable={}", &stable_path.to_string_lossy())) - .arg("main.rs") - .run(); + .input("main.rs") + .emit("metadata") + .extern_("stable", &stable_path) + .output(); let stderr = String::from_utf8_lossy(&output.stderr); let version = include_str!(concat!(env!("S"), "/src/version")); diff --git a/tests/run-make/a-b-a-linker-guard/rmake.rs b/tests/run-make/a-b-a-linker-guard/rmake.rs index ef4813e121402..ffc1b2000b90c 100644 --- a/tests/run-make/a-b-a-linker-guard/rmake.rs +++ b/tests/run-make/a-b-a-linker-guard/rmake.rs @@ -1,44 +1,36 @@ // ignore-tidy-linelength +// Test that if we build `b` against a version of `a` that has one set of types, it will not run +// with a dylib that has a different set of types. + extern crate run_make_support; use run_make_support::{run, run_fail, rustc}; fn main() { rustc() - .arg("a.rs") - .arg("--cfg") - .arg("x") - .arg("-C") - .arg("prefer-dynamic") - .arg("-Z") - .arg("unstable-options") - .arg("-C") - .arg("symbol-mangling-version=legacy") + .input("a.rs") + .cfg("x") + .arg("-Zunstable-options") + .arg("-Cprefer-dynamic") + .arg("-Csymbol-mangling-version=legacy") .run(); rustc() - .arg("b.rs") - .arg("-C") - .arg("prefer-dynamic") - .arg("-Z") - .arg("unstable-options") - .arg("-C") - .arg("symbol-mangling-version=legacy") - .run(); + .input("b.rs") + .arg("-Zunstable-options") + .arg("-Cprefer-dynamic") + .arg("-Csymbol-mangling-version=legacy") + .run(); run("b"); rustc() - .arg("a.rs") - .arg("--cfg") - .arg("y") - .arg("-C") - .arg("prefer-dynamic") - .arg("-Z") - .arg("unstable-options") - .arg("-C") - .arg("symbol-mangling-version=legacy") + .input("a.rs") + .cfg("y") + .arg("-Zunstable-options") + .arg("-Cprefer-dynamic") + .arg("-Csymbol-mangling-version=legacy") .run(); run_fail("b"); diff --git a/tests/run-make/wasm-abi/rmake.rs b/tests/run-make/wasm-abi/rmake.rs index 07b826ae6fe12..4b7e39d21adfa 100644 --- a/tests/run-make/wasm-abi/rmake.rs +++ b/tests/run-make/wasm-abi/rmake.rs @@ -9,7 +9,8 @@ fn main() { return; } - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").run(); + rustc().input("foo.rs").target("wasm32-wasip1").run(); + let file = out_dir().join("foo.wasm"); let has_wasmtime = match Command::new("wasmtime").arg("--version").output() { diff --git a/tests/run-make/wasm-custom-section/rmake.rs b/tests/run-make/wasm-custom-section/rmake.rs index 9ad152695eca3..0921f2db36b0f 100644 --- a/tests/run-make/wasm-custom-section/rmake.rs +++ b/tests/run-make/wasm-custom-section/rmake.rs @@ -1,6 +1,6 @@ extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{out_dir, wasmparser, rustc}; use std::collections::HashMap; fn main() { @@ -8,8 +8,8 @@ fn main() { return; } - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").run(); - rustc().arg("bar.rs").arg("--target=wasm32-wasip1").arg("-Clto").arg("-O").run(); + rustc().input("foo.rs").target("wasm32-wasip1").run(); + rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); let file = std::fs::read(&out_dir().join("bar.wasm")).unwrap(); diff --git a/tests/run-make/wasm-custom-sections-opt/rmake.rs b/tests/run-make/wasm-custom-sections-opt/rmake.rs index db31d6b716391..0f75f33b8454f 100644 --- a/tests/run-make/wasm-custom-sections-opt/rmake.rs +++ b/tests/run-make/wasm-custom-sections-opt/rmake.rs @@ -1,6 +1,6 @@ extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{out_dir, wasmparser, rustc}; use std::collections::HashMap; use std::path::Path; @@ -9,7 +9,8 @@ fn main() { return; } - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-O").run(); + rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); + verify(&out_dir().join("foo.wasm")); } diff --git a/tests/run-make/wasm-export-all-symbols/rmake.rs b/tests/run-make/wasm-export-all-symbols/rmake.rs index e3b118279b757..11dbf4fcf184e 100644 --- a/tests/run-make/wasm-export-all-symbols/rmake.rs +++ b/tests/run-make/wasm-export-all-symbols/rmake.rs @@ -1,6 +1,6 @@ extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{out_dir, wasmparser, rustc}; use std::collections::HashMap; use std::path::Path; use wasmparser::ExternalKind::*; @@ -17,9 +17,10 @@ fn main() { fn test(args: &[&str]) { eprintln!("running with {args:?}"); - rustc().arg("bar.rs").arg("--target=wasm32-wasip1").args(args).run(); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").args(args).run(); - rustc().arg("main.rs").arg("--target=wasm32-wasip1").args(args).run(); + + rustc().input("bar.rs").target("wasm32-wasip1").args(args).run(); + rustc().input("foo.rs").target("wasm32-wasip1").args(args).run(); + rustc().input("main.rs").target("wasm32-wasip1").args(args).run(); verify_exports( &out_dir().join("foo.wasm"), diff --git a/tests/run-make/wasm-import-module/rmake.rs b/tests/run-make/wasm-import-module/rmake.rs index e521b5b0983ac..4911af4870742 100644 --- a/tests/run-make/wasm-import-module/rmake.rs +++ b/tests/run-make/wasm-import-module/rmake.rs @@ -1,6 +1,6 @@ extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{out_dir, wasmparser, rustc}; use std::collections::HashMap; use wasmparser::TypeRef::Func; @@ -9,8 +9,13 @@ fn main() { return; } - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").run(); - rustc().arg("bar.rs").arg("--target=wasm32-wasip1").arg("-Clto").arg("-O").run(); + rustc().input("foo.rs").target("wasm32-wasip1").run(); + rustc() + .input("bar.rs") + .target("wasm32-wasip1") + .arg("-Clto") + .opt() + .run(); let file = std::fs::read(&out_dir().join("bar.wasm")).unwrap(); diff --git a/tests/run-make/wasm-panic-small/rmake.rs b/tests/run-make/wasm-panic-small/rmake.rs index 0260485f74475..e4e18934abe95 100644 --- a/tests/run-make/wasm-panic-small/rmake.rs +++ b/tests/run-make/wasm-panic-small/rmake.rs @@ -17,13 +17,13 @@ fn main() { fn test(cfg: &str) { eprintln!("running cfg {cfg:?}"); + rustc() - .arg("foo.rs") - .arg("--target=wasm32-wasip1") + .input("foo.rs") + .target("wasm32-wasip1") .arg("-Clto") - .arg("-O") - .arg("--cfg") - .arg(cfg) + .opt() + .cfg(cfg) .run(); let bytes = std::fs::read(&out_dir().join("foo.wasm")).unwrap(); diff --git a/tests/run-make/wasm-spurious-import/rmake.rs b/tests/run-make/wasm-spurious-import/rmake.rs index 0ac9104bfb4e8..ab52eb83f0262 100644 --- a/tests/run-make/wasm-spurious-import/rmake.rs +++ b/tests/run-make/wasm-spurious-import/rmake.rs @@ -1,8 +1,7 @@ extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{out_dir, wasmparser, rustc}; use std::collections::HashMap; -use wasmparser::TypeRef::Func; fn main() { if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { @@ -10,9 +9,9 @@ fn main() { } rustc() - .arg("main.rs") - .arg("--target=wasm32-wasip1") - .arg("-Coverflow-checks=yes") + .input("main.rs") + .target("wasm32-wasip1") + .arg("-Coverflow-checks") .arg("-Cpanic=abort") .arg("-Clto") .arg("-Copt-level=z") diff --git a/tests/run-make/wasm-stringify-ints-small/rmake.rs b/tests/run-make/wasm-stringify-ints-small/rmake.rs index 80cff7acdf419..ce6707dbb6370 100644 --- a/tests/run-make/wasm-stringify-ints-small/rmake.rs +++ b/tests/run-make/wasm-stringify-ints-small/rmake.rs @@ -9,7 +9,12 @@ fn main() { return; } - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-Clto").arg("-O").run(); + rustc() + .input("foo.rs") + .target("wasm32-wasip1") + .arg("-Clto") + .opt() + .run(); let bytes = std::fs::read(&out_dir().join("foo.wasm")).unwrap(); println!("{}", bytes.len()); diff --git a/tests/run-make/wasm-symbols-different-module/rmake.rs b/tests/run-make/wasm-symbols-different-module/rmake.rs index c3cc1e0c32b71..07e612bfd5d40 100644 --- a/tests/run-make/wasm-symbols-different-module/rmake.rs +++ b/tests/run-make/wasm-symbols-different-module/rmake.rs @@ -1,6 +1,6 @@ extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{out_dir, wasmparser, rustc}; use std::collections::{HashMap, HashSet}; fn main() { @@ -24,7 +24,7 @@ fn test_file(file: &str, expected_imports: &[(&str, &[&str])]) { fn test(file: &str, args: &[&str], expected_imports: &[(&str, &[&str])]) { println!("test {file:?} {args:?} for {expected_imports:?}"); - rustc().arg(file).arg("--target=wasm32-wasip1").args(args).run(); + rustc().input(file).target("wasm32-wasip1").args(args).run(); let file = std::fs::read(&out_dir().join(file).with_extension("wasm")).unwrap(); diff --git a/tests/run-make/wasm-symbols-not-exported/rmake.rs b/tests/run-make/wasm-symbols-not-exported/rmake.rs index 5ff0dc578b341..7b7701cd7b3c3 100644 --- a/tests/run-make/wasm-symbols-not-exported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-exported/rmake.rs @@ -1,6 +1,6 @@ extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{out_dir, wasmparser, rustc}; use std::path::Path; fn main() { @@ -8,14 +8,14 @@ fn main() { return; } - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").run(); + rustc().input("foo.rs").target("wasm32-wasip1").run(); verify_symbols(&out_dir().join("foo.wasm")); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-O").run(); + rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); verify_symbols(&out_dir().join("foo.wasm")); - rustc().arg("bar.rs").arg("--target=wasm32-wasip1").run(); + rustc().input("bar.rs").target("wasm32-wasip1").run(); verify_symbols(&out_dir().join("bar.wasm")); - rustc().arg("bar.rs").arg("--target=wasm32-wasip1").arg("-O").run(); + rustc().input("bar.rs").target("wasm32-wasip1").opt().run(); verify_symbols(&out_dir().join("bar.wasm")); } diff --git a/tests/run-make/wasm-symbols-not-imported/rmake.rs b/tests/run-make/wasm-symbols-not-imported/rmake.rs index 974f415166b9f..956d62fe3af05 100644 --- a/tests/run-make/wasm-symbols-not-imported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-imported/rmake.rs @@ -1,6 +1,6 @@ extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{out_dir, wasmparser, rustc}; use std::path::Path; fn main() { @@ -8,13 +8,13 @@ fn main() { return; } - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").run(); + rustc().input("foo.rs").target("wasm32-wasip1").run(); verify_symbols(&out_dir().join("foo.wasm")); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-Clto").run(); + rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").run(); verify_symbols(&out_dir().join("foo.wasm")); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-O").run(); + rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); verify_symbols(&out_dir().join("foo.wasm")); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-Clto").arg("-O").run(); + rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); verify_symbols(&out_dir().join("foo.wasm")); } From 246f7465b35f827d200eba25a1c27fddd18d7962 Mon Sep 17 00:00:00 2001 From: Luv-Ray Date: Sat, 23 Mar 2024 23:33:43 +0800 Subject: [PATCH 26/32] Add test in `higher-ranked` --- .../structually-relate-aliases.rs | 17 ++++++++++++ .../structually-relate-aliases.stderr | 27 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/ui/higher-ranked/structually-relate-aliases.rs create mode 100644 tests/ui/higher-ranked/structually-relate-aliases.stderr diff --git a/tests/ui/higher-ranked/structually-relate-aliases.rs b/tests/ui/higher-ranked/structually-relate-aliases.rs new file mode 100644 index 0000000000000..8df24702811dd --- /dev/null +++ b/tests/ui/higher-ranked/structually-relate-aliases.rs @@ -0,0 +1,17 @@ +// regression test for issue #121649. + +trait ToUnit<'a> { + type Unit; +} + +trait Overlap {} + +type Assoc<'a, T> = >::Unit; + +impl Overlap for T {} + +impl Overlap fn(&'a (), Assoc<'a, T>)> for T {} +//~^ ERROR 13:17: 13:49: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied [E0277] +//~| ERROR 13:36: 13:48: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied [E0277] + +fn main() {} diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr new file mode 100644 index 0000000000000..59fab52b221e2 --- /dev/null +++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr @@ -0,0 +1,27 @@ +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) } +error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied + --> $DIR/structually-relate-aliases.rs:13:36 + | +LL | impl Overlap fn(&'a (), Assoc<'a, T>)> for T {} + | ^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl ToUnit<'a>> Overlap fn(&'a (), Assoc<'a, T>)> for T {} + | ++++++++++++++++++++ + +error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied + --> $DIR/structually-relate-aliases.rs:13:17 + | +LL | impl Overlap fn(&'a (), Assoc<'a, T>)> for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl ToUnit<'a>> Overlap fn(&'a (), Assoc<'a, T>)> for T {} + | ++++++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From 188c46a65e40b3a69b43874dc7fee72d986e9ca5 Mon Sep 17 00:00:00 2001 From: Kalle Wachsmuth Date: Mon, 19 Feb 2024 01:01:11 +0100 Subject: [PATCH 27/32] regression test for #103626 --- ...onicalize-fresh-infer-vars-issue-103626.rs | 15 +++++++++ ...alize-fresh-infer-vars-issue-103626.stderr | 33 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs create mode 100644 tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs new file mode 100644 index 0000000000000..3af299e5b115a --- /dev/null +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs @@ -0,0 +1,15 @@ +trait FromResidual::Residual> { + fn from_residual(residual: R) -> Self; +} + +trait Try { + type Residual; +} + +fn w<'a, T: 'a, F: Fn(&'a T)>() { + let b: &dyn FromResidual = &(); + //~^ ERROR: the trait `FromResidual` cannot be made into an object + //~| ERROR: the trait `FromResidual` cannot be made into an object +} + +fn main() {} diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr new file mode 100644 index 0000000000000..d5e9b1be63b0b --- /dev/null +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr @@ -0,0 +1,33 @@ +error[E0038]: the trait `FromResidual` cannot be made into an object + --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:17 + | +LL | let b: &dyn FromResidual = &(); + | ^^^^^^^^^^^^ + | + = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause + +error[E0038]: the trait `FromResidual` cannot be made into an object + --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:12 + | +LL | let b: &dyn FromResidual = &(); + | ^^^^^^^^^^^^^^^^^ `FromResidual` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8 + | +LL | trait FromResidual::Residual> { + | ------------ this trait cannot be made into an object... +LL | fn from_residual(residual: R) -> Self; + | ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter +help: consider turning `from_residual` into a method by giving it a `&self` argument + | +LL | fn from_residual(&self, residual: R) -> Self; + | ++++++ +help: alternatively, consider constraining `from_residual` so it does not apply to trait objects + | +LL | fn from_residual(residual: R) -> Self where Self: Sized; + | +++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. From 7967915c7b456d59fd963260822d3cf583969948 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Fri, 15 Mar 2024 19:45:46 +0000 Subject: [PATCH 28/32] 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 29/32] 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 30/32] 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 e74b01e9256579b285962b148a6f640bc44c0b5d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Mar 2024 21:36:22 +0100 Subject: [PATCH 31/32] core/panicking: fix outdated comment --- library/core/src/panicking.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 9e8dac888166c..a8940d9cd1eb0 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -132,11 +132,11 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo #[rustc_const_unstable(feature = "panic_internals", issue = "none")] #[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators pub const fn panic(expr: &'static str) -> ! { - // Use Arguments::new_v1 instead of format_args!("{expr}") to potentially + // Use Arguments::new_const instead of format_args!("{expr}") to potentially // reduce size overhead. The format_args! macro uses str's Display trait to // write expr, which calls Formatter::pad, which must accommodate string // truncation and padding (even though none is used here). Using - // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the + // Arguments::new_const may allow the compiler to omit Formatter::pad from the // output binary, saving up to a few kilobytes. panic_fmt(fmt::Arguments::new_const(&[expr])); } From 66f1e14cc3fa48aa29ecd19274207bfd3fb08fa8 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sat, 23 Mar 2024 17:24:13 -0700 Subject: [PATCH 32/32] 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, '*');