Auto merge of #128165 - saethlin:optimize-clone-shims, r=compiler-errors

Let InstCombine remove Clone shims inside Clone shims

The Clone shims that we generate tend to recurse into other Clone shims, which gets very silly very quickly. Here's our current state: https://godbolt.org/z/E69YeY8eq

So I've added InstSimplify to the shims optimization passes, and improved `is_trivially_pure_clone_copy` so that it can delete those calls inside the shim. This makes the shim way smaller because most of its size is the required ceremony for unwinding.

This change also completely breaks the UI test added for https://github.com/rust-lang/rust/issues/104870. With this PR, that program ICEs in MIR type checking because `is_trivially_pure_clone_copy` and the trait solver disagree on whether `*mut u8` is `Copy`. And adding the requisite `Copy` impl to make them agree makes the test not generate any diagnostics. Considering that I spent most of my time on this PR fixing `#![no_core]` tests, I would prefer to just delete this one. The maintenance burden of `#![no_core]` is uniquely high because when they break they tend to break in very confusing ways.

try-job: x86_64-mingw
This commit is contained in:
bors 2024-07-26 13:13:04 +00:00
commit 2d5a628a1d
13 changed files with 31 additions and 45 deletions

View File

@ -1864,9 +1864,9 @@ pub fn is_trivially_pure_clone_copy(self) -> bool {
// Definitely absolutely not copy. // Definitely absolutely not copy.
ty::Ref(_, _, hir::Mutability::Mut) => false, ty::Ref(_, _, hir::Mutability::Mut) => false,
// Thin pointers & thin shared references are pure-clone-copy, but for // The standard library has a blanket Copy impl for shared references and raw pointers,
// anything with custom metadata it might be more complicated. // for all unsized types.
ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false, ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => true,
ty::Coroutine(..) | ty::CoroutineWitness(..) => false, ty::Coroutine(..) | ty::CoroutineWitness(..) => false,

View File

@ -17,7 +17,7 @@
use crate::{ use crate::{
abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator,
mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify, instsimplify, mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify,
}; };
use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::patch::MirPatch;
use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle}; use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
@ -154,6 +154,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
&deref_separator::Derefer, &deref_separator::Derefer,
&remove_noop_landing_pads::RemoveNoopLandingPads, &remove_noop_landing_pads::RemoveNoopLandingPads,
&simplify::SimplifyCfg::MakeShim, &simplify::SimplifyCfg::MakeShim,
&instsimplify::InstSimplify,
&abort_unwinding_calls::AbortUnwindingCalls, &abort_unwinding_calls::AbortUnwindingCalls,
&add_call_guards::CriticalCallEdges, &add_call_guards::CriticalCallEdges,
], ],

View File

@ -29,6 +29,8 @@ trait Copy {}
#[lang = "freeze"] #[lang = "freeze"]
auto trait Freeze {} auto trait Freeze {}
impl<T: ?Sized> Copy for *mut T {}
#[lang = "drop_in_place"] #[lang = "drop_in_place"]
#[inline] #[inline]
#[allow(unconditional_recursion)] #[allow(unconditional_recursion)]

View File

@ -17,6 +17,8 @@ trait Copy {}
#[lang = "freeze"] #[lang = "freeze"]
auto trait Freeze {} auto trait Freeze {}
impl<T: ?Sized> Copy for *mut T {}
#[lang = "drop_in_place"] #[lang = "drop_in_place"]
#[inline] #[inline]
#[allow(unconditional_recursion)] #[allow(unconditional_recursion)]

View File

@ -18,6 +18,7 @@ pub trait Sized {}
#[lang = "copy"] #[lang = "copy"]
trait Copy {} trait Copy {}
impl<T: ?Sized> Copy for *const T {}
#[repr(simd)] #[repr(simd)]
pub struct i8x16([i8; 16]); pub struct i8x16([i8; 16]);

View File

@ -18,6 +18,7 @@ pub trait Sized {}
#[lang = "copy"] #[lang = "copy"]
trait Copy {} trait Copy {}
impl<T: ?Sized> Copy for *mut T {}
#[repr(simd)] #[repr(simd)]
pub struct i8x16([i8; 16]); pub struct i8x16([i8; 16]);

View File

@ -17,6 +17,7 @@
pub trait Sized {} pub trait Sized {}
#[lang = "copy"] #[lang = "copy"]
pub trait Copy {} pub trait Copy {}
impl<T: ?Sized> Copy for *const T {}
#[lang = "receiver"] #[lang = "receiver"]
pub trait Receiver {} pub trait Receiver {}
#[lang = "tuple_trait"] #[lang = "tuple_trait"]

View File

@ -0,0 +1,15 @@
// Clone shims for aggregates are generated by just calling the Clone shims for all their members.
// Those calls generate a lot of unnecessary IR if the members are Copy. This test ensures that we
// optimize away those inner calls without needing to inline them.
//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no
#![crate_type = "lib"]
pub type Test = (i32, i32, *const i32);
pub static TEST: fn(&Test) -> Test = <Test as core::clone::Clone>::clone;
// CHECK-NOT: call <i32 as core::clone::Clone>::clone
// CHECK-NOT: call <*const i32 as core::clone::Clone>::clone
// CHECK: ; <(i32, i32, *const i32) as core::clone::Clone>::clone
// CHECK-NOT: call <i32 as core::clone::Clone>::clone
// CHECK-NOT: call <*const i32 as core::clone::Clone>::clone

View File

@ -16,6 +16,8 @@ trait Freeze {}
#[lang = "copy"] #[lang = "copy"]
trait Copy {} trait Copy {}
impl<T> Copy for *mut T {}
#[rustc_intrinsic] #[rustc_intrinsic]
fn size_of<T>() -> usize { fn size_of<T>() -> usize {
loop {} loop {}

View File

@ -18,6 +18,7 @@ impl Copy for i64 {}
impl Copy for u64 {} impl Copy for u64 {}
impl Copy for f32 {} impl Copy for f32 {}
impl Copy for f64 {} impl Copy for f64 {}
impl<T> Copy for *mut T {}
// CHECK: define void @f_void() // CHECK: define void @f_void()
#[no_mangle] #[no_mangle]

View File

@ -15,6 +15,7 @@
trait Sized {} trait Sized {}
#[lang = "copy"] #[lang = "copy"]
trait Copy {} trait Copy {}
impl<T: ?Sized> Copy for &T {}
#[lang = "receiver"] #[lang = "receiver"]
trait Receiver {} trait Receiver {}
#[lang = "dispatch_from_dyn"] #[lang = "dispatch_from_dyn"]

View File

@ -1,20 +0,0 @@
// Avoid panicking if the Clone trait is not found while building error suggestions
// See #104870
#![feature(no_core, lang_items)]
#![no_core]
#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}
fn g<T>(x: T) {}
fn f(x: *mut u8) {
g(x);
g(x); //~ ERROR use of moved value: `x`
}
fn main() {}

View File

@ -1,21 +0,0 @@
error[E0382]: use of moved value: `x`
--> $DIR/missing-clone-for-suggestion.rs:17:7
|
LL | fn f(x: *mut u8) {
| - move occurs because `x` has type `*mut u8`, which does not implement the `Copy` trait
LL | g(x);
| - value moved here
LL | g(x);
| ^ value used here after move
|
note: consider changing this parameter type in function `g` to borrow instead if owning the value isn't necessary
--> $DIR/missing-clone-for-suggestion.rs:13:12
|
LL | fn g<T>(x: T) {}
| - ^ this parameter takes ownership of the value
| |
| in this function
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0382`.