Skip to content

Commit

Permalink
Merge pull request #36 from dtolnay/currentcrate
Browse files Browse the repository at this point in the history
Enforce ref_cast_custom used from same crate as corresponding RefCastCustom
  • Loading branch information
dtolnay committed Oct 12, 2022
2 parents f54c978 + f119772 commit 92a4623
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 6 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Expand Up @@ -14,11 +14,12 @@ rust-version = "1.31"
ref-cast-impl = { version = "=1.0.11", path = "derive" }

[dev-dependencies]
ref-cast-test-suite = { version = "0", path = "tests/helper" }
rustversion = "1.0"
trybuild = { version = "1.0.52", features = ["diff"] }

[workspace]
members = ["derive"]
members = ["derive", "tests/helper"]

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
Expand Down
18 changes: 15 additions & 3 deletions derive/src/lib.rs
Expand Up @@ -279,6 +279,7 @@ fn expand_ref_cast(input: DeriveInput) -> Result<TokenStream2> {
fn expand_ref_cast_custom(input: DeriveInput) -> Result<TokenStream2> {
check_repr(&input)?;

let vis = &input.vis;
let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

Expand All @@ -301,9 +302,15 @@ fn expand_ref_cast_custom(input: DeriveInput) -> Result<TokenStream2> {
};

Ok(quote! {
unsafe impl #impl_generics ::ref_cast::__private::RefCastCustom<#from> for #name #ty_generics #where_clause {
#assert_trivial_fields
}
const _: () = {
#[non_exhaustive]
#vis struct RefCastCurrentCrate {}

unsafe impl #impl_generics ::ref_cast::__private::RefCastCustom<#from> for #name #ty_generics #where_clause {
type CurrentCrate = RefCastCurrentCrate;
#assert_trivial_fields
}
};
})
}

Expand Down Expand Up @@ -335,9 +342,14 @@ fn expand_function_body(function: Function) -> TokenStream2 {
#(#attrs)*
#vis #constness #asyncness #unsafety #abi
#fn_token #ident #generics #args #arrow_token #to_type {
// check lifetime
let _ = || {
::ref_cast::__private::ref_cast_custom::<#from_type, #to_type>(#arg);
};

// check same crate
let _ = ::ref_cast::__private::CurrentCrate::<#from_type, #to_type> {};

unsafe {
::ref_cast::__private::transmute::<#from_type, #to_type>(#arg)
}
Expand Down
28 changes: 27 additions & 1 deletion src/custom.rs
@@ -1,25 +1,51 @@
// Not public API. Use #[derive(RefCastCustom)] and #[ref_cast_custom].
#[doc(hidden)]
pub unsafe trait RefCastCustom<From: ?Sized> {
type CurrentCrate;
fn __static_assert() {}
}

pub unsafe trait RefCastOkay<From> {}
pub unsafe trait RefCastOkay<From>: Sealed<From> {
type CurrentCrate;
type Target: ?Sized;
}

unsafe impl<'a, From, To> RefCastOkay<&'a From> for &'a To
where
From: ?Sized,
To: ?Sized + RefCastCustom<From>,
{
type CurrentCrate = To::CurrentCrate;
type Target = To;
}

unsafe impl<'a, From, To> RefCastOkay<&'a mut From> for &'a mut To
where
From: ?Sized,
To: ?Sized + RefCastCustom<From>,
{
type CurrentCrate = To::CurrentCrate;
type Target = To;
}

pub trait Sealed<From> {}

impl<'a, From, To> Sealed<&'a From> for &'a To
where
From: ?Sized,
To: ?Sized + RefCastCustom<From>,
{
}

impl<'a, From, To> Sealed<&'a mut From> for &'a mut To
where
From: ?Sized,
To: ?Sized + RefCastCustom<From>,
{
}

pub type CurrentCrate<From, To> = <To as RefCastOkay<From>>::CurrentCrate;

pub fn ref_cast_custom<From, To>(_arg: From)
where
To: RefCastOkay<From>,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Expand Up @@ -180,7 +180,7 @@ pub trait RefCast {
// Not public API.
#[doc(hidden)]
pub mod __private {
pub use crate::custom::{ref_cast_custom, RefCastCustom};
pub use crate::custom::{ref_cast_custom, CurrentCrate, RefCastCustom};
pub use crate::layout::{assert_layout, Layout, LayoutUnsized};
pub use crate::trivial::assert_trivial;
pub use core::mem::transmute;
Expand Down
12 changes: 12 additions & 0 deletions tests/helper/Cargo.toml
@@ -0,0 +1,12 @@
[package]
name = "ref-cast-test-suite"
authors = ["David Tolnay <dtolnay@gmail.com>"]
version = "0.0.0"
edition = "2018"
publish = false

[lib]
path = "lib.rs"

[dependencies]
ref-cast = "1"
5 changes: 5 additions & 0 deletions tests/helper/lib.rs
@@ -0,0 +1,5 @@
use ref_cast::RefCastCustom;

#[derive(RefCastCustom)]
#[repr(transparent)]
pub struct Struct(str);
10 changes: 10 additions & 0 deletions tests/ui/cross-crate.rs
@@ -0,0 +1,10 @@
use ref_cast::ref_cast_custom;
use ref_cast_test_suite::Struct;

#[ref_cast_custom]
fn ref_cast(s: &str) -> &Struct;

#[ref_cast_custom]
fn ref_cast_mut(s: &mut str) -> &mut Struct;

fn main() {}
11 changes: 11 additions & 0 deletions tests/ui/cross-crate.stderr
@@ -0,0 +1,11 @@
error[E0639]: cannot create non-exhaustive struct using struct expression
--> tests/ui/cross-crate.rs:5:32
|
5 | fn ref_cast(s: &str) -> &Struct;
| ^

error[E0639]: cannot create non-exhaustive struct using struct expression
--> tests/ui/cross-crate.rs:8:44
|
8 | fn ref_cast_mut(s: &mut str) -> &mut Struct;
| ^
17 changes: 17 additions & 0 deletions tests/ui/no-custom.stderr
Expand Up @@ -13,3 +13,20 @@ note: required by a bound in `ref_cast_custom`
|
| To: RefCastOkay<From>,
| ^^^^^^^^^^^^^^^^^ required by this bound in `ref_cast_custom`

error[E0071]: expected struct, variant or union type, found inferred type
--> tests/ui/no-custom.rs:8:41
|
8 | pub fn ref_cast(s: &String) -> &Self;
| ^ not a struct

error[E0277]: the trait bound `Thing: RefCastCustom<String>` is not satisfied
--> tests/ui/no-custom.rs:8:41
|
8 | pub fn ref_cast(s: &String) -> &Self;
| ^ the trait `RefCastCustom<String>` is not implemented for `Thing`
|
= help: the following other types implement trait `ref_cast::custom::RefCastOkay<From>`:
<&'a To as ref_cast::custom::RefCastOkay<&'a From>>
<&'a mut To as ref_cast::custom::RefCastOkay<&'a mut From>>
= note: required for `&Thing` to implement `ref_cast::custom::RefCastOkay<&String>`

0 comments on commit 92a4623

Please sign in to comment.