From a2a2f30415ffdcfad86cd5f9948e7cfc415164c4 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 25 Mar 2024 06:21:42 +0100 Subject: [PATCH 01/24] test-aux-bin.rs: Clarify that it is aux-bin that blocks cross-compile run-pass --- tests/ui/compiletest-self-test/test-aux-bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/compiletest-self-test/test-aux-bin.rs b/tests/ui/compiletest-self-test/test-aux-bin.rs index 9e01e3ffabf..c1c28e12b3b 100644 --- a/tests/ui/compiletest-self-test/test-aux-bin.rs +++ b/tests/ui/compiletest-self-test/test-aux-bin.rs @@ -1,4 +1,4 @@ -//@ ignore-cross-compile because we run the compiled code +//@ ignore-cross-compile because aux-bin does not yet support it //@ aux-bin: print-it-works.rs //@ run-pass From 71eb763d23c0406b14237be60c651d52c64d29b6 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 24 Feb 2024 16:48:24 +0100 Subject: [PATCH 02/24] unix_sigpipe: Add test for SIGPIPE disposition in child processes For robustness, also test the disposition in our own process even if other tests in `tests/ui/attributes/unix_sigpipe` already covers it. --- .../auxiliary/assert-sigpipe-disposition.rs | 34 +++++++++++ .../unix_sigpipe-and-child-processes.rs | 56 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs create mode 100644 tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs diff --git a/tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs new file mode 100644 index 00000000000..117f6134b4e --- /dev/null +++ b/tests/ui/attributes/unix_sigpipe/auxiliary/assert-sigpipe-disposition.rs @@ -0,0 +1,34 @@ +// It is UB to unwind out of `fn start()` according to +// https://doc.rust-lang.org/beta/unstable-book/language-features/start.html so +// panic with abort to avoid UB: +//@ compile-flags: -Cpanic=abort +//@ no-prefer-dynamic so panic=abort works + +#![feature(start, rustc_private)] + +extern crate libc; + +// Use #[start] so we don't have a runtime that messes with SIGPIPE. +#[start] +fn start(argc: isize, argv: *const *const u8) -> isize { + assert_eq!(argc, 2, "Must pass SIG_IGN or SIG_DFL as first arg"); + let arg1 = unsafe { std::ffi::CStr::from_ptr(*argv.offset(1) as *const libc::c_char) } + .to_str() + .unwrap(); + + let expected = match arg1 { + "SIG_IGN" => libc::SIG_IGN, + "SIG_DFL" => libc::SIG_DFL, + arg => panic!("Must pass SIG_IGN or SIG_DFL as first arg. Got: {}", arg), + }; + + let actual = unsafe { + let mut actual: libc::sigaction = std::mem::zeroed(); + libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual); + actual.sa_sigaction + }; + + assert_eq!(actual, expected, "actual and expected SIGPIPE disposition in child differs"); + + 0 +} diff --git a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs new file mode 100644 index 00000000000..f96bd634876 --- /dev/null +++ b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-and-child-processes.rs @@ -0,0 +1,56 @@ +//@ revisions: default sig_dfl sig_ign inherit +//@ ignore-cross-compile because aux-bin does not yet support it +//@ only-unix because SIGPIPE is a unix thing +//@ run-pass +//@ aux-bin:assert-sigpipe-disposition.rs +//@ aux-crate:sigpipe_utils=sigpipe-utils.rs + +// Checks the signal disposition of `SIGPIPE` in child processes, and in our own +// process for robustness. Without any `unix_sigpipe` attribute, `SIG_IGN` is +// the default. But there is a difference in how `SIGPIPE` is treated in child +// processes with and without the attribute. Search for +// `unix_sigpipe_attr_specified()` in the code base to learn more. + +#![feature(rustc_private)] +#![cfg_attr(any(sig_dfl, sig_ign, inherit), feature(unix_sigpipe))] + +extern crate libc; +extern crate sigpipe_utils; + +use sigpipe_utils::*; + +#[cfg_attr(sig_dfl, unix_sigpipe = "sig_dfl")] +#[cfg_attr(sig_ign, unix_sigpipe = "sig_ign")] +#[cfg_attr(inherit, unix_sigpipe = "inherit")] +fn main() { + // By default we get SIG_IGN but the child gets SIG_DFL through an explicit + // reset before exec: + // https://github.com/rust-lang/rust/blob/bf4de3a874753bbee3323081c8b0c133444fed2d/library/std/src/sys/pal/unix/process/process_unix.rs#L363-L384 + #[cfg(default)] + let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_DFL"); + + // With #[unix_sigpipe = "sig_dfl"] we get SIG_DFL and the child does too + // without any special code running before exec. + #[cfg(sig_dfl)] + let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL"); + + // With #[unix_sigpipe = "sig_ign"] we get SIG_IGN and the child does too + // without any special code running before exec. + #[cfg(sig_ign)] + let (we_expect, child_expects) = (SignalHandler::Ignore, "SIG_IGN"); + + // With #[unix_sigpipe = "inherit"] we get SIG_DFL and the child does too + // without any special code running before exec. + #[cfg(inherit)] + let (we_expect, child_expects) = (SignalHandler::Default, "SIG_DFL"); + + assert_sigpipe_handler(we_expect); + + assert!( + std::process::Command::new("./auxiliary/bin/assert-sigpipe-disposition") + .arg(child_expects) + .status() + .unwrap() + .success() + ); +} From 08c7ff22645cbb661edd67a8a30cf3dd67a07c23 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 28 Mar 2024 12:10:44 -0400 Subject: [PATCH 03/24] Restrict const ty's regions to static when putting them in canonical var list --- compiler/rustc_middle/src/ty/region.rs | 4 + .../src/canonicalizer.rs | 79 +++++++++++++------ compiler/rustc_type_ir/src/interner.rs | 5 +- compiler/rustc_type_ir/src/new.rs | 2 + .../regions-in-canonical.rs | 23 ++++++ .../regions-in-canonical.stderr | 11 +++ 6 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 tests/ui/coherence/negative-coherence/regions-in-canonical.rs create mode 100644 tests/ui/coherence/negative-coherence/regions-in-canonical.stderr diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 867faf63261..b92800a1728 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -140,6 +140,10 @@ impl<'tcx> rustc_type_ir::new::Region> for Region<'tcx> { fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon }) } + + fn new_static(tcx: TyCtxt<'tcx>) -> Self { + tcx.lifetimes.re_static + } } /// Region utilities diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 16d8453ea24..a7148c88864 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -382,43 +382,47 @@ impl, I: Interner> TypeFolder where I::Const: TypeSuperFoldable, { + // We could canonicalize all consts with static types, but the only ones we + // *really* need to worry about are the ones that we end up putting into `CanonicalVarKind` + // since canonical vars can't reference other canonical vars. + let ty = c + .ty() + .fold_with(&mut RegionsToStatic { interner: self.interner(), binder: ty::INNERMOST }); let kind = match c.kind() { - ty::ConstKind::Infer(i) => { - // FIXME: we should fold the ty too eventually - match i { - ty::InferConst::Var(vid) => { - assert_eq!( - self.infcx.root_ct_var(vid), - vid, - "region vid should have been resolved fully before canonicalization" - ); - assert_eq!( - self.infcx.probe_ct_var(vid), - None, - "region vid should have been resolved fully before canonicalization" - ); - CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), c.ty()) - } - ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect, - ty::InferConst::Fresh(_) => todo!(), + ty::ConstKind::Infer(i) => match i { + ty::InferConst::Var(vid) => { + assert_eq!( + self.infcx.root_ct_var(vid), + vid, + "region vid should have been resolved fully before canonicalization" + ); + assert_eq!( + self.infcx.probe_ct_var(vid), + None, + "region vid should have been resolved fully before canonicalization" + ); + CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), ty) } - } + ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect, + ty::InferConst::Fresh(_) => todo!(), + }, ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( PlaceholderLike::new(placeholder.universe(), self.variables.len().into()), - c.ty(), + ty, ), CanonicalizeMode::Response { .. } => { - CanonicalVarKind::PlaceholderConst(placeholder, c.ty()) + CanonicalVarKind::PlaceholderConst(placeholder, ty) } }, ty::ConstKind::Param(_) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()), - c.ty(), + ty, ), CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"), }, + // FIXME: See comment above -- we could fold the region separately or something. ty::ConstKind::Bound(_, _) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Value(_) @@ -435,6 +439,35 @@ impl, I: Interner> TypeFolder }), ); - Const::new_anon_bound(self.interner(), self.binder_index, var, c.ty()) + Const::new_anon_bound(self.interner(), self.binder_index, var, ty) + } +} + +struct RegionsToStatic { + interner: I, + binder: ty::DebruijnIndex, +} + +impl TypeFolder for RegionsToStatic { + fn interner(&self) -> I { + self.interner + } + + fn fold_binder(&mut self, t: I::Binder) -> I::Binder + where + T: TypeFoldable, + I::Binder: TypeSuperFoldable, + { + self.binder.shift_in(1); + let t = t.fold_with(self); + self.binder.shift_out(1); + t + } + + fn fold_region(&mut self, r: I::Region) -> I::Region { + match r.kind() { + ty::ReBound(db, _) if self.binder > db => r, + _ => Region::new_static(self.interner()), + } } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index ae1e1902f14..d941195eecc 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -2,13 +2,14 @@ use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; +use crate::fold::TypeSuperFoldable; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{ new, BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebugWithInfcx, RegionKind, TyKind, UniverseIndex, }; -pub trait Interner: Sized { +pub trait Interner: Sized + Copy { type DefId: Copy + Debug + Hash + Eq; type AdtDef: Copy + Debug + Hash + Eq; @@ -34,6 +35,7 @@ pub trait Interner: Sized { + Into + IntoKind> + TypeSuperVisitable + + TypeSuperFoldable + Flags + new::Ty; type Tys: Copy + Debug + Hash + Eq + IntoIterator; @@ -57,6 +59,7 @@ pub trait Interner: Sized { + IntoKind> + ConstTy + TypeSuperVisitable + + TypeSuperFoldable + Flags + new::Const; type AliasConst: Copy + DebugWithInfcx + Hash + Eq; diff --git a/compiler/rustc_type_ir/src/new.rs b/compiler/rustc_type_ir/src/new.rs index e7e695e5908..1572a641d06 100644 --- a/compiler/rustc_type_ir/src/new.rs +++ b/compiler/rustc_type_ir/src/new.rs @@ -6,6 +6,8 @@ pub trait Ty> { pub trait Region> { fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; + + fn new_static(interner: I) -> Self; } pub trait Const> { diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.rs b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs new file mode 100644 index 00000000000..6c2a11e0135 --- /dev/null +++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs @@ -0,0 +1,23 @@ +//@ check-pass + +#![feature(adt_const_params)] +//~^ WARN the feature `adt_const_params` is incomplete +#![feature(with_negative_coherence, negative_impls)] + +pub trait A {} +pub trait C {} + + +struct W(T); + +// Negative coherence: +// Proving `W: !A<"">` requires proving `CONST alias-eq ""`, which requires proving +// `CONST normalizes-to (?1c: &str)`. The type's region is uniquified, so it ends up being +// put in to the canonical vars list with an infer region => ICE. +impl C for T where T: A<""> {} +impl C for W {} + +impl !A for W {} +const CONST: &str = ""; + +fn main() {} diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr new file mode 100644 index 00000000000..dc8c926f182 --- /dev/null +++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr @@ -0,0 +1,11 @@ +warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/regions-in-canonical.rs:3:12 + | +LL | #![feature(adt_const_params)] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #95174 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + From 6439c7fe238d14f10b9b4cfae328ec408e8dfde4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 28 Mar 2024 12:17:17 -0400 Subject: [PATCH 04/24] Require foldability part of interner item bounds, remove redundant where clauses --- .../src/canonicalizer.rs | 10 +--- compiler/rustc_type_ir/src/fold.rs | 51 ++++--------------- compiler/rustc_type_ir/src/interner.rs | 8 ++- 3 files changed, 20 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index a7148c88864..1899517c0e2 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -296,10 +296,7 @@ impl, I: Interner> TypeFolder Region::new_anon_bound(self.interner(), self.binder_index, var) } - fn fold_ty(&mut self, t: I::Ty) -> I::Ty - where - I::Ty: TypeSuperFoldable, - { + fn fold_ty(&mut self, t: I::Ty) -> I::Ty { let kind = match t.kind() { ty::Infer(i) => match i { ty::TyVar(vid) => { @@ -378,10 +375,7 @@ impl, I: Interner> TypeFolder Ty::new_anon_bound(self.interner(), self.binder_index, var) } - fn fold_const(&mut self, c: I::Const) -> I::Const - where - I::Const: TypeSuperFoldable, - { + fn fold_const(&mut self, c: I::Const) -> I::Const { // We could canonicalize all consts with static types, but the only ones we // *really* need to worry about are the ones that we end up putting into `CanonicalVarKind` // since canonical vars can't reference other canonical vars. diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 8d402588398..01bb3d73dbd 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -136,31 +136,21 @@ pub trait TypeFolder: FallibleTypeFolder { t.super_fold_with(self) } - fn fold_ty(&mut self, t: I::Ty) -> I::Ty - where - I::Ty: TypeSuperFoldable, - { + fn fold_ty(&mut self, t: I::Ty) -> I::Ty { t.super_fold_with(self) } // The default region folder is a no-op because `Region` is non-recursive - // and has no `super_fold_with` method to call. That also explains the - // lack of `I::Region: TypeSuperFoldable` bound on this method. + // and has no `super_fold_with` method to call. fn fold_region(&mut self, r: I::Region) -> I::Region { r } - fn fold_const(&mut self, c: I::Const) -> I::Const - where - I::Const: TypeSuperFoldable, - { + fn fold_const(&mut self, c: I::Const) -> I::Const { c.super_fold_with(self) } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate - where - I::Predicate: TypeSuperFoldable, - { + fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { p.super_fold_with(self) } } @@ -185,31 +175,21 @@ pub trait FallibleTypeFolder: Sized { t.try_super_fold_with(self) } - fn try_fold_ty(&mut self, t: I::Ty) -> Result - where - I::Ty: TypeSuperFoldable, - { + fn try_fold_ty(&mut self, t: I::Ty) -> Result { t.try_super_fold_with(self) } // The default region folder is a no-op because `Region` is non-recursive - // and has no `super_fold_with` method to call. That also explains the - // lack of `I::Region: TypeSuperFoldable` bound on this method. + // and has no `super_fold_with` method to call. fn try_fold_region(&mut self, r: I::Region) -> Result { Ok(r) } - fn try_fold_const(&mut self, c: I::Const) -> Result - where - I::Const: TypeSuperFoldable, - { + fn try_fold_const(&mut self, c: I::Const) -> Result { c.try_super_fold_with(self) } - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result - where - I::Predicate: TypeSuperFoldable, - { + fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { p.try_super_fold_with(self) } } @@ -234,10 +214,7 @@ where Ok(self.fold_binder(t)) } - fn try_fold_ty(&mut self, t: I::Ty) -> Result - where - I::Ty: TypeSuperFoldable, - { + fn try_fold_ty(&mut self, t: I::Ty) -> Result { Ok(self.fold_ty(t)) } @@ -245,17 +222,11 @@ where Ok(self.fold_region(r)) } - fn try_fold_const(&mut self, c: I::Const) -> Result - where - I::Const: TypeSuperFoldable, - { + fn try_fold_const(&mut self, c: I::Const) -> Result { Ok(self.fold_const(c)) } - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result - where - I::Predicate: TypeSuperFoldable, - { + fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { Ok(self.fold_predicate(p)) } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index d941195eecc..7a2885dd3bb 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -85,7 +85,13 @@ pub trait Interner: Sized + Copy { type PlaceholderRegion: Copy + Debug + Hash + Eq + PlaceholderLike; // Predicates - type Predicate: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; + type Predicate: Copy + + Debug + + Hash + + Eq + + TypeSuperVisitable + + TypeSuperFoldable + + Flags; type TraitPredicate: Copy + Debug + Hash + Eq; type RegionOutlivesPredicate: Copy + Debug + Hash + Eq; type TypeOutlivesPredicate: Copy + Debug + Hash + Eq; From d7d5fc97341ebc127ad716053c3efe6e613ba3a7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 26 Mar 2024 05:22:18 -0400 Subject: [PATCH 05/24] Add basic trait impls for `f16` and `f128` Split off part of so the compiler doesn't ICE because it expects primitives to have some minimal traits. Fixes --- library/core/src/clone.rs | 2 +- library/core/src/cmp.rs | 4 ++-- library/core/src/default.rs | 4 ++++ library/core/src/lib.rs | 2 ++ library/core/src/marker.rs | 2 +- tests/ui/binop/binary-op-suggest-deref.stderr | 6 +++--- tests/ui/mismatched_types/binops.stderr | 12 ++++++------ 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index ba86334f950..d448c5338fc 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -227,7 +227,7 @@ mod impls { impl_clone! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 - f32 f64 + f16 f32 f64 f128 bool char } diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index a2f07814726..3567203384a 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1486,7 +1486,7 @@ mod impls { } partial_eq_impl! { - bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 + bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } macro_rules! eq_impl { @@ -1539,7 +1539,7 @@ mod impls { } } - partial_ord_impl! { f32 f64 } + partial_ord_impl! { f16 f32 f64 f128 } macro_rules! ord_impl { ($($t:ty)*) => ($( diff --git a/library/core/src/default.rs b/library/core/src/default.rs index a5075554682..e717a8d022f 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -178,5 +178,9 @@ default_impl! { i32, 0, "Returns the default value of `0`" } default_impl! { i64, 0, "Returns the default value of `0`" } default_impl! { i128, 0, "Returns the default value of `0`" } +#[cfg(not(bootstrap))] +default_impl! { f16, 0.0f16, "Returns the default value of `0.0`" } default_impl! { f32, 0.0f32, "Returns the default value of `0.0`" } default_impl! { f64, 0.0f64, "Returns the default value of `0.0`" } +#[cfg(not(bootstrap))] +default_impl! { f128, 0.0f128, "Returns the default value of `0.0`" } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 3bc1a87f848..48251e5707b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -229,6 +229,8 @@ #![feature(doc_notable_trait)] #![feature(effects)] #![feature(extern_types)] +#![feature(f128)] +#![feature(f16)] #![feature(freeze_impls)] #![feature(fundamental)] #![feature(generic_arg_infer)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index a56a2578c22..385c288db12 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -422,7 +422,7 @@ marker_impls! { Copy for usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, - f32, f64, + f16, f32, f64, f128, bool, char, {T: ?Sized} *const T, {T: ?Sized} *mut T, diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr index 32bd2554abb..47af51e2106 100644 --- a/tests/ui/binop/binary-op-suggest-deref.stderr +++ b/tests/ui/binop/binary-op-suggest-deref.stderr @@ -247,15 +247,15 @@ LL | _ = &&0 == Foo; | = help: the trait `PartialEq` is not implemented for `&&{integer}` = help: the following other types implement trait `PartialEq`: + f128 + f16 f32 f64 i128 i16 i32 i64 - i8 - isize - and 6 others + and 8 others error[E0369]: binary operation `==` cannot be applied to type `Foo` --> $DIR/binary-op-suggest-deref.rs:60:13 diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr index 3585587ed4c..f8047c8e2d4 100644 --- a/tests/ui/mismatched_types/binops.stderr +++ b/tests/ui/mismatched_types/binops.stderr @@ -73,15 +73,15 @@ LL | 5 < String::new(); | = help: the trait `PartialOrd` is not implemented for `{integer}` = help: the following other types implement trait `PartialOrd`: + f128 + f16 f32 f64 i128 i16 i32 i64 - i8 - isize - and 6 others + and 8 others error[E0277]: can't compare `{integer}` with `Result<{integer}, _>` --> $DIR/binops.rs:7:7 @@ -91,15 +91,15 @@ LL | 6 == Ok(1); | = help: the trait `PartialEq>` is not implemented for `{integer}` = help: the following other types implement trait `PartialEq`: + f128 + f16 f32 f64 i128 i16 i32 i64 - i8 - isize - and 6 others + and 8 others error: aborting due to 6 previous errors From b110cb3dc6da68fc46b08d7b0ed40a48b3503306 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Fri, 29 Mar 2024 03:44:16 +0000 Subject: [PATCH 06/24] Require Debug for Pointee::Metadata Useful for debugging --- library/core/src/ptr/metadata.rs | 2 +- library/core/tests/ptr.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index fe19f66a31a..d3d1b3d053d 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -57,7 +57,7 @@ pub trait Pointee { // NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata` // in `library/core/src/ptr/metadata.rs` // in sync with those here: - type Metadata: Copy + Send + Sync + Ord + Hash + Unpin; + type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin; } /// Pointers to types implementing this trait alias are “thin”. diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 5c518e2d593..f0656f997fd 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -841,11 +841,19 @@ fn ptr_metadata_bounds() { fn static_assert_expected_bounds_for_metadata() where // Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs` - Meta: Copy + Send + Sync + Ord + std::hash::Hash + Unpin, + Meta: Debug + Copy + Send + Sync + Ord + std::hash::Hash + Unpin, { } } +#[test] +fn pointee_metadata_debug() { + assert_eq!("()", format!("{:?}", metadata::(&17))); + assert_eq!("2", format!("{:?}", metadata::<[u32]>(&[19, 23]))); + let for_dyn = format!("{:?}", metadata::(&29)); + assert!(for_dyn.starts_with("DynMetadata(0x"), "{:?}", for_dyn); +} + #[test] fn dyn_metadata() { #[derive(Debug)] From 29c1a2b9e9009287025d620ad6897d1be4897923 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Fri, 29 Mar 2024 16:35:58 +0000 Subject: [PATCH 07/24] KCFI: Require -C panic=abort While the KCFI scheme is not incompatible with unwinding, LLVM's `invoke` instruction does not currently support KCFI bundles. While it likely will in the near future, we won't be able to assume that in Rust for a while. --- compiler/rustc_session/messages.ftl | 2 ++ compiler/rustc_session/src/errors.rs | 4 ++++ compiler/rustc_session/src/session.rs | 5 +++++ tests/ui/sanitizer/cfg.rs | 1 + tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs | 1 + tests/ui/sanitizer/cfi-complex-receiver.rs | 1 + tests/ui/sanitizer/cfi-self-ref.rs | 1 + tests/ui/sanitizer/cfi-virtual-auto.rs | 1 + 8 files changed, 16 insertions(+) diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 179fd79bef7..b8dacc6968d 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -96,6 +96,8 @@ session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto` or `-Cli session_sanitizer_cfi_requires_single_codegen_unit = `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1` +session_sanitizer_kcfi_requires_panic_abort = `-Z sanitizer=kcfi` requires `-C panic=abort` + session_sanitizer_not_supported = {$us} sanitizer is not supported for this target session_sanitizers_not_supported = {$us} sanitizers are not supported for this target diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 0a855f87586..2e4c7d14ecd 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -145,6 +145,10 @@ pub(crate) struct SanitizerCfiGeneralizePointersRequiresCfi; #[diag(session_sanitizer_cfi_normalize_integers_requires_cfi)] pub(crate) struct SanitizerCfiNormalizeIntegersRequiresCfi; +#[derive(Diagnostic)] +#[diag(session_sanitizer_kcfi_requires_panic_abort)] +pub(crate) struct SanitizerKcfiRequiresPanicAbort; + #[derive(Diagnostic)] #[diag(session_split_lto_unit_requires_lto)] pub(crate) struct SplitLtoUnitRequiresLto; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index e6d82d6fab3..9023a0375ee 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1234,6 +1234,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.dcx().emit_err(errors::SanitizerCfiRequiresLto); } + // KCFI requires panic=abort + if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy() != PanicStrategy::Abort { + sess.dcx().emit_err(errors::SanitizerKcfiRequiresPanicAbort); + } + // LLVM CFI using rustc LTO requires a single codegen unit. if sess.is_sanitizer_cfi_enabled() && sess.lto() == config::Lto::Fat diff --git a/tests/ui/sanitizer/cfg.rs b/tests/ui/sanitizer/cfg.rs index 942141bd3fe..b1ba17d5713 100644 --- a/tests/ui/sanitizer/cfg.rs +++ b/tests/ui/sanitizer/cfg.rs @@ -11,6 +11,7 @@ //@[cfi]compile-flags: -Clto -Ccodegen-units=1 //@[kcfi]needs-llvm-components: x86 //@[kcfi]compile-flags: -Zsanitizer=kcfi --cfg kcfi --target x86_64-unknown-none +//@[kcfi]compile-flags: -C panic=abort //@[leak]needs-sanitizer-leak //@[leak]compile-flags: -Zsanitizer=leak --cfg leak //@[memory]needs-sanitizer-memory diff --git a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs index 1ae494d87d4..03818544aab 100644 --- a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs +++ b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs @@ -14,6 +14,7 @@ //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off //@ run-pass pub fn main() { diff --git a/tests/ui/sanitizer/cfi-complex-receiver.rs b/tests/ui/sanitizer/cfi-complex-receiver.rs index 52095a384b2..c7b45a775ca 100644 --- a/tests/ui/sanitizer/cfi-complex-receiver.rs +++ b/tests/ui/sanitizer/cfi-complex-receiver.rs @@ -11,6 +11,7 @@ //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off //@ run-pass use std::sync::Arc; diff --git a/tests/ui/sanitizer/cfi-self-ref.rs b/tests/ui/sanitizer/cfi-self-ref.rs index f8793aec6e2..3b524ac661c 100644 --- a/tests/ui/sanitizer/cfi-self-ref.rs +++ b/tests/ui/sanitizer/cfi-self-ref.rs @@ -9,6 +9,7 @@ //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off //@ run-pass use std::marker::PhantomData; diff --git a/tests/ui/sanitizer/cfi-virtual-auto.rs b/tests/ui/sanitizer/cfi-virtual-auto.rs index 517c3d49f76..6971d516a20 100644 --- a/tests/ui/sanitizer/cfi-virtual-auto.rs +++ b/tests/ui/sanitizer/cfi-virtual-auto.rs @@ -9,6 +9,7 @@ //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off //@ run-pass trait Foo { From 7804edebfec17dec75bd6d2bb67e641434fbaa27 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Fri, 29 Mar 2024 10:10:52 -0700 Subject: [PATCH 08/24] Improve wording in std::any explanation Prefer 'log' over 'log out' to avoid confusion, and use backticks consistently. --- library/core/src/any.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/any.rs b/library/core/src/any.rs index a4252d0c9e0..37cb8e7d303 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -40,10 +40,10 @@ //! //! ## Examples //! -//! Consider a situation where we want to log out a value passed to a function. -//! We know the value we're working on implements Debug, but we don't know its +//! Consider a situation where we want to log a value passed to a function. +//! We know the value we're working on implements `Debug`, but we don't know its //! concrete type. We want to give special treatment to certain types: in this -//! case printing out the length of String values prior to their value. +//! case printing out the length of `String` values prior to their value. //! We don't know the concrete type of our value at compile time, so we need to //! use runtime reflection instead. //! @@ -51,7 +51,7 @@ //! use std::fmt::Debug; //! use std::any::Any; //! -//! // Logger function for any type that implements Debug. +//! // Logger function for any type that implements `Debug`. //! fn log(value: &T) { //! let value_any = value as &dyn Any; //! From d301f40c84c0a65ee7b86a6cdcca3544ab5db0fe Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Sun, 24 Mar 2024 18:56:15 +0000 Subject: [PATCH 09/24] CFI: Encode Virtual calls as calls through the defining trait For example, if `trait Foo: Bar`, and we try to call a method from `Bar` on `dyn Foo`, encode the callsite as passing a `dyn Bar`, not a `dyn Foo`. --- .../src/typeid/typeid_itanium_cxx_abi.rs | 24 +++--- tests/ui/sanitizer/cfi-supertraits.rs | 73 +++++++++++++++++++ 2 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 tests/ui/sanitizer/cfi-supertraits.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 04b92fbd33b..29305896188 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 @@ -1140,8 +1140,17 @@ pub fn typeid_for_instance<'tcx>( let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]); let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn); instance.args = tcx.mk_args_trait(self_ty, List::empty()); - } else if matches!(instance.def, ty::InstanceDef::Virtual(..)) { - instance.args = strip_receiver_auto(tcx, instance.args); + } else if let ty::InstanceDef::Virtual(def_id, _) = instance.def { + let upcast_ty = match tcx.trait_of_item(def_id) { + Some(trait_id) => trait_object_ty( + tcx, + ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)), + ), + // drop_in_place won't have a defining trait, skip the upcast + None => instance.args.type_at(0), + }; + let stripped_ty = strip_receiver_auto(tcx, upcast_ty); + instance.args = tcx.mk_args_trait(stripped_ty, instance.args.into_iter().skip(1)); } if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) @@ -1190,15 +1199,11 @@ 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); +fn strip_receiver_auto<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { let ty::Dynamic(preds, lifetime, kind) = ty.kind() else { bug!("Tried to strip auto traits from non-dynamic type {ty}"); }; - let new_rcvr = if preds.principal().is_some() { + if preds.principal().is_some() { let filtered_preds = tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| { !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..)) @@ -1209,8 +1214,7 @@ fn strip_receiver_auto<'tcx>( // about it. This technically discards the knowledge that it was a type that was made // into a trait object at some point, but that's not a lot. tcx.types.unit - }; - tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1)) + } } #[instrument(skip(tcx), ret)] diff --git a/tests/ui/sanitizer/cfi-supertraits.rs b/tests/ui/sanitizer/cfi-supertraits.rs new file mode 100644 index 00000000000..ed3d722ebb7 --- /dev/null +++ b/tests/ui/sanitizer/cfi-supertraits.rs @@ -0,0 +1,73 @@ +#![feature(trait_upcasting)] +// Check that super-traits are callable. + +//@ revisions: cfi kcfi +// FIXME(#122848) Remove only-linux once OSX CFI binaries work +//@ only-linux +//@ [cfi] needs-sanitizer-cfi +//@ [kcfi] needs-sanitizer-kcfi +//@ compile-flags: -C target-feature=-crt-static +//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 +//@ [cfi] compile-flags: -Z sanitizer=cfi +//@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off +//@ run-pass + +trait Parent1 { + type P1; + fn p1(&self) -> Self::P1; +} + +trait Parent2 { + type P2; + fn p2(&self) -> Self::P2; +} + +trait Child : Parent1 + Parent2 { + type C; + fn c(&self) -> Self::C; +} + +struct Foo; + +impl Parent1 for Foo { + type P1 = u16; + fn p1(&self) -> Self::P1 { + println!("p1"); + 1 + } +} + +impl Parent2 for Foo { + type P2 = u32; + fn p2(&self) -> Self::P2 { + println!("p2"); + 2 + } +} + +impl Child for Foo { + type C = u8; + fn c(&self) -> Self::C { + println!("c"); + 0 + } +} + +fn main() { + // Child can access its own methods and super methods. + let x = &Foo as &dyn Child; + x.c(); + x.p1(); + x.p2(); + // Parents can be created and access their methods. + let y = &Foo as &dyn Parent1; + y.p1(); + let z = &Foo as &dyn Parent2; + z.p2(); + // Trait upcasting works + let x1 = x as &dyn Parent1; + x1.p1(); + let x2 = x as &dyn Parent2; + x2.p2(); +} From d54e9833e3513958a9e03c5f50b9496c618ebde5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 29 Mar 2024 19:05:54 +0000 Subject: [PATCH 10/24] Do not attempt to write `ty::Err` on binding that isn't from current HIR Owner Fix #123009. --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 13 ++----- ...dings-in-pattern-with-ty-err-doesnt-ice.rs | 7 ++++ ...s-in-pattern-with-ty-err-doesnt-ice.stderr | 36 +++++++++++++++++++ 3 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs create mode 100644 tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ebc5e11a561..8ea1a88be5d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1916,18 +1916,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx hir::Pat<'tcx>, ty: Ty<'tcx>, ) { - struct V<'tcx> { - tcx: TyCtxt<'tcx>, + struct V { pat_hir_ids: Vec, } - impl<'tcx> Visitor<'tcx> for V<'tcx> { - type NestedFilter = rustc_middle::hir::nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - + impl<'tcx> Visitor<'tcx> for V { fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { self.pat_hir_ids.push(p.hir_id); hir::intravisit::walk_pat(self, p); @@ -1938,7 +1931,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let err = Ty::new_error(self.tcx, guar); self.write_ty(hir_id, err); self.write_ty(pat.hir_id, err); - let mut visitor = V { tcx: self.tcx, pat_hir_ids: vec![] }; + let mut visitor = V { pat_hir_ids: vec![] }; hir::intravisit::walk_pat(&mut visitor, pat); // Mark all the subpatterns as `{type error}` as well. This allows errors for specific // subpatterns to be silenced. diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs new file mode 100644 index 00000000000..d08ca644a1c --- /dev/null +++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs @@ -0,0 +1,7 @@ +fn main() { + let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; +//~^ ERROR expected a pattern, found an expression +//~| ERROR cannot find type `T` in this scope +//~| ERROR type and const arguments are not allowed on builtin type `str` +//~| ERROR expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes` +} diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr new file mode 100644 index 00000000000..19d4ac713ce --- /dev/null +++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr @@ -0,0 +1,36 @@ +error: expected a pattern, found an expression + --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:31 + | +LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; + | ^^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + +error[E0412]: cannot find type `T` in this scope + --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:55 + | +LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; + | ^ not found in this scope + +error[E0109]: type and const arguments are not allowed on builtin type `str` + --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:15 + | +LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; + | --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ type and const arguments not allowed + | | + | not allowed on builtin type `str` + | +help: primitive type `str` doesn't have generic parameters + | +LL - let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; +LL + let str::as_bytes; + | + +error[E0533]: expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes` + --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:9 + | +LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constant + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0109, E0412, E0533. +For more information about an error, try `rustc --explain E0109`. From 16d11c539f9783a5e066d90a7d7b17f70ee2b086 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 19 Feb 2024 21:50:33 +0100 Subject: [PATCH 11/24] Add support for NonNull in ambiguous_wide_ptr_comparisions --- .../src/tagged_ptr/copy.rs | 1 + compiler/rustc_lint/src/lints.rs | 18 ++- compiler/rustc_lint/src/types.rs | 38 +++-- tests/ui/lint/wide_pointer_comparisons.rs | 12 ++ tests/ui/lint/wide_pointer_comparisons.stderr | 135 +++++++++++------- 5 files changed, 139 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs index ff4208def31..8b9e834b60b 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs @@ -243,6 +243,7 @@ where T: Tag, { #[inline] + #[allow(ambiguous_wide_pointer_comparisons)] fn eq(&self, other: &Self) -> bool { self.packed == other.packed } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index cf3890dc61c..a034bebc85e 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1632,11 +1632,13 @@ pub struct AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a> { pub ne: &'a str, pub deref_left: &'a str, pub deref_right: &'a str, + pub l_modifiers: &'a str, + pub r_modifiers: &'a str, #[suggestion_part(code = "{ne}std::ptr::eq({deref_left}")] pub left: Span, - #[suggestion_part(code = ", {deref_right}")] + #[suggestion_part(code = "{l_modifiers}, {deref_right}")] pub middle: Span, - #[suggestion_part(code = ")")] + #[suggestion_part(code = "{r_modifiers})")] pub right: Span, } @@ -1652,11 +1654,13 @@ pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> { ne: &'a str, deref_left: &'a str, deref_right: &'a str, + l_modifiers: &'a str, + r_modifiers: &'a str, #[suggestion_part(code = "{ne}std::ptr::addr_eq({deref_left}")] left: Span, - #[suggestion_part(code = ", {deref_right}")] + #[suggestion_part(code = "{l_modifiers}, {deref_right}")] middle: Span, - #[suggestion_part(code = ")")] + #[suggestion_part(code = "{r_modifiers})")] right: Span, }, #[multipart_suggestion( @@ -1670,13 +1674,15 @@ pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> { deref_right: &'a str, paren_left: &'a str, paren_right: &'a str, + l_modifiers: &'a str, + r_modifiers: &'a str, #[suggestion_part(code = "({deref_left}")] left_before: Option, - #[suggestion_part(code = "{paren_left}.cast::<()>()")] + #[suggestion_part(code = "{l_modifiers}{paren_left}.cast::<()>()")] left_after: Span, #[suggestion_part(code = "({deref_right}")] right_before: Option, - #[suggestion_part(code = "{paren_right}.cast::<()>()")] + #[suggestion_part(code = "{r_modifiers}{paren_right}.cast::<()>()")] right_after: Span, }, } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 68cc024d9c7..534eb60eeb0 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -670,7 +670,11 @@ fn lint_wide_pointer<'tcx>( l: &'tcx hir::Expr<'tcx>, r: &'tcx hir::Expr<'tcx>, ) { - let ptr_unsized = |mut ty: Ty<'tcx>| -> Option<(usize, bool)> { + let ptr_unsized = |mut ty: Ty<'tcx>| -> Option<( + /* number of refs */ usize, + /* modifiers */ String, + /* is dyn */ bool, + )> { let mut refs = 0; // here we remove any "implicit" references and count the number // of them to correctly suggest the right number of deref @@ -678,11 +682,20 @@ fn lint_wide_pointer<'tcx>( ty = *inner_ty; refs += 1; } - match ty.kind() { - ty::RawPtr(ty, _) => (!ty.is_sized(cx.tcx, cx.param_env)) - .then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))), - _ => None, - } + + // get the inner type of a pointer (or akin) + let mut modifiers = String::new(); + ty = match ty.kind() { + ty::RawPtr(ty, _) => *ty, + ty::Adt(def, args) if cx.tcx.is_diagnostic_item(sym::NonNull, def.did()) => { + modifiers.push_str(".as_ptr()"); + args.type_at(0) + } + _ => return None, + }; + + (!ty.is_sized(cx.tcx, cx.param_env)) + .then(|| (refs, modifiers, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))) }; // the left and right operands can have references, remove any explicit references @@ -696,10 +709,10 @@ fn lint_wide_pointer<'tcx>( return; }; - let Some((l_ty_refs, l_inner_ty_is_dyn)) = ptr_unsized(l_ty) else { + let Some((l_ty_refs, l_modifiers, l_inner_ty_is_dyn)) = ptr_unsized(l_ty) else { return; }; - let Some((r_ty_refs, r_inner_ty_is_dyn)) = ptr_unsized(r_ty) else { + let Some((r_ty_refs, r_modifiers, r_inner_ty_is_dyn)) = ptr_unsized(r_ty) else { return; }; @@ -724,6 +737,9 @@ fn lint_wide_pointer<'tcx>( let deref_left = &*"*".repeat(l_ty_refs); let deref_right = &*"*".repeat(r_ty_refs); + let l_modifiers = &*l_modifiers; + let r_modifiers = &*r_modifiers; + cx.emit_span_lint( AMBIGUOUS_WIDE_POINTER_COMPARISONS, e.span, @@ -733,6 +749,8 @@ fn lint_wide_pointer<'tcx>( ne, deref_left, deref_right, + l_modifiers, + r_modifiers, left, middle, right, @@ -743,6 +761,8 @@ fn lint_wide_pointer<'tcx>( ne, deref_left, deref_right, + l_modifiers, + r_modifiers, left, middle, right, @@ -751,6 +771,8 @@ fn lint_wide_pointer<'tcx>( AmbiguousWidePointerComparisonsAddrSuggestion::Cast { deref_left, deref_right, + l_modifiers, + r_modifiers, paren_left: if l_ty_refs != 0 { ")" } else { "" }, paren_right: if r_ty_refs != 0 { ")" } else { "" }, left_before: (l_ty_refs != 0).then_some(l_span.shrink_to_lo()), diff --git a/tests/ui/lint/wide_pointer_comparisons.rs b/tests/ui/lint/wide_pointer_comparisons.rs index bc4b3cecabc..05097cbf1e3 100644 --- a/tests/ui/lint/wide_pointer_comparisons.rs +++ b/tests/ui/lint/wide_pointer_comparisons.rs @@ -3,6 +3,7 @@ use std::rc::Rc; use std::sync::Arc; use std::cmp::PartialEq; +use std::ptr::NonNull; struct A; struct B; @@ -50,6 +51,17 @@ fn main() { let _ = a.gt(&b); //~^ WARN ambiguous wide pointer comparison + { + let a = NonNull::::new(a as *mut _).unwrap(); + let b = NonNull::::new(b as *mut _).unwrap(); + let _ = a == b; + //~^ WARN ambiguous wide pointer comparison + let _ = a >= b; + //~^ WARN ambiguous wide pointer comparison + let _ = &a == &b; + //~^ WARN ambiguous wide pointer comparison + } + { // &*const ?Sized let a = &a; diff --git a/tests/ui/lint/wide_pointer_comparisons.stderr b/tests/ui/lint/wide_pointer_comparisons.stderr index 8140f9fa5aa..81a221c0ee6 100644 --- a/tests/ui/lint/wide_pointer_comparisons.stderr +++ b/tests/ui/lint/wide_pointer_comparisons.stderr @@ -1,5 +1,5 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:19:13 + --> $DIR/wide_pointer_comparisons.rs:20:13 | LL | let _ = a == b; | ^^^^^^ @@ -11,7 +11,7 @@ LL | let _ = std::ptr::addr_eq(a, b); | ++++++++++++++++++ ~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:21:13 + --> $DIR/wide_pointer_comparisons.rs:22:13 | LL | let _ = a != b; | ^^^^^^ @@ -22,7 +22,7 @@ LL | let _ = !std::ptr::addr_eq(a, b); | +++++++++++++++++++ ~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:23:13 + --> $DIR/wide_pointer_comparisons.rs:24:13 | LL | let _ = a < b; | ^^^^^ @@ -33,7 +33,7 @@ LL | let _ = a.cast::<()>() < b.cast::<()>(); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:25:13 + --> $DIR/wide_pointer_comparisons.rs:26:13 | LL | let _ = a <= b; | ^^^^^^ @@ -44,7 +44,7 @@ LL | let _ = a.cast::<()>() <= b.cast::<()>(); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:27:13 + --> $DIR/wide_pointer_comparisons.rs:28:13 | LL | let _ = a > b; | ^^^^^ @@ -55,7 +55,7 @@ LL | let _ = a.cast::<()>() > b.cast::<()>(); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:29:13 + --> $DIR/wide_pointer_comparisons.rs:30:13 | LL | let _ = a >= b; | ^^^^^^ @@ -66,7 +66,7 @@ LL | let _ = a.cast::<()>() >= b.cast::<()>(); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:32:13 + --> $DIR/wide_pointer_comparisons.rs:33:13 | LL | let _ = PartialEq::eq(&a, &b); | ^^^^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | let _ = std::ptr::addr_eq(a, b); | ~~~~~~~~~~~~~~~~~~ ~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:34:13 + --> $DIR/wide_pointer_comparisons.rs:35:13 | LL | let _ = PartialEq::ne(&a, &b); | ^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = !std::ptr::addr_eq(a, b); | ~~~~~~~~~~~~~~~~~~~ ~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:36:13 + --> $DIR/wide_pointer_comparisons.rs:37:13 | LL | let _ = a.eq(&b); | ^^^^^^^^ @@ -99,7 +99,7 @@ LL | let _ = std::ptr::addr_eq(a, b); | ++++++++++++++++++ ~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:38:13 + --> $DIR/wide_pointer_comparisons.rs:39:13 | LL | let _ = a.ne(&b); | ^^^^^^^^ @@ -110,7 +110,7 @@ LL | let _ = !std::ptr::addr_eq(a, b); | +++++++++++++++++++ ~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:40:13 + --> $DIR/wide_pointer_comparisons.rs:41:13 | LL | let _ = a.cmp(&b); | ^^^^^^^^^ @@ -121,7 +121,7 @@ LL | let _ = a.cast::<()>().cmp(&b.cast::<()>()); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:42:13 + --> $DIR/wide_pointer_comparisons.rs:43:13 | LL | let _ = a.partial_cmp(&b); | ^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | let _ = a.cast::<()>().partial_cmp(&b.cast::<()>()); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:44:13 + --> $DIR/wide_pointer_comparisons.rs:45:13 | LL | let _ = a.le(&b); | ^^^^^^^^ @@ -143,7 +143,7 @@ LL | let _ = a.cast::<()>().le(&b.cast::<()>()); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:46:13 + --> $DIR/wide_pointer_comparisons.rs:47:13 | LL | let _ = a.lt(&b); | ^^^^^^^^ @@ -154,7 +154,7 @@ LL | let _ = a.cast::<()>().lt(&b.cast::<()>()); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:48:13 + --> $DIR/wide_pointer_comparisons.rs:49:13 | LL | let _ = a.ge(&b); | ^^^^^^^^ @@ -165,7 +165,7 @@ LL | let _ = a.cast::<()>().ge(&b.cast::<()>()); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:50:13 + --> $DIR/wide_pointer_comparisons.rs:51:13 | LL | let _ = a.gt(&b); | ^^^^^^^^ @@ -176,7 +176,40 @@ LL | let _ = a.cast::<()>().gt(&b.cast::<()>()); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:58:17 + --> $DIR/wide_pointer_comparisons.rs:57:17 + | +LL | let _ = a == b; + | ^^^^^^ + | +help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses + | +LL | let _ = std::ptr::addr_eq(a.as_ptr(), b.as_ptr()); + | ++++++++++++++++++ ~~~~~~~~~~ ++++++++++ + +warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected + --> $DIR/wide_pointer_comparisons.rs:59:17 + | +LL | let _ = a >= b; + | ^^^^^^ + | +help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses + | +LL | let _ = a.as_ptr().cast::<()>() >= b.as_ptr().cast::<()>(); + | ++++++++++++++++++++++ ++++++++++++++++++++++ + +warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected + --> $DIR/wide_pointer_comparisons.rs:61:17 + | +LL | let _ = &a == &b; + | ^^^^^^^^ + | +help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses + | +LL | let _ = std::ptr::addr_eq(a.as_ptr(), b.as_ptr()); + | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~ ++++++++++ + +warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected + --> $DIR/wide_pointer_comparisons.rs:70:17 | LL | let _ = a == b; | ^^^^^^ @@ -187,7 +220,7 @@ LL | let _ = std::ptr::addr_eq(*a, *b); | +++++++++++++++++++ ~~~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:60:17 + --> $DIR/wide_pointer_comparisons.rs:72:17 | LL | let _ = a != b; | ^^^^^^ @@ -198,7 +231,7 @@ LL | let _ = !std::ptr::addr_eq(*a, *b); | ++++++++++++++++++++ ~~~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:62:17 + --> $DIR/wide_pointer_comparisons.rs:74:17 | LL | let _ = a < b; | ^^^^^ @@ -209,7 +242,7 @@ LL | let _ = (*a).cast::<()>() < (*b).cast::<()>(); | ++ ++++++++++++++ ++ ++++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:64:17 + --> $DIR/wide_pointer_comparisons.rs:76:17 | LL | let _ = a <= b; | ^^^^^^ @@ -220,7 +253,7 @@ LL | let _ = (*a).cast::<()>() <= (*b).cast::<()>(); | ++ ++++++++++++++ ++ ++++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:66:17 + --> $DIR/wide_pointer_comparisons.rs:78:17 | LL | let _ = a > b; | ^^^^^ @@ -231,7 +264,7 @@ LL | let _ = (*a).cast::<()>() > (*b).cast::<()>(); | ++ ++++++++++++++ ++ ++++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:68:17 + --> $DIR/wide_pointer_comparisons.rs:80:17 | LL | let _ = a >= b; | ^^^^^^ @@ -242,7 +275,7 @@ LL | let _ = (*a).cast::<()>() >= (*b).cast::<()>(); | ++ ++++++++++++++ ++ ++++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:71:17 + --> $DIR/wide_pointer_comparisons.rs:83:17 | LL | let _ = PartialEq::eq(a, b); | ^^^^^^^^^^^^^^^^^^^ @@ -253,7 +286,7 @@ LL | let _ = std::ptr::addr_eq(*a, *b); | ~~~~~~~~~~~~~~~~~~~ ~~~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:73:17 + --> $DIR/wide_pointer_comparisons.rs:85:17 | LL | let _ = PartialEq::ne(a, b); | ^^^^^^^^^^^^^^^^^^^ @@ -264,7 +297,7 @@ LL | let _ = !std::ptr::addr_eq(*a, *b); | ~~~~~~~~~~~~~~~~~~~~ ~~~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:75:17 + --> $DIR/wide_pointer_comparisons.rs:87:17 | LL | let _ = PartialEq::eq(&a, &b); | ^^^^^^^^^^^^^^^^^^^^^ @@ -275,7 +308,7 @@ LL | let _ = std::ptr::addr_eq(*a, *b); | ~~~~~~~~~~~~~~~~~~~ ~~~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:77:17 + --> $DIR/wide_pointer_comparisons.rs:89:17 | LL | let _ = PartialEq::ne(&a, &b); | ^^^^^^^^^^^^^^^^^^^^^ @@ -286,7 +319,7 @@ LL | let _ = !std::ptr::addr_eq(*a, *b); | ~~~~~~~~~~~~~~~~~~~~ ~~~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:79:17 + --> $DIR/wide_pointer_comparisons.rs:91:17 | LL | let _ = a.eq(b); | ^^^^^^^ @@ -297,7 +330,7 @@ LL | let _ = std::ptr::addr_eq(*a, *b); | +++++++++++++++++++ ~~~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:81:17 + --> $DIR/wide_pointer_comparisons.rs:93:17 | LL | let _ = a.ne(b); | ^^^^^^^ @@ -308,7 +341,7 @@ LL | let _ = !std::ptr::addr_eq(*a, *b); | ++++++++++++++++++++ ~~~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:83:17 + --> $DIR/wide_pointer_comparisons.rs:95:17 | LL | let _ = a.cmp(&b); | ^^^^^^^^^ @@ -319,7 +352,7 @@ LL | let _ = (*a).cast::<()>().cmp(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:85:17 + --> $DIR/wide_pointer_comparisons.rs:97:17 | LL | let _ = a.partial_cmp(&b); | ^^^^^^^^^^^^^^^^^ @@ -330,7 +363,7 @@ LL | let _ = (*a).cast::<()>().partial_cmp(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:87:17 + --> $DIR/wide_pointer_comparisons.rs:99:17 | LL | let _ = a.le(&b); | ^^^^^^^^ @@ -341,7 +374,7 @@ LL | let _ = (*a).cast::<()>().le(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:89:17 + --> $DIR/wide_pointer_comparisons.rs:101:17 | LL | let _ = a.lt(&b); | ^^^^^^^^ @@ -352,7 +385,7 @@ LL | let _ = (*a).cast::<()>().lt(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:91:17 + --> $DIR/wide_pointer_comparisons.rs:103:17 | LL | let _ = a.ge(&b); | ^^^^^^^^ @@ -363,7 +396,7 @@ LL | let _ = (*a).cast::<()>().ge(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:93:17 + --> $DIR/wide_pointer_comparisons.rs:105:17 | LL | let _ = a.gt(&b); | ^^^^^^^^ @@ -374,7 +407,7 @@ LL | let _ = (*a).cast::<()>().gt(&(*b).cast::<()>()); | ++ ++++++++++++++ ++ ++++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:98:13 + --> $DIR/wide_pointer_comparisons.rs:110:13 | LL | let _ = s == s; | ^^^^^^ @@ -389,7 +422,7 @@ LL | let _ = std::ptr::eq(s, s); | +++++++++++++ ~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:102:13 + --> $DIR/wide_pointer_comparisons.rs:114:13 | LL | let _ = s == s; | ^^^^^^ @@ -404,7 +437,7 @@ LL | let _ = std::ptr::eq(s, s); | +++++++++++++ ~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:106:17 + --> $DIR/wide_pointer_comparisons.rs:118:17 | LL | let _ = a == b; | ^^^^^^ @@ -419,7 +452,7 @@ LL | let _ = std::ptr::eq(a, b); | +++++++++++++ ~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:108:17 + --> $DIR/wide_pointer_comparisons.rs:120:17 | LL | let _ = a != b; | ^^^^^^ @@ -434,7 +467,7 @@ LL | let _ = !std::ptr::eq(a, b); | ++++++++++++++ ~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:110:17 + --> $DIR/wide_pointer_comparisons.rs:122:17 | LL | let _ = a < b; | ^^^^^ @@ -445,7 +478,7 @@ LL | let _ = a.cast::<()>() < b.cast::<()>(); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:112:17 + --> $DIR/wide_pointer_comparisons.rs:124:17 | LL | let _ = a <= b; | ^^^^^^ @@ -456,7 +489,7 @@ LL | let _ = a.cast::<()>() <= b.cast::<()>(); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:114:17 + --> $DIR/wide_pointer_comparisons.rs:126:17 | LL | let _ = a > b; | ^^^^^ @@ -467,7 +500,7 @@ LL | let _ = a.cast::<()>() > b.cast::<()>(); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:116:17 + --> $DIR/wide_pointer_comparisons.rs:128:17 | LL | let _ = a >= b; | ^^^^^^ @@ -478,7 +511,7 @@ LL | let _ = a.cast::<()>() >= b.cast::<()>(); | +++++++++++++ +++++++++++++ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:119:17 + --> $DIR/wide_pointer_comparisons.rs:131:17 | LL | let _ = PartialEq::eq(&a, &b); | ^^^^^^^^^^^^^^^^^^^^^ @@ -493,7 +526,7 @@ LL | let _ = std::ptr::eq(a, b); | ~~~~~~~~~~~~~ ~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:121:17 + --> $DIR/wide_pointer_comparisons.rs:133:17 | LL | let _ = PartialEq::ne(&a, &b); | ^^^^^^^^^^^^^^^^^^^^^ @@ -508,7 +541,7 @@ LL | let _ = !std::ptr::eq(a, b); | ~~~~~~~~~~~~~~ ~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:123:17 + --> $DIR/wide_pointer_comparisons.rs:135:17 | LL | let _ = a.eq(&b); | ^^^^^^^^ @@ -523,7 +556,7 @@ LL | let _ = std::ptr::eq(a, b); | +++++++++++++ ~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:125:17 + --> $DIR/wide_pointer_comparisons.rs:137:17 | LL | let _ = a.ne(&b); | ^^^^^^^^ @@ -538,7 +571,7 @@ LL | let _ = !std::ptr::eq(a, b); | ++++++++++++++ ~ ~ warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:130:9 + --> $DIR/wide_pointer_comparisons.rs:142:9 | LL | &*a == &*b | ^^^^^^^^^^ @@ -553,7 +586,7 @@ LL | std::ptr::eq(*a, *b) | ~~~~~~~~~~~~~ ~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:141:14 + --> $DIR/wide_pointer_comparisons.rs:153:14 | LL | cmp!(a, b); | ^^^^ @@ -564,7 +597,7 @@ LL | cmp!(std::ptr::addr_eq(a, b)); | ++++++++++++++++++ ~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:147:39 + --> $DIR/wide_pointer_comparisons.rs:159:39 | LL | ($a:ident, $b:ident) => { $a == $b } | ^^^^^^^^ @@ -579,7 +612,7 @@ LL | ($a:ident, $b:ident) => { std::ptr::addr_eq($a, $b) } | ++++++++++++++++++ ~ + warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected - --> $DIR/wide_pointer_comparisons.rs:157:37 + --> $DIR/wide_pointer_comparisons.rs:169:37 | LL | ($a:expr, $b:expr) => { $a == $b } | ^^ @@ -591,5 +624,5 @@ LL | cmp!(&a, &b); = help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses = note: this warning originates in the macro `cmp` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: 50 warnings emitted +warning: 53 warnings emitted From ea92faec491084849f9c2fb258a0e3161bb29ae4 Mon Sep 17 00:00:00 2001 From: Aria Beingessner Date: Sun, 3 Mar 2024 14:44:15 -0500 Subject: [PATCH 12/24] stabilize ptr.is_aligned, move ptr.is_aligned_to to a new feature gate This is an alternative to #121920 --- .../0001-core-Disable-portable-simd-test.patch | 4 ++-- library/alloc/src/lib.rs | 1 - library/alloc/tests/lib.rs | 2 +- library/core/src/ptr/const_ptr.rs | 17 ++++++----------- library/core/src/ptr/mut_ptr.rs | 17 ++++++----------- library/core/src/ptr/non_null.rs | 16 ++++++---------- library/core/src/sync/atomic.rs | 12 +++--------- library/core/tests/lib.rs | 2 +- library/std/src/lib.rs | 2 +- .../miri/tests/pass-dep/shims/posix_memalign.rs | 2 +- tests/assembly/is_aligned.rs | 2 +- tests/ui/mir/alignment/packed.rs | 2 +- tests/ui/structs-enums/type-sizes.rs | 2 +- 13 files changed, 30 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch index 914ae986b50..36d0789d2a2 100644 --- a/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch +++ b/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch @@ -14,7 +14,7 @@ index d0a119c..76fdece 100644 @@ -89,7 +89,6 @@ #![feature(never_type)] #![feature(unwrap_infallible)] - #![feature(pointer_is_aligned)] + #![feature(pointer_is_aligned_to)] -#![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(lazy_cell)] @@ -27,6 +27,6 @@ index d0a119c..76fdece 100644 mod slice; mod str; mod str_lossy; --- +-- 2.42.1 diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b6a9d6005d4..cafd59cb0d9 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -198,7 +198,6 @@ #![feature(multiple_supertrait_upcastable)] #![feature(negative_impls)] #![feature(never_type)] -#![feature(pointer_is_aligned)] #![feature(rustc_allow_const_fn_unstable)] #![feature(rustc_attrs)] #![feature(slice_internals)] diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 04709af5c0a..a34bce66496 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -37,7 +37,7 @@ #![feature(const_trait_impl)] #![feature(const_str_from_utf8)] #![feature(panic_update_hook)] -#![feature(pointer_is_aligned)] +#![feature(pointer_is_aligned_to)] #![feature(slice_flatten)] #![feature(thin_box)] #![feature(strict_provenance)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 68ce80ee321..99bd631b581 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1401,8 +1401,6 @@ impl *const T { /// # Examples /// /// ``` - /// #![feature(pointer_is_aligned)] - /// /// // On some platforms, the alignment of i32 is less than 4. /// #[repr(align(4))] /// struct AlignedI32(i32); @@ -1425,7 +1423,6 @@ impl *const T { /// underlying allocation. /// /// ``` - /// #![feature(pointer_is_aligned)] /// #![feature(const_pointer_is_aligned)] /// /// // On some platforms, the alignment of primitives is less than their size. @@ -1451,7 +1448,6 @@ impl *const T { /// pointer is aligned, even if the compiletime pointer wasn't aligned. /// /// ``` - /// #![feature(pointer_is_aligned)] /// #![feature(const_pointer_is_aligned)] /// /// // On some platforms, the alignment of primitives is less than their size. @@ -1477,7 +1473,6 @@ impl *const T { /// runtime and compiletime. /// /// ``` - /// #![feature(pointer_is_aligned)] /// #![feature(const_pointer_is_aligned)] /// /// // On some platforms, the alignment of primitives is less than their size. @@ -1501,7 +1496,7 @@ impl *const T { /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] - #[unstable(feature = "pointer_is_aligned", issue = "96284")] + #[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] pub const fn is_aligned(self) -> bool where @@ -1522,7 +1517,7 @@ impl *const T { /// # Examples /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// /// // On some platforms, the alignment of i32 is less than 4. /// #[repr(align(4))] @@ -1551,7 +1546,7 @@ impl *const T { /// cannot be stricter aligned than the reference's underlying allocation. /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// #![feature(const_pointer_is_aligned)] /// /// // On some platforms, the alignment of i32 is less than 4. @@ -1576,7 +1571,7 @@ impl *const T { /// pointer is aligned, even if the compiletime pointer wasn't aligned. /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// #![feature(const_pointer_is_aligned)] /// /// // On some platforms, the alignment of i32 is less than 4. @@ -1600,7 +1595,7 @@ impl *const T { /// runtime and compiletime. /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// #![feature(const_pointer_is_aligned)] /// /// const _: () = { @@ -1616,7 +1611,7 @@ impl *const T { /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] - #[unstable(feature = "pointer_is_aligned", issue = "96284")] + #[unstable(feature = "pointer_is_aligned_to", issue = "96284")] #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] pub const fn is_aligned_to(self, align: usize) -> bool { if !align.is_power_of_two() { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 3dde83541d4..e9d39b2c276 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1660,8 +1660,6 @@ impl *mut T { /// # Examples /// /// ``` - /// #![feature(pointer_is_aligned)] - /// /// // On some platforms, the alignment of i32 is less than 4. /// #[repr(align(4))] /// struct AlignedI32(i32); @@ -1684,7 +1682,6 @@ impl *mut T { /// underlying allocation. /// /// ``` - /// #![feature(pointer_is_aligned)] /// #![feature(const_pointer_is_aligned)] /// #![feature(const_mut_refs)] /// @@ -1711,7 +1708,6 @@ impl *mut T { /// pointer is aligned, even if the compiletime pointer wasn't aligned. /// /// ``` - /// #![feature(pointer_is_aligned)] /// #![feature(const_pointer_is_aligned)] /// /// // On some platforms, the alignment of primitives is less than their size. @@ -1738,7 +1734,6 @@ impl *mut T { /// runtime and compiletime. /// /// ``` - /// #![feature(pointer_is_aligned)] /// #![feature(const_pointer_is_aligned)] /// /// // On some platforms, the alignment of primitives is less than their size. @@ -1762,7 +1757,7 @@ impl *mut T { /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] - #[unstable(feature = "pointer_is_aligned", issue = "96284")] + #[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] pub const fn is_aligned(self) -> bool where @@ -1783,7 +1778,7 @@ impl *mut T { /// # Examples /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// /// // On some platforms, the alignment of i32 is less than 4. /// #[repr(align(4))] @@ -1812,7 +1807,7 @@ impl *mut T { /// cannot be stricter aligned than the reference's underlying allocation. /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// #![feature(const_pointer_is_aligned)] /// #![feature(const_mut_refs)] /// @@ -1838,7 +1833,7 @@ impl *mut T { /// pointer is aligned, even if the compiletime pointer wasn't aligned. /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// #![feature(const_pointer_is_aligned)] /// /// // On some platforms, the alignment of i32 is less than 4. @@ -1863,7 +1858,7 @@ impl *mut T { /// runtime and compiletime. /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// #![feature(const_pointer_is_aligned)] /// /// const _: () = { @@ -1879,7 +1874,7 @@ impl *mut T { /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 #[must_use] #[inline] - #[unstable(feature = "pointer_is_aligned", issue = "96284")] + #[unstable(feature = "pointer_is_aligned_to", issue = "96284")] #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] pub const fn is_aligned_to(self, align: usize) -> bool { if !align.is_power_of_two() { diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index c0a36bb405e..f0e4b958bc6 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1288,7 +1288,6 @@ impl NonNull { /// # Examples /// /// ``` - /// #![feature(pointer_is_aligned)] /// use std::ptr::NonNull; /// /// // On some platforms, the alignment of i32 is less than 4. @@ -1313,7 +1312,6 @@ impl NonNull { /// underlying allocation. /// /// ``` - /// #![feature(pointer_is_aligned)] /// #![feature(const_pointer_is_aligned)] /// #![feature(non_null_convenience)] /// #![feature(const_option)] @@ -1343,7 +1341,6 @@ impl NonNull { /// pointer is aligned, even if the compiletime pointer wasn't aligned. /// /// ``` - /// #![feature(pointer_is_aligned)] /// #![feature(const_pointer_is_aligned)] /// /// // On some platforms, the alignment of primitives is less than their size. @@ -1369,7 +1366,6 @@ impl NonNull { /// runtime and compiletime. /// /// ``` - /// #![feature(pointer_is_aligned)] /// #![feature(const_pointer_is_aligned)] /// #![feature(const_option)] /// #![feature(const_nonnull_new)] @@ -1394,7 +1390,7 @@ impl NonNull { /// ``` /// /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 - #[unstable(feature = "pointer_is_aligned", issue = "96284")] + #[stable(feature = "pointer_is_aligned", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] #[must_use] #[inline] @@ -1417,7 +1413,7 @@ impl NonNull { /// # Examples /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// /// // On some platforms, the alignment of i32 is less than 4. /// #[repr(align(4))] @@ -1446,7 +1442,7 @@ impl NonNull { /// cannot be stricter aligned than the reference's underlying allocation. /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// #![feature(const_pointer_is_aligned)] /// /// // On some platforms, the alignment of i32 is less than 4. @@ -1471,7 +1467,7 @@ impl NonNull { /// pointer is aligned, even if the compiletime pointer wasn't aligned. /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// #![feature(const_pointer_is_aligned)] /// /// // On some platforms, the alignment of i32 is less than 4. @@ -1495,7 +1491,7 @@ impl NonNull { /// runtime and compiletime. /// /// ``` - /// #![feature(pointer_is_aligned)] + /// #![feature(pointer_is_aligned_to)] /// #![feature(const_pointer_is_aligned)] /// /// const _: () = { @@ -1509,7 +1505,7 @@ impl NonNull { /// ``` /// /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 - #[unstable(feature = "pointer_is_aligned", issue = "96284")] + #[unstable(feature = "pointer_is_aligned_to", issue = "96284")] #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] #[must_use] #[inline] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 77002ef87aa..0a749fcb8f9 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -418,14 +418,12 @@ impl AtomicBool { /// # Examples /// /// ``` - /// #![feature(pointer_is_aligned)] /// use std::sync::atomic::{self, AtomicBool}; - /// use std::mem::align_of; /// /// // Get a pointer to an allocated value /// let ptr: *mut bool = Box::into_raw(Box::new(false)); /// - /// assert!(ptr.is_aligned_to(align_of::())); + /// assert!(ptr.cast::().is_aligned()); /// /// { /// // Create an atomic view of the allocated value @@ -1216,14 +1214,12 @@ impl AtomicPtr { /// # Examples /// /// ``` - /// #![feature(pointer_is_aligned)] /// use std::sync::atomic::{self, AtomicPtr}; - /// use std::mem::align_of; /// /// // Get a pointer to an allocated value /// let ptr: *mut *mut u8 = Box::into_raw(Box::new(std::ptr::null_mut())); /// - /// assert!(ptr.is_aligned_to(align_of::>())); + /// assert!(ptr.cast::>().is_aligned()); /// /// { /// // Create an atomic view of the allocated value @@ -2199,14 +2195,12 @@ macro_rules! atomic_int { /// # Examples /// /// ``` - /// #![feature(pointer_is_aligned)] #[doc = concat!($extra_feature, "use std::sync::atomic::{self, ", stringify!($atomic_type), "};")] - /// use std::mem::align_of; /// /// // Get a pointer to an allocated value #[doc = concat!("let ptr: *mut ", stringify!($int_type), " = Box::into_raw(Box::new(0));")] /// - #[doc = concat!("assert!(ptr.is_aligned_to(align_of::<", stringify!($atomic_type), ">()));")] + #[doc = concat!("assert!(ptr.cast::<", stringify!($atomic_type), ">().is_aligned());")] /// /// { /// // Create an atomic view of the allocated value diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 421062f5873..f6d975c2c1e 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -95,7 +95,7 @@ #![feature(const_waker)] #![feature(never_type)] #![feature(unwrap_infallible)] -#![feature(pointer_is_aligned)] +#![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(lazy_cell)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 3781ae15c3a..31a8711e0eb 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -341,7 +341,7 @@ #![feature(panic_can_unwind)] #![feature(panic_info_message)] #![feature(panic_internals)] -#![feature(pointer_is_aligned)] +#![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(prelude_2024)] #![feature(ptr_as_uninit)] diff --git a/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs b/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs index 5cf62995fbe..db66b213416 100644 --- a/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs +++ b/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs @@ -1,6 +1,6 @@ //@ignore-target-windows: No libc on Windows -#![feature(pointer_is_aligned)] +#![feature(pointer_is_aligned_to)] #![feature(strict_provenance)] use core::ptr; diff --git a/tests/assembly/is_aligned.rs b/tests/assembly/is_aligned.rs index 9d637793f87..14423a52064 100644 --- a/tests/assembly/is_aligned.rs +++ b/tests/assembly/is_aligned.rs @@ -7,7 +7,7 @@ #![crate_type="rlib"] #![feature(core_intrinsics)] -#![feature(pointer_is_aligned)] +#![feature(pointer_is_aligned_to)] // CHECK-LABEL: is_aligned_to_unchecked // CHECK: decq diff --git a/tests/ui/mir/alignment/packed.rs b/tests/ui/mir/alignment/packed.rs index fe8ecc668b8..1a12425f11a 100644 --- a/tests/ui/mir/alignment/packed.rs +++ b/tests/ui/mir/alignment/packed.rs @@ -1,7 +1,7 @@ //@ run-pass //@ compile-flags: -C debug-assertions -#![feature(strict_provenance, pointer_is_aligned)] +#![feature(strict_provenance)] #[repr(packed)] struct Misaligner { diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs index 66f663ce077..50491d5ef3e 100644 --- a/tests/ui/structs-enums/type-sizes.rs +++ b/tests/ui/structs-enums/type-sizes.rs @@ -4,7 +4,7 @@ #![allow(dead_code)] #![feature(generic_nonzero)] #![feature(never_type)] -#![feature(pointer_is_aligned)] +#![feature(pointer_is_aligned_to)] #![feature(strict_provenance)] use std::mem::size_of; From 5e2c54977202a0a245dca4bfd5171ced47bed487 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 29 Mar 2024 20:40:45 -0400 Subject: [PATCH 13/24] Assert that ADTs have the right number of substs --- compiler/rustc_middle/src/ty/sty.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 57a675e4453..b5e619f1e2a 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1624,6 +1624,13 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { + debug_assert_eq!( + tcx.generics_of(def.did()).count(), + args.len(), + "wrong number of args for ADT: {:#?} vs {:#?}", + tcx.generics_of(def.did()).params, + args + ); Ty::new(tcx, Adt(def, args)) } From bc1f1ef2c82c5c84e0d90c5c5d261444fba9ffec Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 29 Mar 2024 21:21:41 -0400 Subject: [PATCH 14/24] Stop removing substs from Adt type in coherence --- compiler/rustc_hir_analysis/messages.ftl | 2 ++ .../src/coherence/orphan.rs | 28 +++++++++++-------- compiler/rustc_hir_analysis/src/errors.rs | 15 +++++++++- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 9bf4d63267a..d8a90d62dac 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -295,6 +295,8 @@ hir_analysis_not_supported_delegation = {$descr} is not supported yet .label = callee defined here +hir_analysis_only_current_traits_adt = `{$name}` is not defined in the current crate + hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index ca8a635ab5e..92e8c459509 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -4,7 +4,7 @@ use crate::errors; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; -use rustc_middle::ty::{self, AliasKind, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, AliasKind, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_trait_selection::traits::{self, IsFirstInputType}; @@ -283,8 +283,14 @@ fn emit_orphan_check_error<'tcx>( let self_ty = trait_ref.self_ty(); Err(match err { traits::OrphanCheckErr::NonLocalInputType(tys) => { - let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) = - (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()); + // FIXME: Someone needs to just turn these into `Subdiag`s and attach + // them to the `Diag` after creating the error. + let mut opaque = vec![]; + let mut foreign = vec![]; + let mut name = vec![]; + let mut pointer = vec![]; + let mut ty_diag = vec![]; + let mut adt = vec![]; let mut sugg = None; for &(mut ty, is_target_ty) in &tys { let span = if matches!(is_target_ty, IsFirstInputType::Yes) { @@ -296,15 +302,6 @@ fn emit_orphan_check_error<'tcx>( }; ty = tcx.erase_regions(ty); - ty = match ty.kind() { - // Remove the type arguments from the output, as they are not relevant. - // You can think of this as the reverse of `resolve_vars_if_possible`. - // That way if we had `Vec`, we will properly attribute the - // problem to `Vec` and avoid confusing the user if they were to see - // `MyType` in the error. - ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()), - _ => ty, - }; fn push_to_foreign_or_name<'tcx>( is_foreign: bool, @@ -366,6 +363,10 @@ fn emit_orphan_check_error<'tcx>( } pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty }); } + ty::Adt(adt_def, _) => adt.push(errors::OnlyCurrentTraitsAdt { + span, + name: tcx.def_path_str(adt_def.did()), + }), _ => ty_diag.push(errors::OnlyCurrentTraitsTy { span, ty }), } } @@ -379,6 +380,7 @@ fn emit_orphan_check_error<'tcx>( name, pointer, ty: ty_diag, + adt, sugg, }, _ if self_ty.is_primitive() => errors::OnlyCurrentTraits::Primitive { @@ -389,6 +391,7 @@ fn emit_orphan_check_error<'tcx>( name, pointer, ty: ty_diag, + adt, sugg, }, _ => errors::OnlyCurrentTraits::Arbitrary { @@ -399,6 +402,7 @@ fn emit_orphan_check_error<'tcx>( name, pointer, ty: ty_diag, + adt, sugg, }, }; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index fb919714afd..6595ee542e0 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1395,6 +1395,8 @@ pub enum OnlyCurrentTraits<'a> { #[subdiagnostic] ty: Vec>, #[subdiagnostic] + adt: Vec, + #[subdiagnostic] sugg: Option>, }, #[diag(hir_analysis_only_current_traits_primitive, code = E0117)] @@ -1415,6 +1417,8 @@ pub enum OnlyCurrentTraits<'a> { #[subdiagnostic] ty: Vec>, #[subdiagnostic] + adt: Vec, + #[subdiagnostic] sugg: Option>, }, #[diag(hir_analysis_only_current_traits_arbitrary, code = E0117)] @@ -1435,6 +1439,8 @@ pub enum OnlyCurrentTraits<'a> { #[subdiagnostic] ty: Vec>, #[subdiagnostic] + adt: Vec, + #[subdiagnostic] sugg: Option>, }, } @@ -1445,7 +1451,6 @@ pub struct OnlyCurrentTraitsOpaque { #[primary_span] pub span: Span, } - #[derive(Subdiagnostic)] #[label(hir_analysis_only_current_traits_foreign)] pub struct OnlyCurrentTraitsForeign { @@ -1477,6 +1482,14 @@ pub struct OnlyCurrentTraitsTy<'a> { pub ty: Ty<'a>, } +#[derive(Subdiagnostic)] +#[label(hir_analysis_only_current_traits_adt)] +pub struct OnlyCurrentTraitsAdt { + #[primary_span] + pub span: Span, + pub name: String, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( hir_analysis_only_current_traits_pointer_sugg, From f487d8339086eb3bf0c0aec5fac7d343c5d8fa46 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 29 Mar 2024 22:23:10 -0400 Subject: [PATCH 15/24] Stop doing so much to handle subdiagnostics --- .../src/coherence/orphan.rs | 162 ++++++++---------- compiler/rustc_hir_analysis/src/errors.rs | 44 +---- 2 files changed, 69 insertions(+), 137 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 92e8c459509..1770f7b4e91 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -283,15 +283,14 @@ fn emit_orphan_check_error<'tcx>( let self_ty = trait_ref.self_ty(); Err(match err { traits::OrphanCheckErr::NonLocalInputType(tys) => { - // FIXME: Someone needs to just turn these into `Subdiag`s and attach - // them to the `Diag` after creating the error. - let mut opaque = vec![]; - let mut foreign = vec![]; - let mut name = vec![]; - let mut pointer = vec![]; - let mut ty_diag = vec![]; - let mut adt = vec![]; - let mut sugg = None; + let mut diag = tcx.dcx().create_err(match self_ty.kind() { + ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span: sp, note: () }, + _ if self_ty.is_primitive() => { + errors::OnlyCurrentTraits::Primitive { span: sp, note: () } + } + _ => errors::OnlyCurrentTraits::Arbitrary { span: sp, note: () }, + }); + for &(mut ty, is_target_ty) in &tys { let span = if matches!(is_target_ty, IsFirstInputType::Yes) { // Point at `D` in `impl for C in D` @@ -303,110 +302,85 @@ fn emit_orphan_check_error<'tcx>( ty = tcx.erase_regions(ty); - fn push_to_foreign_or_name<'tcx>( - is_foreign: bool, - foreign: &mut Vec, - name: &mut Vec>, - span: Span, - sname: &'tcx str, - ) { - if is_foreign { - foreign.push(errors::OnlyCurrentTraitsForeign { span }) - } else { - name.push(errors::OnlyCurrentTraitsName { span, name: sname }); - } - } - let is_foreign = !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No); match *ty.kind() { ty::Slice(_) => { - push_to_foreign_or_name( - is_foreign, - &mut foreign, - &mut name, - span, - "slices", - ); + if is_foreign { + diag.subdiagnostic( + tcx.dcx(), + errors::OnlyCurrentTraitsForeign { span }, + ); + } else { + diag.subdiagnostic( + tcx.dcx(), + errors::OnlyCurrentTraitsName { span, name: "slices" }, + ); + } } ty::Array(..) => { - push_to_foreign_or_name( - is_foreign, - &mut foreign, - &mut name, - span, - "arrays", - ); + if is_foreign { + diag.subdiagnostic( + tcx.dcx(), + errors::OnlyCurrentTraitsForeign { span }, + ); + } else { + diag.subdiagnostic( + tcx.dcx(), + errors::OnlyCurrentTraitsName { span, name: "arrays" }, + ); + } } ty::Tuple(..) => { - push_to_foreign_or_name( - is_foreign, - &mut foreign, - &mut name, - span, - "tuples", - ); + if is_foreign { + diag.subdiagnostic( + tcx.dcx(), + errors::OnlyCurrentTraitsForeign { span }, + ); + } else { + diag.subdiagnostic( + tcx.dcx(), + errors::OnlyCurrentTraitsName { span, name: "tuples" }, + ); + } } ty::Alias(ty::Opaque, ..) => { - opaque.push(errors::OnlyCurrentTraitsOpaque { span }) + diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span }); } ty::RawPtr(ptr_ty, mutbl) => { if !self_ty.has_param() { - let mut_key = mutbl.prefix_str(); - sugg = Some(errors::OnlyCurrentTraitsPointerSugg { - wrapper_span: self_ty_span, - struct_span: full_impl_span.shrink_to_lo(), - mut_key, - ptr_ty, - }); + diag.subdiagnostic( + tcx.dcx(), + errors::OnlyCurrentTraitsPointerSugg { + wrapper_span: self_ty_span, + struct_span: full_impl_span.shrink_to_lo(), + mut_key: mutbl.prefix_str(), + ptr_ty, + }, + ); } - pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty }); + diag.subdiagnostic( + tcx.dcx(), + errors::OnlyCurrentTraitsPointer { span, pointer: ty }, + ); + } + ty::Adt(adt_def, _) => { + diag.subdiagnostic( + tcx.dcx(), + errors::OnlyCurrentTraitsAdt { + span, + name: tcx.def_path_str(adt_def.did()), + }, + ); + } + _ => { + diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsTy { span, ty }); } - ty::Adt(adt_def, _) => adt.push(errors::OnlyCurrentTraitsAdt { - span, - name: tcx.def_path_str(adt_def.did()), - }), - _ => ty_diag.push(errors::OnlyCurrentTraitsTy { span, ty }), } } - let err_struct = match self_ty.kind() { - ty::Adt(..) => errors::OnlyCurrentTraits::Outside { - span: sp, - note: (), - opaque, - foreign, - name, - pointer, - ty: ty_diag, - adt, - sugg, - }, - _ if self_ty.is_primitive() => errors::OnlyCurrentTraits::Primitive { - span: sp, - note: (), - opaque, - foreign, - name, - pointer, - ty: ty_diag, - adt, - sugg, - }, - _ => errors::OnlyCurrentTraits::Arbitrary { - span: sp, - note: (), - opaque, - foreign, - name, - pointer, - ty: ty_diag, - adt, - sugg, - }, - }; - tcx.dcx().emit_err(err_struct) + diag.emit() } traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => { let mut sp = sp; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 6595ee542e0..2d4742fa1dc 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1376,7 +1376,7 @@ pub struct TyParamSome<'a> { } #[derive(Diagnostic)] -pub enum OnlyCurrentTraits<'a> { +pub enum OnlyCurrentTraits { #[diag(hir_analysis_only_current_traits_outside, code = E0117)] Outside { #[primary_span] @@ -1384,20 +1384,6 @@ pub enum OnlyCurrentTraits<'a> { span: Span, #[note(hir_analysis_only_current_traits_note)] note: (), - #[subdiagnostic] - opaque: Vec, - #[subdiagnostic] - foreign: Vec, - #[subdiagnostic] - name: Vec>, - #[subdiagnostic] - pointer: Vec>, - #[subdiagnostic] - ty: Vec>, - #[subdiagnostic] - adt: Vec, - #[subdiagnostic] - sugg: Option>, }, #[diag(hir_analysis_only_current_traits_primitive, code = E0117)] Primitive { @@ -1406,20 +1392,6 @@ pub enum OnlyCurrentTraits<'a> { span: Span, #[note(hir_analysis_only_current_traits_note)] note: (), - #[subdiagnostic] - opaque: Vec, - #[subdiagnostic] - foreign: Vec, - #[subdiagnostic] - name: Vec>, - #[subdiagnostic] - pointer: Vec>, - #[subdiagnostic] - ty: Vec>, - #[subdiagnostic] - adt: Vec, - #[subdiagnostic] - sugg: Option>, }, #[diag(hir_analysis_only_current_traits_arbitrary, code = E0117)] Arbitrary { @@ -1428,20 +1400,6 @@ pub enum OnlyCurrentTraits<'a> { span: Span, #[note(hir_analysis_only_current_traits_note)] note: (), - #[subdiagnostic] - opaque: Vec, - #[subdiagnostic] - foreign: Vec, - #[subdiagnostic] - name: Vec>, - #[subdiagnostic] - pointer: Vec>, - #[subdiagnostic] - ty: Vec>, - #[subdiagnostic] - adt: Vec, - #[subdiagnostic] - sugg: Option>, }, } From b20e267cc52d495a7617c57006644730d1ba60dc Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Fri, 29 Mar 2024 23:00:54 -0400 Subject: [PATCH 16/24] compiletest: print reason for failing to read tests --- src/tools/compiletest/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index b791b38379f..1624e2a6084 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -571,7 +571,9 @@ pub fn make_tests( &modified_tests, &mut poisoned, ) - .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display())); + .unwrap_or_else(|reason| { + panic!("Could not read tests from {}: {reason}", config.src_base.display()) + }); if poisoned { eprintln!(); From 3855b8bb609bbaaa3871797b40a78757f88d9b12 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Tue, 25 Jul 2023 22:27:15 +0100 Subject: [PATCH 17/24] Make {integer}::from_str_radix constant --- library/core/src/lib.rs | 1 + library/core/src/num/error.rs | 3 +- library/core/src/num/int_macros.rs | 26 -- library/core/src/num/mod.rs | 311 ++++++++++++------- library/core/src/num/nonzero.rs | 3 +- library/core/src/num/uint_macros.rs | 27 -- library/core/tests/lib.rs | 1 + library/core/tests/num/mod.rs | 10 + tests/ui/consts/const-eval/parse_ints.rs | 10 + tests/ui/consts/const-eval/parse_ints.stderr | 31 ++ 10 files changed, 248 insertions(+), 175 deletions(-) create mode 100644 tests/ui/consts/const-eval/parse_ints.rs create mode 100644 tests/ui/consts/const-eval/parse_ints.stderr diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 18dd3440b6e..476e230472b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -137,6 +137,7 @@ #![feature(const_heap)] #![feature(const_hint_assert_unchecked)] #![feature(const_index_range_slice_index)] +#![feature(const_int_from_str)] #![feature(const_intrinsic_copy)] #![feature(const_intrinsic_forget)] #![feature(const_ipv4)] diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index 14e99578a7c..a2d7e6f7b07 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -113,8 +113,9 @@ pub enum IntErrorKind { impl ParseIntError { /// Outputs the detailed cause of parsing an integer failing. #[must_use] + #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")] #[stable(feature = "int_error_matching", since = "1.55.0")] - pub fn kind(&self) -> &IntErrorKind { + pub const fn kind(&self) -> &IntErrorKind { &self.kind } } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 2fec8ef2381..2f5184da885 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -60,32 +60,6 @@ macro_rules! int_impl { #[stable(feature = "int_bits_const", since = "1.53.0")] pub const BITS: u32 = <$UnsignedT>::BITS; - /// Converts a string slice in a given base to an integer. - /// - /// The string is expected to be an optional `+` or `-` sign followed by digits. - /// Leading and trailing whitespace represent an error. Digits are a subset of these characters, - /// depending on `radix`: - /// - /// * `0-9` - /// * `a-z` - /// * `A-Z` - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 36. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")] - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) - } - /// Returns the number of ones in the binary representation of `self`. /// /// # Examples diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 03c977abbbb..9e519dad432 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -6,7 +6,6 @@ use crate::ascii; use crate::hint; use crate::intrinsics; use crate::mem; -use crate::ops::{Add, Mul, Sub}; use crate::str::FromStr; // Used because the `?` operator is not allowed in a const context. @@ -1386,51 +1385,19 @@ pub enum FpCategory { Normal, } -#[doc(hidden)] -trait FromStrRadixHelper: - PartialOrd + Copy + Add + Sub + Mul -{ - const MIN: Self; - fn from_u32(u: u32) -> Self; - fn checked_mul(&self, other: u32) -> Option; - fn checked_sub(&self, other: u32) -> Option; - fn checked_add(&self, other: u32) -> Option; -} - macro_rules! from_str_radix_int_impl { ($($t:ty)*) => {$( #[stable(feature = "rust1", since = "1.0.0")] impl FromStr for $t { type Err = ParseIntError; fn from_str(src: &str) -> Result { - from_str_radix(src, 10) + <$t>::from_str_radix(src, 10) } } )*} } from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } -macro_rules! impl_helper_for { - ($($t:ty)*) => ($(impl FromStrRadixHelper for $t { - const MIN: Self = Self::MIN; - #[inline] - fn from_u32(u: u32) -> Self { u as Self } - #[inline] - fn checked_mul(&self, other: u32) -> Option { - Self::checked_mul(*self, other as Self) - } - #[inline] - fn checked_sub(&self, other: u32) -> Option { - Self::checked_sub(*self, other as Self) - } - #[inline] - fn checked_add(&self, other: u32) -> Option { - Self::checked_add(*self, other as Self) - } - })*) -} -impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize } - /// Determines if a string of text of that length of that radix could be guaranteed to be /// stored in the given type T. /// Note that if the radix is known to the compiler, it is just the check of digits.len that @@ -1438,92 +1405,198 @@ impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize } #[doc(hidden)] #[inline(always)] #[unstable(issue = "none", feature = "std_internals")] -pub fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool { +pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool { radix <= 16 && digits.len() <= mem::size_of::() * 2 - is_signed_ty as usize } -fn from_str_radix(src: &str, radix: u32) -> Result { - use self::IntErrorKind::*; - use self::ParseIntError as PIE; - - assert!( - (2..=36).contains(&radix), - "from_str_radix_int: must lie in the range `[2, 36]` - found {}", - radix - ); - - if src.is_empty() { - return Err(PIE { kind: Empty }); - } - - let is_signed_ty = T::from_u32(0) > T::MIN; - - // all valid digits are ascii, so we will just iterate over the utf8 bytes - // and cast them to chars. .to_digit() will safely return None for anything - // other than a valid ascii digit for the given radix, including the first-byte - // of multi-byte sequences - let src = src.as_bytes(); - - let (is_positive, digits) = match src[0] { - b'+' | b'-' if src[1..].is_empty() => { - return Err(PIE { kind: InvalidDigit }); - } - b'+' => (true, &src[1..]), - b'-' if is_signed_ty => (false, &src[1..]), - _ => (true, src), - }; - - let mut result = T::from_u32(0); - - if can_not_overflow::(radix, is_signed_ty, digits) { - // If the len of the str is short compared to the range of the type - // we are parsing into, then we can be certain that an overflow will not occur. - // This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition - // above is a faster (conservative) approximation of this. - // - // Consider radix 16 as it has the highest information density per digit and will thus overflow the earliest: - // `u8::MAX` is `ff` - any str of len 2 is guaranteed to not overflow. - // `i8::MAX` is `7f` - only a str of len 1 is guaranteed to not overflow. - macro_rules! run_unchecked_loop { - ($unchecked_additive_op:expr) => { - for &c in digits { - result = result * T::from_u32(radix); - let x = (c as char).to_digit(radix).ok_or(PIE { kind: InvalidDigit })?; - result = $unchecked_additive_op(result, T::from_u32(x)); - } - }; - } - if is_positive { - run_unchecked_loop!(::add) - } else { - run_unchecked_loop!(::sub) - }; - } else { - macro_rules! run_checked_loop { - ($checked_additive_op:ident, $overflow_err:expr) => { - for &c in digits { - // When `radix` is passed in as a literal, rather than doing a slow `imul` - // the compiler can use shifts if `radix` can be expressed as a - // sum of powers of 2 (x*10 can be written as x*8 + x*2). - // When the compiler can't use these optimisations, - // the latency of the multiplication can be hidden by issuing it - // before the result is needed to improve performance on - // modern out-of-order CPU as multiplication here is slower - // than the other instructions, we can get the end result faster - // doing multiplication first and let the CPU spends other cycles - // doing other computation and get multiplication result later. - let mul = result.checked_mul(radix); - let x = (c as char).to_digit(radix).ok_or(PIE { kind: InvalidDigit })?; - result = mul.ok_or_else($overflow_err)?; - result = T::$checked_additive_op(&result, x).ok_or_else($overflow_err)?; - } - }; - } - if is_positive { - run_checked_loop!(checked_add, || PIE { kind: PosOverflow }) - } else { - run_checked_loop!(checked_sub, || PIE { kind: NegOverflow }) - }; - } - Ok(result) +#[track_caller] +const fn from_str_radix_panic_ct(_radix: u32) -> ! { + panic!("from_str_radix_int: must lie in the range `[2, 36]`"); } + +#[track_caller] +fn from_str_radix_panic_rt(radix: u32) -> ! { + panic!("from_str_radix_int: must lie in the range `[2, 36]` - found {}", radix); +} + +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cold] +#[track_caller] +const fn from_str_radix_assert(radix: u32) { + if 2 > radix || radix > 36 { + // The only difference between these two functions is their panic message. + intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt); + } +} + +macro_rules! from_str_radix { + ($($int_ty:ty)+) => {$( + impl $int_ty { + /// Converts a string slice in a given base to an integer. + /// + /// The string is expected to be an optional `+` sign + /// followed by digits. + /// Leading and trailing whitespace represent an error. + /// Digits are a subset of these characters, depending on `radix`: + /// + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 36. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_str_radix(\"A\", 16), Ok(10));")] + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")] + pub const fn from_str_radix(src: &str, radix: u32) -> Result<$int_ty, ParseIntError> { + use self::IntErrorKind::*; + use self::ParseIntError as PIE; + + from_str_radix_assert(radix); + + if src.is_empty() { + return Err(PIE { kind: Empty }); + } + + #[allow(unused_comparisons)] + let is_signed_ty = 0 > <$int_ty>::MIN; + + // all valid digits are ascii, so we will just iterate over the utf8 bytes + // and cast them to chars. .to_digit() will safely return None for anything + // other than a valid ascii digit for the given radix, including the first-byte + // of multi-byte sequences + let src = src.as_bytes(); + + let (is_positive, mut digits) = match src { + [b'+' | b'-'] => { + return Err(PIE { kind: InvalidDigit }); + } + [b'+', rest @ ..] => (true, rest), + [b'-', rest @ ..] if is_signed_ty => (false, rest), + _ => (true, src), + }; + + let mut result = 0; + + macro_rules! unwrap_or_PIE { + ($option:expr, $kind:ident) => { + match $option { + Some(value) => value, + None => return Err(PIE { kind: $kind }), + } + }; + } + + if can_not_overflow::<$int_ty>(radix, is_signed_ty, digits) { + // If the len of the str is short compared to the range of the type + // we are parsing into, then we can be certain that an overflow will not occur. + // This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition + // above is a faster (conservative) approximation of this. + // + // Consider radix 16 as it has the highest information density per digit and will thus overflow the earliest: + // `u8::MAX` is `ff` - any str of len 2 is guaranteed to not overflow. + // `i8::MAX` is `7f` - only a str of len 1 is guaranteed to not overflow. + macro_rules! run_unchecked_loop { + ($unchecked_additive_op:tt) => {{ + while let [c, rest @ ..] = digits { + result = result * (radix as $int_ty); + let x = unwrap_or_PIE!((*c as char).to_digit(radix), InvalidDigit); + result = result $unchecked_additive_op (x as $int_ty); + digits = rest; + } + }}; + } + if is_positive { + run_unchecked_loop!(+) + } else { + run_unchecked_loop!(-) + }; + } else { + macro_rules! run_checked_loop { + ($checked_additive_op:ident, $overflow_err:ident) => {{ + while let [c, rest @ ..] = digits { + // When `radix` is passed in as a literal, rather than doing a slow `imul` + // the compiler can use shifts if `radix` can be expressed as a + // sum of powers of 2 (x*10 can be written as x*8 + x*2). + // When the compiler can't use these optimisations, + // the latency of the multiplication can be hidden by issuing it + // before the result is needed to improve performance on + // modern out-of-order CPU as multiplication here is slower + // than the other instructions, we can get the end result faster + // doing multiplication first and let the CPU spends other cycles + // doing other computation and get multiplication result later. + let mul = result.checked_mul(radix as $int_ty); + let x = unwrap_or_PIE!((*c as char).to_digit(radix), InvalidDigit) as $int_ty; + result = unwrap_or_PIE!(mul, $overflow_err); + result = unwrap_or_PIE!(<$int_ty>::$checked_additive_op(result, x), $overflow_err); + digits = rest; + } + }}; + } + if is_positive { + run_checked_loop!(checked_add, PosOverflow) + } else { + run_checked_loop!(checked_sub, NegOverflow) + }; + } + Ok(result) + } + } + )+} +} + +from_str_radix! { i8 u8 i16 u16 i32 u32 i64 u64 i128 u128 } + +// Re-use the relevant implementation of from_str_radix for isize and usize to avoid outputting two +// identical functions. +macro_rules! from_str_radix_size_impl { + ($($t:ident $size:ty),*) => {$( + impl $size { + /// Converts a string slice in a given base to an integer. + /// + /// The string is expected to be an optional `+` sign + /// followed by digits. + /// Leading and trailing whitespace represent an error. + /// Digits are a subset of these characters, depending on `radix`: + /// + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 36. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + #[doc = concat!("assert_eq!(", stringify!($size), "::from_str_radix(\"A\", 16), Ok(10));")] + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_from_str", issue = "59133")] + pub const fn from_str_radix(src: &str, radix: u32) -> Result<$size, ParseIntError> { + match <$t>::from_str_radix(src, radix) { + Ok(x) => Ok(x as $size), + Err(e) => Err(e), + } + } + })*} +} + +#[cfg(target_pointer_width = "16")] +from_str_radix_size_impl! { i16 isize, u16 usize } +#[cfg(target_pointer_width = "32")] +from_str_radix_size_impl! { i32 isize, u32 usize } +#[cfg(target_pointer_width = "64")] +from_str_radix_size_impl! { i64 isize, u64 usize } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 1171407c07a..62ea7abf652 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -11,7 +11,6 @@ use crate::ptr; use crate::str::FromStr; use crate::ub_checks; -use super::from_str_radix; use super::{IntErrorKind, ParseIntError}; /// A marker trait for primitive types which can be zero. @@ -804,7 +803,7 @@ macro_rules! nonzero_integer { impl FromStr for $Ty { type Err = ParseIntError; fn from_str(src: &str) -> Result { - Self::new(from_str_radix(src, 10)?) + Self::new(<$Int>::from_str_radix(src, 10)?) .ok_or(ParseIntError { kind: IntErrorKind::Zero }) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index f76f110fc4e..3f4b5955d62 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -58,33 +58,6 @@ macro_rules! uint_impl { #[stable(feature = "int_bits_const", since = "1.53.0")] pub const BITS: u32 = Self::MAX.count_ones(); - /// Converts a string slice in a given base to an integer. - /// - /// The string is expected to be an optional `+` sign - /// followed by digits. - /// Leading and trailing whitespace represent an error. - /// Digits are a subset of these characters, depending on `radix`: - /// - /// * `0-9` - /// * `a-z` - /// * `A-Z` - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 36. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")] - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) - } - /// Returns the number of ones in the binary representation of `self`. /// /// # Examples diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index f6d975c2c1e..52d2b798c91 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -16,6 +16,7 @@ #![feature(const_hash)] #![feature(const_heap)] #![feature(const_intrinsic_copy)] +#![feature(const_int_from_str)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_nonnull_new)] #![feature(const_pointer_is_aligned)] diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index 863da9b18a2..0fed854318d 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -214,6 +214,16 @@ fn test_infallible_try_from_int_error() { assert!(func(0).is_ok()); } +const _TEST_CONST_PARSE: () = { + let Ok(-0x8000) = i16::from_str_radix("-8000", 16) else { panic!() }; + let Ok(12345) = u64::from_str_radix("12345", 10) else { panic!() }; + if let Err(e) = i8::from_str_radix("+", 10) { + let IntErrorKind::InvalidDigit = e.kind() else { panic!() }; + } else { + panic!() + } +}; + macro_rules! test_impl_from { ($fn_name:ident, bool, $target: ty) => { #[test] diff --git a/tests/ui/consts/const-eval/parse_ints.rs b/tests/ui/consts/const-eval/parse_ints.rs new file mode 100644 index 00000000000..ff9fc47e65c --- /dev/null +++ b/tests/ui/consts/const-eval/parse_ints.rs @@ -0,0 +1,10 @@ +#![feature(const_int_from_str)] + +const _OK: () = match i32::from_str_radix("-1234", 10) { + Ok(x) => assert!(x == -1234), + Err(_) => panic!(), +}; +const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); }; +const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); }; + +fn main () {} diff --git a/tests/ui/consts/const-eval/parse_ints.stderr b/tests/ui/consts/const-eval/parse_ints.stderr new file mode 100644 index 00000000000..9e49fe433a1 --- /dev/null +++ b/tests/ui/consts/const-eval/parse_ints.stderr @@ -0,0 +1,31 @@ +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: the evaluated program panicked at 'from_str_radix_int: must lie in the range `[2, 36]`', $SRC_DIR/core/src/num/mod.rs:LL:COL + | +note: inside `core::num::::from_str_radix` + --> $SRC_DIR/core/src/num/mod.rs:LL:COL +note: inside `_TOO_LOW` + --> $DIR/parse_ints.rs:7:24 + | +LL | const _TOO_LOW: () = { u64::from_str_radix("12345ABCD", 1); }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `from_str_radix` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/num/mod.rs:LL:COL + | + = note: the evaluated program panicked at 'from_str_radix_int: must lie in the range `[2, 36]`', $SRC_DIR/core/src/num/mod.rs:LL:COL + | +note: inside `core::num::::from_str_radix` + --> $SRC_DIR/core/src/num/mod.rs:LL:COL +note: inside `_TOO_HIGH` + --> $DIR/parse_ints.rs:8:25 + | +LL | const _TOO_HIGH: () = { u64::from_str_radix("12345ABCD", 37); }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `from_str_radix` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. From e67f5294df55176213d0f1e8db0e8a27fd0155dc Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 13 Mar 2024 15:04:07 +0100 Subject: [PATCH 18/24] Regroup mir-opt tests of match building --- .../deref-patterns/string.foo.PreCodegen.after.mir | 0 .../{ => building/match}/deref-patterns/string.rs | 0 ...onential_or.match_tuple.SimplifyCfg-initial.after.mir | 0 tests/mir-opt/{ => building/match}/exponential_or.rs | 0 .../match_false_edges.full_tested_match.built.after.mir | 0 .../match_false_edges.full_tested_match2.built.after.mir | 0 .../{ => match}/match_false_edges.main.built.after.mir | 0 tests/mir-opt/building/{ => match}/match_false_edges.rs | 0 .../{ => match}/simple_match.match_bool.built.after.mir | 0 tests/mir-opt/building/{ => match}/simple_match.rs | 0 ...idates.disjoint_ranges.SimplifyCfg-initial.after.mir} | 4 ++-- .../{match_test.rs => building/match/sort_candidates.rs} | 9 +++++---- 12 files changed, 7 insertions(+), 6 deletions(-) rename tests/mir-opt/{ => building/match}/deref-patterns/string.foo.PreCodegen.after.mir (100%) rename tests/mir-opt/{ => building/match}/deref-patterns/string.rs (100%) rename tests/mir-opt/{ => building/match}/exponential_or.match_tuple.SimplifyCfg-initial.after.mir (100%) rename tests/mir-opt/{ => building/match}/exponential_or.rs (100%) rename tests/mir-opt/building/{ => match}/match_false_edges.full_tested_match.built.after.mir (100%) rename tests/mir-opt/building/{ => match}/match_false_edges.full_tested_match2.built.after.mir (100%) rename tests/mir-opt/building/{ => match}/match_false_edges.main.built.after.mir (100%) rename tests/mir-opt/building/{ => match}/match_false_edges.rs (100%) rename tests/mir-opt/building/{ => match}/simple_match.match_bool.built.after.mir (100%) rename tests/mir-opt/building/{ => match}/simple_match.rs (100%) rename tests/mir-opt/{match_test.main.SimplifyCfg-initial.after.mir => building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir} (95%) rename tests/mir-opt/{match_test.rs => building/match/sort_candidates.rs} (64%) diff --git a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir b/tests/mir-opt/building/match/deref-patterns/string.foo.PreCodegen.after.mir similarity index 100% rename from tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir rename to tests/mir-opt/building/match/deref-patterns/string.foo.PreCodegen.after.mir diff --git a/tests/mir-opt/deref-patterns/string.rs b/tests/mir-opt/building/match/deref-patterns/string.rs similarity index 100% rename from tests/mir-opt/deref-patterns/string.rs rename to tests/mir-opt/building/match/deref-patterns/string.rs diff --git a/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/exponential_or.match_tuple.SimplifyCfg-initial.after.mir similarity index 100% rename from tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir rename to tests/mir-opt/building/match/exponential_or.match_tuple.SimplifyCfg-initial.after.mir diff --git a/tests/mir-opt/exponential_or.rs b/tests/mir-opt/building/match/exponential_or.rs similarity index 100% rename from tests/mir-opt/exponential_or.rs rename to tests/mir-opt/building/match/exponential_or.rs diff --git a/tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir similarity index 100% rename from tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir rename to tests/mir-opt/building/match/match_false_edges.full_tested_match.built.after.mir diff --git a/tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir b/tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir similarity index 100% rename from tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir rename to tests/mir-opt/building/match/match_false_edges.full_tested_match2.built.after.mir diff --git a/tests/mir-opt/building/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir similarity index 100% rename from tests/mir-opt/building/match_false_edges.main.built.after.mir rename to tests/mir-opt/building/match/match_false_edges.main.built.after.mir diff --git a/tests/mir-opt/building/match_false_edges.rs b/tests/mir-opt/building/match/match_false_edges.rs similarity index 100% rename from tests/mir-opt/building/match_false_edges.rs rename to tests/mir-opt/building/match/match_false_edges.rs diff --git a/tests/mir-opt/building/simple_match.match_bool.built.after.mir b/tests/mir-opt/building/match/simple_match.match_bool.built.after.mir similarity index 100% rename from tests/mir-opt/building/simple_match.match_bool.built.after.mir rename to tests/mir-opt/building/match/simple_match.match_bool.built.after.mir diff --git a/tests/mir-opt/building/simple_match.rs b/tests/mir-opt/building/match/simple_match.rs similarity index 100% rename from tests/mir-opt/building/simple_match.rs rename to tests/mir-opt/building/match/simple_match.rs diff --git a/tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir similarity index 95% rename from tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir rename to tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir index 107f56f7f69..149c13a8c2f 100644 --- a/tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir @@ -1,6 +1,6 @@ -// MIR for `main` after SimplifyCfg-initial +// MIR for `disjoint_ranges` after SimplifyCfg-initial -fn main() -> () { +fn disjoint_ranges() -> () { let mut _0: (); let _1: i32; let _3: i32; diff --git a/tests/mir-opt/match_test.rs b/tests/mir-opt/building/match/sort_candidates.rs similarity index 64% rename from tests/mir-opt/match_test.rs rename to tests/mir-opt/building/match/sort_candidates.rs index e465289e427..755e445ed18 100644 --- a/tests/mir-opt/match_test.rs +++ b/tests/mir-opt/building/match/sort_candidates.rs @@ -1,10 +1,9 @@ // skip-filecheck -// Make sure redundant testing paths in `match` expressions are sorted out. - +// Check specific cases of sorting candidates in match lowering. #![feature(exclusive_range_pattern)] -// EMIT_MIR match_test.main.SimplifyCfg-initial.after.mir -fn main() { +// EMIT_MIR sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir +fn disjoint_ranges() { let x = 3; let b = true; @@ -17,3 +16,5 @@ fn main() { _ => 3, }; } + +fn main() {} From 5ef9ad37abf51d7346f7ac68b910f1a18d86f65b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 13 Mar 2024 22:20:40 +0100 Subject: [PATCH 19/24] Add test --- ....constant_eq.SimplifyCfg-initial.after.mir | 127 ++++++++++++++++++ .../mir-opt/building/match/sort_candidates.rs | 12 ++ 2 files changed, 139 insertions(+) create mode 100644 tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir new file mode 100644 index 00000000000..d515a676bb0 --- /dev/null +++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir @@ -0,0 +1,127 @@ +// MIR for `constant_eq` after SimplifyCfg-initial + +fn constant_eq(_1: &str, _2: bool) -> u32 { + debug s => _1; + debug b => _2; + let mut _0: u32; + let mut _3: (&str, bool); + let mut _4: &str; + let mut _5: bool; + let mut _6: bool; + let mut _7: bool; + let mut _8: bool; + let mut _9: &&str; + let mut _10: &bool; + let mut _11: bool; + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = _1; + StorageLive(_5); + _5 = _2; + _3 = (move _4, move _5); + StorageDead(_5); + StorageDead(_4); + PlaceMention(_3); + _8 = ::eq((_3.0: &str), const "a") -> [return: bb13, unwind: bb21]; + } + + bb1: { + _7 = ::eq((_3.0: &str), const "b") -> [return: bb11, unwind: bb21]; + } + + bb2: { + _6 = ::eq((_3.0: &str), const "a") -> [return: bb8, unwind: bb21]; + } + + bb3: { + switchInt((_3.1: bool)) -> [0: bb4, otherwise: bb5]; + } + + bb4: { + _0 = const 5_u32; + goto -> bb20; + } + + bb5: { + falseEdge -> [real: bb19, imaginary: bb4]; + } + + bb6: { + switchInt((_3.1: bool)) -> [0: bb3, otherwise: bb7]; + } + + bb7: { + falseEdge -> [real: bb18, imaginary: bb5]; + } + + bb8: { + switchInt(move _6) -> [0: bb3, otherwise: bb6]; + } + + bb9: { + switchInt((_3.1: bool)) -> [0: bb2, otherwise: bb10]; + } + + bb10: { + falseEdge -> [real: bb17, imaginary: bb7]; + } + + bb11: { + switchInt(move _7) -> [0: bb2, otherwise: bb9]; + } + + bb12: { + falseEdge -> [real: bb14, imaginary: bb10]; + } + + bb13: { + switchInt(move _8) -> [0: bb1, otherwise: bb12]; + } + + bb14: { + _9 = &fake (_3.0: &str); + _10 = &fake (_3.1: bool); + StorageLive(_11); + _11 = const true; + switchInt(move _11) -> [0: bb16, otherwise: bb15]; + } + + bb15: { + StorageDead(_11); + FakeRead(ForMatchGuard, _9); + FakeRead(ForMatchGuard, _10); + _0 = const 1_u32; + goto -> bb20; + } + + bb16: { + StorageDead(_11); + falseEdge -> [real: bb1, imaginary: bb10]; + } + + bb17: { + _0 = const 2_u32; + goto -> bb20; + } + + bb18: { + _0 = const 3_u32; + goto -> bb20; + } + + bb19: { + _0 = const 4_u32; + goto -> bb20; + } + + bb20: { + StorageDead(_3); + return; + } + + bb21 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/match/sort_candidates.rs b/tests/mir-opt/building/match/sort_candidates.rs index 755e445ed18..ead8e62db52 100644 --- a/tests/mir-opt/building/match/sort_candidates.rs +++ b/tests/mir-opt/building/match/sort_candidates.rs @@ -2,6 +2,18 @@ // Check specific cases of sorting candidates in match lowering. #![feature(exclusive_range_pattern)] +// EMIT_MIR sort_candidates.constant_eq.SimplifyCfg-initial.after.mir +fn constant_eq(s: &str, b: bool) -> u32 { + // For now we test "a" twice. + match (s, b) { + ("a", _) if true => 1, + ("b", true) => 2, + ("a", true) => 3, + (_, true) => 4, + _ => 5, + } +} + // EMIT_MIR sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir fn disjoint_ranges() { let x = 3; From 75d2e67ed240731c15b697424bbd671464c4bde6 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 13 Mar 2024 22:23:45 +0100 Subject: [PATCH 20/24] Sort `Eq` candidates in the failure case too --- .../rustc_mir_build/src/build/matches/test.rs | 14 ++-- ....constant_eq.SimplifyCfg-initial.after.mir | 79 ++++++++----------- .../mir-opt/building/match/sort_candidates.rs | 2 +- 3 files changed, 44 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index b66dd83b7ec..690879b9488 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -650,12 +650,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - // FIXME(#29623): return `Some(1)` when the values are different. - (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) - if test_val == case_val => - { - fully_matched = true; - Some(TestBranch::Success) + (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) => { + if test_val == case_val { + fully_matched = true; + Some(TestBranch::Success) + } else { + fully_matched = false; + Some(TestBranch::Failure) + } } ( diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir index d515a676bb0..e95a97b5b87 100644 --- a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir @@ -9,10 +9,9 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { let mut _5: bool; let mut _6: bool; let mut _7: bool; - let mut _8: bool; - let mut _9: &&str; - let mut _10: &bool; - let mut _11: bool; + let mut _8: &&str; + let mut _9: &bool; + let mut _10: bool; bb0: { StorageLive(_3); @@ -24,104 +23,96 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { StorageDead(_5); StorageDead(_4); PlaceMention(_3); - _8 = ::eq((_3.0: &str), const "a") -> [return: bb13, unwind: bb21]; + _7 = ::eq((_3.0: &str), const "a") -> [return: bb11, unwind: bb19]; } bb1: { - _7 = ::eq((_3.0: &str), const "b") -> [return: bb11, unwind: bb21]; + switchInt((_3.1: bool)) -> [0: bb2, otherwise: bb3]; } bb2: { - _6 = ::eq((_3.0: &str), const "a") -> [return: bb8, unwind: bb21]; + _0 = const 5_u32; + goto -> bb18; } bb3: { - switchInt((_3.1: bool)) -> [0: bb4, otherwise: bb5]; + falseEdge -> [real: bb17, imaginary: bb2]; } bb4: { - _0 = const 5_u32; - goto -> bb20; + falseEdge -> [real: bb12, imaginary: bb9]; } bb5: { - falseEdge -> [real: bb19, imaginary: bb4]; + switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb6]; } bb6: { - switchInt((_3.1: bool)) -> [0: bb3, otherwise: bb7]; + falseEdge -> [real: bb16, imaginary: bb3]; } bb7: { - falseEdge -> [real: bb18, imaginary: bb5]; + _6 = ::eq((_3.0: &str), const "b") -> [return: bb10, unwind: bb19]; } bb8: { - switchInt(move _6) -> [0: bb3, otherwise: bb6]; + switchInt((_3.1: bool)) -> [0: bb1, otherwise: bb9]; } bb9: { - switchInt((_3.1: bool)) -> [0: bb2, otherwise: bb10]; + falseEdge -> [real: bb15, imaginary: bb6]; } bb10: { - falseEdge -> [real: bb17, imaginary: bb7]; + switchInt(move _6) -> [0: bb1, otherwise: bb8]; } bb11: { - switchInt(move _7) -> [0: bb2, otherwise: bb9]; + switchInt(move _7) -> [0: bb7, otherwise: bb4]; } bb12: { - falseEdge -> [real: bb14, imaginary: bb10]; + _8 = &fake (_3.0: &str); + _9 = &fake (_3.1: bool); + StorageLive(_10); + _10 = const true; + switchInt(move _10) -> [0: bb14, otherwise: bb13]; } bb13: { - switchInt(move _8) -> [0: bb1, otherwise: bb12]; + StorageDead(_10); + FakeRead(ForMatchGuard, _8); + FakeRead(ForMatchGuard, _9); + _0 = const 1_u32; + goto -> bb18; } bb14: { - _9 = &fake (_3.0: &str); - _10 = &fake (_3.1: bool); - StorageLive(_11); - _11 = const true; - switchInt(move _11) -> [0: bb16, otherwise: bb15]; + StorageDead(_10); + falseEdge -> [real: bb5, imaginary: bb9]; } bb15: { - StorageDead(_11); - FakeRead(ForMatchGuard, _9); - FakeRead(ForMatchGuard, _10); - _0 = const 1_u32; - goto -> bb20; + _0 = const 2_u32; + goto -> bb18; } bb16: { - StorageDead(_11); - falseEdge -> [real: bb1, imaginary: bb10]; + _0 = const 3_u32; + goto -> bb18; } bb17: { - _0 = const 2_u32; - goto -> bb20; + _0 = const 4_u32; + goto -> bb18; } bb18: { - _0 = const 3_u32; - goto -> bb20; - } - - bb19: { - _0 = const 4_u32; - goto -> bb20; - } - - bb20: { StorageDead(_3); return; } - bb21 (cleanup): { + bb19 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match/sort_candidates.rs b/tests/mir-opt/building/match/sort_candidates.rs index ead8e62db52..2f93cd767bd 100644 --- a/tests/mir-opt/building/match/sort_candidates.rs +++ b/tests/mir-opt/building/match/sort_candidates.rs @@ -4,7 +4,7 @@ // EMIT_MIR sort_candidates.constant_eq.SimplifyCfg-initial.after.mir fn constant_eq(s: &str, b: bool) -> u32 { - // For now we test "a" twice. + // Check that we only test "a" once match (s, b) { ("a", _) if true => 1, ("b", true) => 2, From e974570c42f4460b30fce11003b7891435931cbd Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Wed, 27 Mar 2024 15:50:53 +0000 Subject: [PATCH 21/24] CFI: Only encode Coroutine Parent Args Fixes #122705 --- .../src/typeid/typeid_itanium_cxx_abi.rs | 16 ++++++++-- tests/ui/sanitizer/cfi-async-closures.rs | 30 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 tests/ui/sanitizer/cfi-async-closures.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 aba3212b4ce..82ceccba66a 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 @@ -641,9 +641,7 @@ fn encode_ty<'tcx>( } // Function types - ty::FnDef(def_id, args) - | ty::Closure(def_id, args) - | ty::CoroutineClosure(def_id, args) => { + ty::FnDef(def_id, args) | ty::Closure(def_id, args) => { // u[IE], where is , // as vendor extended type. let mut s = String::new(); @@ -654,6 +652,18 @@ fn encode_ty<'tcx>( typeid.push_str(&s); } + ty::CoroutineClosure(def_id, args) => { + // u[IE], where is , + // as vendor extended type. + let mut s = String::new(); + let name = encode_ty_name(tcx, *def_id); + let _ = write!(s, "u{}{}", name.len(), &name); + let parent_args = tcx.mk_args(args.as_coroutine_closure().parent_args()); + s.push_str(&encode_args(tcx, parent_args, dict, options)); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + ty::Coroutine(def_id, args, ..) => { // u[IE], where is , // as vendor extended type. diff --git a/tests/ui/sanitizer/cfi-async-closures.rs b/tests/ui/sanitizer/cfi-async-closures.rs new file mode 100644 index 00000000000..50edeb852bd --- /dev/null +++ b/tests/ui/sanitizer/cfi-async-closures.rs @@ -0,0 +1,30 @@ +// Check various forms of dynamic closure calls + +//@ edition: 2021 +//@ revisions: cfi kcfi +// FIXME(#122848) Remove only-linux once OSX CFI binaries work +//@ only-linux +//@ [cfi] needs-sanitizer-cfi +//@ [kcfi] needs-sanitizer-kcfi +//@ compile-flags: -C target-feature=-crt-static +//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 +//@ [cfi] compile-flags: -Z sanitizer=cfi +//@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ run-pass + +#![feature(async_closure)] +#![feature(async_fn_traits)] + +use std::ops::AsyncFn; + +#[inline(never)] +fn identity(x: T) -> T { x } + +// We can't actually create a `dyn AsyncFn()`, because it's not object-safe, but we should check +// that we don't bug out when we encounter one. + +fn main() { + let f = identity(async || ()); + let _ = f.async_call(()); + let _ = f(); +} From 8cc9a912d7daf092adc53f0b6b7fac5e86fa7e0a Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Tue, 26 Mar 2024 17:00:57 +0000 Subject: [PATCH 22/24] CFI: Rewrite closure and coroutine instances to their trait method Similar to methods on a trait object, the most common way to indirectly call a closure or coroutine is through the vtable on the appropriate trait. This uses the same approach as we use for trait methods, after backing out the trait arguments from the type. --- .../src/typeid/typeid_itanium_cxx_abi.rs | 115 +++++++++++++----- tests/ui/sanitizer/cfi-async-closures.rs | 3 + tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs | 23 ---- tests/ui/sanitizer/cfi-closures.rs | 83 +++++++++++++ tests/ui/sanitizer/cfi-coroutine.rs | 30 +++++ 5 files changed, 198 insertions(+), 56 deletions(-) delete mode 100644 tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs create mode 100644 tests/ui/sanitizer/cfi-closures.rs create mode 100644 tests/ui/sanitizer/cfi-coroutine.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 82ceccba66a..5963bd7c5f1 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 @@ -10,6 +10,7 @@ use rustc_data_structures::base_n; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; +use rustc_hir::lang_items::LangItem; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{ @@ -1161,43 +1162,91 @@ pub fn typeid_for_instance<'tcx>( }; let stripped_ty = strip_receiver_auto(tcx, upcast_ty); instance.args = tcx.mk_args_trait(stripped_ty, instance.args.into_iter().skip(1)); + } else if let ty::InstanceDef::VTableShim(def_id) = instance.def + && let Some(trait_id) = tcx.trait_of_item(def_id) + { + // VTableShims may have a trait method, but a concrete Self. This is not suitable for a vtable, + // as the caller will not know the concrete Self. + let trait_ref = ty::TraitRef::new(tcx, trait_id, instance.args); + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); + instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); } - if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE) - && let Some(impl_id) = tcx.impl_of_method(instance.def_id()) - && let Some(trait_ref) = tcx.impl_trait_ref(impl_id) - { - let impl_method = tcx.associated_item(instance.def_id()); - let method_id = impl_method - .trait_item_def_id - .expect("Part of a trait implementation, but not linked to the def_id?"); - let trait_method = tcx.associated_item(method_id); - let trait_id = trait_ref.skip_binder().def_id; - if traits::is_vtable_safe_method(tcx, trait_id, trait_method) - && tcx.object_safety_violations(trait_id).is_empty() + if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE) { + if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) + && let Some(trait_ref) = tcx.impl_trait_ref(impl_id) { - // Trait methods will have a Self polymorphic parameter, where the concreteized - // implementatation will not. We need to walk back to the more general trait method - let trait_ref = tcx.instantiate_and_normalize_erasing_regions( - instance.args, - ty::ParamEnv::reveal_all(), - trait_ref, - ); - let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); + let impl_method = tcx.associated_item(instance.def_id()); + let method_id = impl_method + .trait_item_def_id + .expect("Part of a trait implementation, but not linked to the def_id?"); + let trait_method = tcx.associated_item(method_id); + let trait_id = trait_ref.skip_binder().def_id; + if traits::is_vtable_safe_method(tcx, trait_id, trait_method) + && tcx.object_safety_violations(trait_id).is_empty() + { + // Trait methods will have a Self polymorphic parameter, where the concreteized + // implementatation will not. We need to walk back to the more general trait method + let trait_ref = tcx.instantiate_and_normalize_erasing_regions( + instance.args, + ty::ParamEnv::reveal_all(), + trait_ref, + ); + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); - // At the call site, any call to this concrete function through a vtable will be - // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the - // original method id, and we've recovered the trait arguments, we can make the callee - // instance we're computing the alias set for match the caller instance. - // - // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder. - // If we ever *do* start encoding the vtable index, we will need to generate an alias set - // based on which vtables we are putting this method into, as there will be more than one - // index value when supertraits are involved. - instance.def = ty::InstanceDef::Virtual(method_id, 0); - let abstract_trait_args = - tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); - instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args); + // At the call site, any call to this concrete function through a vtable will be + // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the + // original method id, and we've recovered the trait arguments, we can make the callee + // instance we're computing the alias set for match the caller instance. + // + // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder. + // If we ever *do* start encoding the vtable index, we will need to generate an alias set + // based on which vtables we are putting this method into, as there will be more than one + // index value when supertraits are involved. + instance.def = ty::InstanceDef::Virtual(method_id, 0); + let abstract_trait_args = + tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); + instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args); + } + } else if tcx.is_closure_like(instance.def_id()) { + // We're either a closure or a coroutine. Our goal is to find the trait we're defined on, + // instantiate it, and take the type of its only method as our own. + let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + let (trait_id, inputs) = match closure_ty.kind() { + ty::Closure(..) => { + let closure_args = instance.args.as_closure(); + let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap(); + let tuple_args = + tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0]; + (trait_id, tuple_args) + } + ty::Coroutine(..) => ( + tcx.require_lang_item(LangItem::Coroutine, None), + instance.args.as_coroutine().resume_ty(), + ), + ty::CoroutineClosure(..) => ( + tcx.require_lang_item(LangItem::FnOnce, None), + tcx.instantiate_bound_regions_with_erased( + instance.args.as_coroutine_closure().coroutine_closure_sig(), + ) + .tupled_inputs_ty, + ), + x => bug!("Unexpected type kind for closure-like: {x:?}"), + }; + let trait_ref = ty::TraitRef::new(tcx, trait_id, [closure_ty, inputs]); + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); + let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); + // There should be exactly one method on this trait, and it should be the one we're + // defining. + let call = tcx + .associated_items(trait_id) + .in_definition_order() + .find(|it| it.kind == ty::AssocKind::Fn) + .expect("No call-family function on closure-like Fn trait?") + .def_id; + + instance.def = ty::InstanceDef::Virtual(call, 0); + instance.args = abstract_args; } } diff --git a/tests/ui/sanitizer/cfi-async-closures.rs b/tests/ui/sanitizer/cfi-async-closures.rs index 50edeb852bd..d94f2992d84 100644 --- a/tests/ui/sanitizer/cfi-async-closures.rs +++ b/tests/ui/sanitizer/cfi-async-closures.rs @@ -10,6 +10,7 @@ //@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 //@ [cfi] compile-flags: -Z sanitizer=cfi //@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off //@ run-pass #![feature(async_closure)] @@ -27,4 +28,6 @@ fn main() { let f = identity(async || ()); let _ = f.async_call(()); let _ = f(); + let g: Box _> = Box::new(f) as _; + let _ = g(); } diff --git a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs deleted file mode 100644 index 03818544aab..00000000000 --- a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Tests that converting a closure to a function pointer works -// The notable thing being tested here is that when the closure does not capture anything, -// the call method from its Fn trait takes a ZST representing its environment. The compiler then -// uses the assumption that the ZST is non-passed to reify this into a function pointer. -// -// This checks that the reified function pointer will have the expected alias set at its call-site. - -//@ revisions: cfi kcfi -// FIXME(#122848) Remove only-linux once OSX CFI binaries work -//@ only-linux -//@ [cfi] needs-sanitizer-cfi -//@ [kcfi] needs-sanitizer-kcfi -//@ compile-flags: -C target-feature=-crt-static -//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 -//@ [cfi] compile-flags: -Z sanitizer=cfi -//@ [kcfi] compile-flags: -Z sanitizer=kcfi -//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off -//@ run-pass - -pub fn main() { - let f: &fn() = &((|| ()) as _); - f(); -} diff --git a/tests/ui/sanitizer/cfi-closures.rs b/tests/ui/sanitizer/cfi-closures.rs new file mode 100644 index 00000000000..54f1cc035bc --- /dev/null +++ b/tests/ui/sanitizer/cfi-closures.rs @@ -0,0 +1,83 @@ +// Check various forms of dynamic closure calls + +//@ revisions: cfi kcfi +// FIXME(#122848) Remove only-linux once OSX CFI binaries work +//@ only-linux +//@ [cfi] needs-sanitizer-cfi +//@ [kcfi] needs-sanitizer-kcfi +//@ compile-flags: -C target-feature=-crt-static +//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 +//@ [cfi] compile-flags: -Z sanitizer=cfi +//@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off +//@ compile-flags: --test +//@ run-pass + +#![feature(fn_traits)] +#![feature(unboxed_closures)] +#![feature(cfg_sanitize)] + +fn foo<'a, T>() -> Box &'a T> { + Box::new(|x| x) +} + +#[test] +fn dyn_fn_with_params() { + let x = 3; + let f = foo(); + f(&x); + // FIXME remove once drops are working. + std::mem::forget(f); +} + +#[test] +fn call_fn_trait() { + let f: &(dyn Fn()) = &(|| {}) as _; + f.call(()); +} + +#[test] +fn fn_ptr_cast() { + let f: &fn() = &((|| ()) as _); + f(); +} + +fn use_fnmut(mut f: F) { + f() +} + +#[test] +fn fn_to_fnmut() { + let f: &(dyn Fn()) = &(|| {}) as _; + use_fnmut(f); +} + +fn hrtb_helper(f: &dyn for<'a> Fn(&'a usize)) { + f(&10) +} + +#[test] +fn hrtb_fn() { + hrtb_helper((&|x: &usize| println!("{}", *x)) as _) +} + +#[test] +fn fnonce() { + let f: Box = Box::new(|| {}) as _; + f(); +} + +fn use_closure(call: extern "rust-call" fn(&C, ()) -> i32, f: &C) -> i32 { + call(f, ()) +} + +#[test] +// FIXME after KCFI reify support is added, remove this +// It will appear to work if you test locally, set -C opt-level=0 to see it fail. +#[cfg_attr(sanitize = "kcfi", ignore)] +fn closure_addr_taken() { + let x = 3i32; + let f = || x; + let call = Fn::<()>::call; + use_closure(call, &f); +} diff --git a/tests/ui/sanitizer/cfi-coroutine.rs b/tests/ui/sanitizer/cfi-coroutine.rs new file mode 100644 index 00000000000..24e59cf5b4d --- /dev/null +++ b/tests/ui/sanitizer/cfi-coroutine.rs @@ -0,0 +1,30 @@ +// Verifies that we can call dynamic coroutines + +//@ revisions: cfi kcfi +// FIXME(#122848) Remove only-linux once OSX CFI binaries work +//@ only-linux +//@ [cfi] needs-sanitizer-cfi +//@ [kcfi] needs-sanitizer-kcfi +//@ compile-flags: -C target-feature=-crt-static +//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 +//@ [cfi] compile-flags: -Z sanitizer=cfi +//@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off +//@ compile-flags: --test +//@ run-pass + +#![feature(coroutines)] +#![feature(coroutine_trait)] + +use std::ops::{Coroutine, CoroutineState}; +use std::pin::{pin, Pin}; + +fn main() { + let mut coro = |x: i32| { + yield x; + "done" + }; + let mut abstract_coro: Pin<&mut dyn Coroutine> = pin!(coro); + assert_eq!(abstract_coro.as_mut().resume(2), CoroutineState::Yielded(2)); + assert_eq!(abstract_coro.as_mut().resume(0), CoroutineState::Complete("done")); +} From 65efa5b3b9ec77be6a009a08ea07971d6438ec9b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 27 Mar 2024 17:50:58 +0100 Subject: [PATCH 23/24] Add FileCheck directives to the new tests. --- ...joint_ranges.SimplifyCfg-initial.after.mir | 70 +++++++------------ .../mir-opt/building/match/sort_candidates.rs | 23 ++++-- 2 files changed, 42 insertions(+), 51 deletions(-) diff --git a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir index 149c13a8c2f..80d3c2e5c23 100644 --- a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir @@ -1,38 +1,24 @@ // MIR for `disjoint_ranges` after SimplifyCfg-initial -fn disjoint_ranges() -> () { - let mut _0: (); - let _1: i32; - let _3: i32; +fn disjoint_ranges(_1: i32, _2: bool) -> u32 { + debug x => _1; + debug b => _2; + let mut _0: u32; + let mut _3: bool; let mut _4: bool; let mut _5: bool; let mut _6: bool; - let mut _7: bool; - let mut _8: &i32; - let mut _9: bool; - scope 1 { - debug x => _1; - let _2: bool; - scope 2 { - debug b => _2; - } - } + let mut _7: &i32; + let mut _8: bool; bb0: { - StorageLive(_1); - _1 = const 3_i32; - FakeRead(ForLet(None), _1); - StorageLive(_2); - _2 = const true; - FakeRead(ForLet(None), _2); - StorageLive(_3); PlaceMention(_1); - _6 = Le(const 0_i32, _1); - switchInt(move _6) -> [0: bb3, otherwise: bb8]; + _5 = Le(const 0_i32, _1); + switchInt(move _5) -> [0: bb3, otherwise: bb8]; } bb1: { - _3 = const 3_i32; + _0 = const 3_u32; goto -> bb14; } @@ -41,8 +27,8 @@ fn disjoint_ranges() -> () { } bb3: { - _4 = Le(const 10_i32, _1); - switchInt(move _4) -> [0: bb5, otherwise: bb7]; + _3 = Le(const 10_i32, _1); + switchInt(move _3) -> [0: bb5, otherwise: bb7]; } bb4: { @@ -58,49 +44,45 @@ fn disjoint_ranges() -> () { } bb7: { - _5 = Le(_1, const 20_i32); - switchInt(move _5) -> [0: bb5, otherwise: bb4]; + _4 = Le(_1, const 20_i32); + switchInt(move _4) -> [0: bb5, otherwise: bb4]; } bb8: { - _7 = Lt(_1, const 10_i32); - switchInt(move _7) -> [0: bb3, otherwise: bb2]; + _6 = Lt(_1, const 10_i32); + switchInt(move _6) -> [0: bb3, otherwise: bb2]; } bb9: { - _8 = &fake _1; - StorageLive(_9); - _9 = _2; - switchInt(move _9) -> [0: bb11, otherwise: bb10]; + _7 = &fake _1; + StorageLive(_8); + _8 = _2; + switchInt(move _8) -> [0: bb11, otherwise: bb10]; } bb10: { - StorageDead(_9); - FakeRead(ForMatchGuard, _8); - _3 = const 0_i32; + StorageDead(_8); + FakeRead(ForMatchGuard, _7); + _0 = const 0_u32; goto -> bb14; } bb11: { - StorageDead(_9); + StorageDead(_8); falseEdge -> [real: bb1, imaginary: bb4]; } bb12: { - _3 = const 1_i32; + _0 = const 1_u32; goto -> bb14; } bb13: { - _3 = const 2_i32; + _0 = const 2_u32; goto -> bb14; } bb14: { - StorageDead(_3); - _0 = const (); - StorageDead(_2); - StorageDead(_1); return; } } diff --git a/tests/mir-opt/building/match/sort_candidates.rs b/tests/mir-opt/building/match/sort_candidates.rs index 2f93cd767bd..a2583ff8284 100644 --- a/tests/mir-opt/building/match/sort_candidates.rs +++ b/tests/mir-opt/building/match/sort_candidates.rs @@ -1,10 +1,14 @@ -// skip-filecheck // Check specific cases of sorting candidates in match lowering. #![feature(exclusive_range_pattern)] // EMIT_MIR sort_candidates.constant_eq.SimplifyCfg-initial.after.mir fn constant_eq(s: &str, b: bool) -> u32 { // Check that we only test "a" once + + // CHECK-LABEL: fn constant_eq( + // CHECK: bb0: { + // CHECK: [[a:_.*]] = const "a"; + // CHECK-NOT: {{_.*}} = const "a"; match (s, b) { ("a", _) if true => 1, ("b", true) => 2, @@ -15,18 +19,23 @@ fn constant_eq(s: &str, b: bool) -> u32 { } // EMIT_MIR sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir -fn disjoint_ranges() { - let x = 3; - let b = true; +fn disjoint_ranges(x: i32, b: bool) -> u32 { + // When `(0..=10).contains(x) && !b`, we should jump to the last arm without testing the two + // other candidates. - // When `(0..=10).contains(x) && !b`, we should jump to the last arm - // without testing two other candidates. + // CHECK-LABEL: fn disjoint_ranges( + // CHECK: debug b => _2; + // CHECK: bb0: { + // CHECK: switchInt(_2) -> [0: [[jump:bb.*]], otherwise: {{bb.*}}]; + // CHECK: [[jump]]: { + // CHECK-NEXT: _0 = const 3_u32; + // CHECK-NEXT: return; match x { 0..10 if b => 0, 10..=20 => 1, -1 => 2, _ => 3, - }; + } } fn main() {} From 2dd824789c34d059ad787fc65ad15ffc668c895e Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 31 Mar 2024 05:33:07 +0000 Subject: [PATCH 24/24] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 3679f56c0c0..187756851c7 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -69fa40cb48384fad7930dce2d9a20d18fe4d1b51 +5baf1e13f568b61e121953bf6a3d09faee7dd446