rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.11k stars 12.69k forks source link

HRTB prevent mem::transmute and mem::MaybeUninit from working #62201

Open SeeSpring opened 5 years ago

SeeSpring commented 5 years ago

The following code prevents mem::MaybeUninit and mem::transmute from creating values.

trait Ty<'a> {
    type V;
}

trait SIter: for<'a> Ty<'a> {
    fn f<F>(&self, f: F)
    where
        F: for<'r> Fn(<Self as Ty<'r>>::V);
}

struct S<I>(I);

impl<'a, I: Ty<'a>> Ty<'a> for S<I> {
    type V = <I as Ty<'a>>::V;
}

trait Is<'a> {
    type V;
}

impl<'a, T> Is<'a> for T {
    type V = T;
}

impl<I: SIter, Item> SIter for S<I>
where
    // for<'r> Self: Ty<'r, V = <I as Ty<'r>>::V>,
    for<'r> S<I>: Ty<'r, V = Item>,
    for<'r> I: Ty<'r, V = Item>,
    // for<'r> <Self as Ty<'r>>::V: Is<'r, V = <I as Ty<'r>>::V>,
{
    fn f<F>(&self, f: F)
    where
        F: Fn(<Self as Ty>::V),
    {
        self.0.f(|item| unsafe {
            // let item: <Self as Ty>::V = std::mem::transmute_copy(&item);
            let item: <Self as Ty>::V = std::mem::MaybeUninit::uninit().assume_init();
            // let item: <Self as Ty>::V = loop {};
            f(item)
        })
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/lib.rs:40:15
   |
40 |             f(item)
   |               ^^^^ expected associated type, found type parameter
   |
   = note: expected type `<S<I> as Ty<'_>>::V`
              found type `Item`

error[E0277]: expected a `std::ops::Fn<(Item,)>` closure, found `F`
  --> src/lib.rs:40:13
   |
40 |             f(item)
   |             ^^^^^^^ expected an `Fn<(Item,)>` closure, found `F`
   |
   = help: the trait `std::ops::Fn<(Item,)>` is not implemented for `F`
   = help: consider adding a `where F: std::ops::Fn<(Item,)>` bound

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: Could not compile `playground`.

To learn more, run the command again with --verbose.

The code works fine without any unsafe if I remove all lifetimes from it.

trait Ty {
    type V;
}

trait SIter: Ty {
    fn f<F>(&self, f: F)
    where
        F: Fn(<Self as Ty>::V);
}

struct S<I>(I);

impl<I: Ty> Ty for S<I> {
    type V = <I as Ty>::V;
}

// trait Is<'a> {
//     type V;
// }

// impl<'a, T> Is<'a> for T {
//     type V = T;
// }

impl<I: SIter> SIter for S<I>
where
    // for<'r> Self: Ty<'r, V = <I as Ty<'r>>::V>,
    // for<'r> S<I>: Ty<'r, V = Item>,
    // for<'r> I: Ty<'r, V = Item>,
    // for<'r> <Self as Ty<'r>>::V: Is<'r, V = <I as Ty<'r>>::V>,
{
    fn f<F>(&self, f: F)
    where
        F: Fn(<Self as Ty>::V),
    {
        self.0.f(|item| unsafe {
            // let item: <Self as Ty>::V = std::mem::transmute_copy(&item);
            // let item: <Self as Ty>::V = std::mem::MaybeUninit::uninit().assume_init();
            // let item: <Self as Ty>::V = loop {};
            f(item)
        })
    }
}

(Playground)

SeeSpring commented 5 years ago

As a workaround, make a helper function to coerce the types

fn help<'a, T: Ty<'a>, F>(f: &F, t: <T as Ty<'a>>::V)
where
    F: Fn(<T as Ty>::V),
{
    f(t)
}

and swap

f(item)

for

help(&f,item)
SeeSpring commented 4 years ago

Actually attempting to use this causes an ICE

trait Ty<'a> {
    type V;
}

trait SIter: for<'a> Ty<'a> {
    fn f<F>(&self, f: F)
    where
        F: for<'r> Fn(<Self as Ty<'r>>::V);
}

struct S<I>(I);

impl<'a, I: Ty<'a>> Ty<'a> for S<I> {
    type V = <I as Ty<'a>>::V;
}

impl<I: SIter, Item> SIter for S<I>
where
    for<'r> S<I>: Ty<'r, V = Item>,
    for<'r> I: Ty<'r, V = Item>,
{
    fn f<F>(&self, f: F)
    where
        F: Fn(<Self as Ty>::V),
    {
        self.0.f(|item| help(&f, item))
    }
}

fn help<'a, T: Ty<'a>, F>(f: &F, t: <T as Ty<'a>>::V)
where
    F: Fn(<T as Ty>::V),
{
    f(t)
}

struct AA;
impl<'a> Ty<'a> for AA {
    type V = ();
}
impl SIter for AA {
    fn f<F>(&self, f: F)
    where
        F: for<'r> Fn(<Self as Ty<'r>>::V),
    {
        help(&f, ())
    }
}

fn main() {
    S(AA).f(|_| {})
}
   Compiling playground v0.0.1 (/playground)
error: internal compiler error: src/librustc_infer/traits/codegen/mod.rs:61: Encountered error `OutputTypeParameterMismatch(Binder(<[closure@src/main.rs:26:18: 26:39 f:&[closure@src/main.rs:51:13: 51:19]] as std::ops::Fn<(<AA as Ty<'_>>::V,)>>), Binder(<[closure@src/main.rs:26:18: 26:39 f:&[closure@src/main.rs:51:13: 51:19]] as std::ops::Fn<((),)>>), Sorts(ExpectedFound { expected: (), found: <AA as Ty<'_>>::V }))` selecting `Binder(<[closure@src/main.rs:26:18: 26:39 f:&[closure@src/main.rs:51:13: 51:19]] as std::ops::Fn<((),)>>)` during codegen

thread 'rustc' panicked at 'Box<Any>', src/librustc_errors/lib.rs:875:9
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/libunwind.rs:86
   1: backtrace::backtrace::trace_unsynchronized
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:78
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:59
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1063
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1428
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:62
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:49
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:204
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:224
  10: rustc_driver::report_ice
  11: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:474
  12: std::panicking::begin_panic
  13: rustc_errors::HandlerInner::bug
  14: rustc_errors::Handler::bug
  15: rustc::util::bug::opt_span_bug_fmt::{{closure}}
  16: rustc::ty::context::tls::with_opt::{{closure}}
  17: rustc::ty::context::tls::with_opt
  18: rustc::util::bug::opt_span_bug_fmt
  19: rustc::util::bug::bug_fmt
  20: rustc::ty::context::GlobalCtxt::enter_local
  21: rustc_infer::traits::codegen::codegen_fulfill_obligation
  22: rustc::ty::query::__query_compute::codegen_fulfill_obligation
  23: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::codegen_fulfill_obligation>::compute
  24: rustc::dep_graph::graph::DepGraph::with_task_impl
  25: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  26: rustc_ty::instance::resolve_instance
  27: rustc::ty::instance::Instance::resolve
  28: <rustc_mir::monomorphize::collector::MirNeighborCollector as rustc::mir::visit::Visitor>::visit_terminator_kind
  29: rustc_mir::monomorphize::collector::collect_items_rec
  30: rustc_mir::monomorphize::collector::collect_items_rec
  31: rustc_mir::monomorphize::collector::collect_items_rec
  32: rustc_mir::monomorphize::collector::collect_items_rec
  33: rustc_session::utils::<impl rustc_session::session::Session>::time
  34: rustc_mir::monomorphize::collector::collect_crate_mono_items
  35: rustc_mir::monomorphize::partitioning::collect_and_partition_mono_items
  36: rustc::ty::query::__query_compute::collect_and_partition_mono_items
  37: rustc::dep_graph::graph::DepGraph::with_task_impl
  38: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  39: rustc_codegen_ssa::base::codegen_crate
  40: <rustc_codegen_llvm::LlvmCodegenBackend as rustc_codegen_utils::codegen_backend::CodegenBackend>::codegen_crate
  41: rustc_interface::passes::start_codegen
  42: rustc::ty::context::tls::enter_global
  43: rustc_interface::queries::Queries::ongoing_codegen
  44: rustc_interface::interface::run_compiler_in_existing_thread_pool
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.43.0-nightly (3dbade652 2020-03-09) running on x86_64-unknown-linux-gnu

note: compiler flags: -C codegen-units=1 -C debuginfo=2 --crate-type bin

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
#0 [codegen_fulfill_obligation] checking if `std::ops::Fn` fulfills its obligations
#1 [collect_and_partition_mono_items] collect_and_partition_mono_items
end of query stack
error: aborting due to previous error

error: could not compile `playground`.

To learn more, run the command again with --verbose.

Playground

SkiFire13 commented 1 year ago

The original code seems to compile fine now.