1
Fork 0

introduce CoercePointeeWellformed for coherence checks at typeck stage

This commit is contained in:
Ding Xiang Fei 2025-01-27 06:06:06 +08:00
parent 43ca9d18e3
commit de405dcb8f
No known key found for this signature in database
GPG key ID: 3CD748647EEF6359
15 changed files with 337 additions and 36 deletions

View file

@ -3,11 +3,12 @@ use ast::ptr::P;
use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::visit::BoundKind;
use rustc_ast::{
self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem,
self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind, MetaItem,
TraitBoundModifiers, VariantData, WherePredicate,
};
use rustc_attr_parsing as attr;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_errors::E0802;
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_macros::Diagnostic;
use rustc_span::{Ident, Span, Symbol, sym};
@ -88,8 +89,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
} else {
let mut pointees = type_params
.iter()
.filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span)))
.fuse();
.filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span)));
match (pointees.next(), pointees.next()) {
(Some((idx, _span)), None) => idx,
(None, _) => {
@ -110,6 +110,52 @@ pub(crate) fn expand_deriving_coerce_pointee(
// Declare helper function that adds implementation blocks.
// FIXME(dingxiangfei2009): Investigate the set of attributes on target struct to be propagated to impls
let attrs = thin_vec![cx.attr_word(sym::automatically_derived, span),];
// # Wellformed-ness assertion
{
let trait_path =
cx.path_all(span, true, path!(span, core::marker::CoercePointeeWellformed), vec![]);
let trait_ref = cx.trait_ref(trait_path);
push(Annotatable::Item(
cx.item(
span,
Ident::empty(),
attrs.clone(),
ast::ItemKind::Impl(Box::new(ast::Impl {
safety: ast::Safety::Default,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: ast::Const::No,
generics: Generics {
params: generics
.params
.iter()
.map(|p| match &p.kind {
GenericParamKind::Lifetime => {
cx.lifetime_param(p.span(), p.ident, p.bounds.clone())
}
GenericParamKind::Type { default: _ } => {
cx.typaram(p.span(), p.ident, p.bounds.clone(), None)
}
GenericParamKind::Const { ty, kw_span: _, default: _ } => cx
.const_param(
p.span(),
p.ident,
p.bounds.clone(),
ty.clone(),
None,
),
})
.collect(),
where_clause: generics.where_clause.clone(),
span: generics.span,
},
of_trait: Some(trait_ref),
self_ty: self_type.clone(),
items: ThinVec::new(),
})),
),
));
}
let mut add_impl_block = |generics, trait_symbol, trait_args| {
let mut parts = path!(span, core::ops);
parts.push(Ident::new(trait_symbol, span));
@ -430,35 +476,35 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b>
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_transparent)]
#[diag(builtin_macros_coerce_pointee_requires_transparent, code = E0802)]
struct RequireTransparent {
#[primary_span]
span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_one_field)]
#[diag(builtin_macros_coerce_pointee_requires_one_field, code = E0802)]
struct RequireOneField {
#[primary_span]
span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_one_generic)]
#[diag(builtin_macros_coerce_pointee_requires_one_generic, code = E0802)]
struct RequireOneGeneric {
#[primary_span]
span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_one_pointee)]
#[diag(builtin_macros_coerce_pointee_requires_one_pointee, code = E0802)]
struct RequireOnePointee {
#[primary_span]
span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_too_many_pointees)]
#[diag(builtin_macros_coerce_pointee_too_many_pointees, code = E0802)]
struct TooManyPointees {
#[primary_span]
one: Span,
@ -467,7 +513,7 @@ struct TooManyPointees {
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_maybe_sized)]
#[diag(builtin_macros_coerce_pointee_requires_maybe_sized, code = E0802)]
struct RequiresMaybeSized {
#[primary_span]
span: Span,

View file

@ -0,0 +1,80 @@
The target of `derive(CoercePointee)` macro has inadmissible specification for
a meaningful use.
Erroneous code examples:
The target data is not a `struct`.
```compile_fail,E0802
#[derive(CoercePointee)]
enum NotStruct<'a, T: ?Sized> {
Variant(&'a T),
}
```
The target data has a layout that is not transparent, or `repr(transparent)`
in other words.
```compile_fail,E0802
#[derive(CoercePointee)]
struct NotTransparent<'a, #[pointee] T: ?Sized> {
ptr: &'a T,
}
```
The target data has no data field.
```compile_fail,E0802
#[derive(CoercePointee)]
#[repr(transparent)]
struct NoField<'a, #[pointee] T: ?Sized> {}
```
The target data is not generic over any data, or has no generic type parameter.
```compile_fail,E0802
#[derive(CoercePointee)]
#[repr(transparent)]
struct NoGeneric<'a>(&'a u8);
```
The target data has multiple generic type parameters, but none is designated as
a pointee for coercion.
```compile_fail,E0802
#[derive(CoercePointee)]
#[repr(transparent)]
struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> {
a: (&'a T1, &'a T2),
}
```
The target data has multiple generic type parameters that are designated as
pointees for coercion.
```compile_fail,E0802
#[derive(CoercePointee)]
#[repr(transparent)]
struct TooManyPointees<
'a,
#[pointee] A: ?Sized,
#[pointee] B: ?Sized>
((&'a A, &'a B));
```
The type parameter that is designated as a pointee is not marked `?Sized`.
```compile_fail,E0802
#[derive(CoercePointee)]
#[repr(transparent)]
struct NoMaybeSized<'a, #[pointee] T> {
ptr: &'a T,
}
```
In summary, the `CoercePointee` macro demands the type to be a `struct` that is
generic over at least one type or over more types, one of which is marked with
`#[pointee]`, and has at least one data field and adopts a `repr(transparent)`
layout.
The only generic type or the type marked with `#[pointee]` has to be also
marked as `?Sized`.

View file

@ -545,6 +545,7 @@ E0798: 0798,
E0799: 0799,
E0800: 0800,
E0801: 0801,
E0802: 0802,
);
)
}

View file

@ -1,7 +1,8 @@
use rustc_ast::ptr::P;
use rustc_ast::util::literal;
use rustc_ast::{
self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp, attr, token,
self as ast, AnonConst, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp,
attr, token,
};
use rustc_span::source_map::Spanned;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
@ -138,6 +139,42 @@ impl<'a> ExtCtxt<'a> {
}
}
pub fn lifetime_param(
&self,
span: Span,
ident: Ident,
bounds: ast::GenericBounds,
) -> ast::GenericParam {
ast::GenericParam {
id: ast::DUMMY_NODE_ID,
ident: ident.with_span_pos(span),
attrs: AttrVec::new(),
bounds,
is_placeholder: false,
kind: ast::GenericParamKind::Lifetime,
colon_span: None,
}
}
pub fn const_param(
&self,
span: Span,
ident: Ident,
bounds: ast::GenericBounds,
ty: P<ast::Ty>,
default: Option<AnonConst>,
) -> ast::GenericParam {
ast::GenericParam {
id: ast::DUMMY_NODE_ID,
ident: ident.with_span_pos(span),
attrs: AttrVec::new(),
bounds,
is_placeholder: false,
kind: ast::GenericParamKind::Const { ty, kw_span: DUMMY_SP, default },
colon_span: None,
}
}
pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef {
ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID }
}

View file

@ -370,6 +370,8 @@ language_item_table! {
PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0);
CoercePointeeWellformed, sym::coerce_pointee_wellformed, coerce_pointee_wellformed_trait, Target::Trait, GenericRequirement::Exact(0);
ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0);
UnsizedConstParamTy, sym::unsized_const_param_ty, unsized_const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0);
@ -429,9 +431,13 @@ language_item_table! {
ContractCheckRequires, sym::contract_check_requires, contract_check_requires_fn, Target::Fn, GenericRequirement::None;
}
/// The requirement imposed on the generics of a lang item
pub enum GenericRequirement {
/// No restriction on the generics
None,
/// A minimum number of generics that is demanded on a lang item
Minimum(usize),
/// The number of generics must match precisely as stipulated
Exact(usize),
}

View file

@ -85,6 +85,12 @@ hir_analysis_cmse_output_stack_spill =
.note1 = functions with the `"{$abi_name}"` ABI must pass their result via the available return registers
.note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
hir_analysis_coerce_pointee_not_concrete_ty = `derive(CoercePointee)` is only applicable to `struct`
hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applicable to `struct`, instead of `{$kind}`
hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout
hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures
hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions

View file

@ -48,6 +48,10 @@ pub(super) fn check_trait<'tcx>(
checker
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
checker.check(
lang_items.coerce_pointee_wellformed_trait(),
visit_implementation_of_coerce_pointee_wellformed,
)?;
Ok(())
}
@ -782,3 +786,27 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
.with_note(why_disqualified)
.emit())
}
fn visit_implementation_of_coerce_pointee_wellformed(
checker: &Checker<'_>,
) -> Result<(), ErrorGuaranteed> {
let tcx = checker.tcx;
let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
let ty::Adt(def, _args) = self_ty.kind() else {
return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType {
span: tcx.def_span(checker.impl_def_id),
}));
};
let did = def.did();
let span =
if let Some(local) = did.as_local() { tcx.source_span(local) } else { tcx.def_span(did) };
if !def.is_struct() {
return Err(tcx
.dcx()
.emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() }));
}
if !def.repr().transparent() {
return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span }));
}
Ok(())
}

View file

@ -1180,6 +1180,28 @@ pub(crate) struct DispatchFromDynRepr {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_coerce_pointee_not_struct, code = E0802)]
pub(crate) struct CoercePointeeNotStruct {
#[primary_span]
pub span: Span,
pub kind: String,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_coerce_pointee_not_concrete_ty, code = E0802)]
pub(crate) struct CoercePointeeNotConcreteType {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_coerce_pointee_not_transparent, code = E0802)]
pub(crate) struct CoercePointeeNotTransparent {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_ty_outside_relevant, code = E0390)]
#[help]

View file

@ -193,6 +193,7 @@ symbols! {
Cleanup,
Clone,
CoercePointee,
CoercePointeeWellformed,
CoerceUnsized,
Command,
ConstParamTy,
@ -619,6 +620,7 @@ symbols! {
cmp_partialord_lt,
cmpxchg16b_target_feature,
cmse_nonsecure_entry,
coerce_pointee_wellformed,
coerce_unsized,
cold,
cold_path,

View file

@ -1289,3 +1289,9 @@ pub trait FnPtr: Copy + Clone {
pub macro CoercePointee($item:item) {
/* compiler built-in */
}
#[cfg(not(bootstrap))]
#[lang = "coerce_pointee_wellformed"]
#[unstable(feature = "derive_coerce_pointee", issue = "123430")]
#[doc(hidden)]
pub trait CoercePointeeWellformed {}

View file

@ -0,0 +1,31 @@
#![feature(let_chains)]
extern crate proc_macro;
use proc_macro::{Delimiter, TokenStream, TokenTree};
#[proc_macro_attribute]
pub fn norepr(_: TokenStream, input: TokenStream) -> TokenStream {
let mut tokens = vec![];
let mut tts = input.into_iter().fuse().peekable();
loop {
let Some(token) = tts.next() else { break };
if let TokenTree::Punct(punct) = &token
&& punct.as_char() == '#'
{
if let Some(TokenTree::Group(group)) = tts.peek()
&& let Delimiter::Bracket = group.delimiter()
&& let Some(TokenTree::Ident(ident)) = group.stream().into_iter().next()
&& ident.to_string() == "repr"
{
let _ = tts.next();
// skip '#' and '[repr(..)]
} else {
tokens.push(token);
}
} else {
tokens.push(token);
}
}
tokens.into_iter().collect()
}

View file

@ -20,6 +20,8 @@ pub struct Ptr<'a, #[pointee] T: ?Sized> {
data: &'a mut T,
}
#[automatically_derived]
impl<'a, T: ?Sized> ::core::marker::CoercePointeeWellformed for Ptr<'a, T> { }
#[automatically_derived]
impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized>
::core::ops::DispatchFromDyn<Ptr<'a, __S>> for Ptr<'a, T> {
}

View file

@ -16,6 +16,10 @@ struct MyPointer<'a, #[pointee] T: ?Sized> {
ptr: &'a T,
}
#[automatically_derived]
impl<'a, T: ?Sized> ::core::marker::CoercePointeeWellformed for
MyPointer<'a, T> {
}
#[automatically_derived]
impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized>
::core::ops::DispatchFromDyn<MyPointer<'a, __S>> for MyPointer<'a, T> {
}
@ -31,6 +35,11 @@ pub struct MyPointer2<'a, Y, Z: MyTrait<T>, #[pointee] T: ?Sized + MyTrait<T>,
x: core::marker::PhantomData<X>,
}
#[automatically_derived]
impl<'a, Y, Z: MyTrait<T>, T: ?Sized + MyTrait<T>, X: MyTrait<T>>
::core::marker::CoercePointeeWellformed for MyPointer2<'a, Y, Z, T, X>
where Y: MyTrait<T> {
}
#[automatically_derived]
impl<'a, Y, Z: MyTrait<T> + MyTrait<__S>, T: ?Sized + MyTrait<T> +
::core::marker::Unsize<__S>, __S: ?Sized + MyTrait<__S>, X: MyTrait<T> +
MyTrait<__S>> ::core::ops::DispatchFromDyn<MyPointer2<'a, Y, Z, __S, X>>
@ -48,6 +57,10 @@ struct MyPointerWithoutPointee<'a, T: ?Sized> {
ptr: &'a T,
}
#[automatically_derived]
impl<'a, T: ?Sized> ::core::marker::CoercePointeeWellformed for
MyPointerWithoutPointee<'a, T> {
}
#[automatically_derived]
impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized>
::core::ops::DispatchFromDyn<MyPointerWithoutPointee<'a, __S>> for
MyPointerWithoutPointee<'a, T> {

View file

@ -1,6 +1,9 @@
//@ proc-macro: malicious-macro.rs
#![feature(derive_coerce_pointee, arbitrary_self_types)]
extern crate core;
extern crate malicious_macro;
use std::marker::CoercePointee;
#[derive(CoercePointee)]
@ -131,4 +134,12 @@ struct GlobalCoreSized<'a, #[pointee] T: ?::core::marker::Sized> {
ptr: &'a T,
}
#[derive(CoercePointee)]
#[malicious_macro::norepr]
#[repr(transparent)]
struct TryToWipeRepr<'a, #[pointee] T: ?Sized> {
//~^ ERROR: `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout [E0802]
ptr: &'a T,
}
fn main() {}

View file

@ -1,89 +1,89 @@
error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
--> $DIR/deriving-coerce-pointee-neg.rs:6:10
error[E0802]: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
--> $DIR/deriving-coerce-pointee-neg.rs:9:10
|
LL | #[derive(CoercePointee)]
| ^^^^^^^^^^^^^
|
= note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `CoercePointee` can only be derived on `struct`s with at least one field
--> $DIR/deriving-coerce-pointee-neg.rs:12:10
error[E0802]: `CoercePointee` can only be derived on `struct`s with at least one field
--> $DIR/deriving-coerce-pointee-neg.rs:15:10
|
LL | #[derive(CoercePointee)]
| ^^^^^^^^^^^^^
|
= note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `CoercePointee` can only be derived on `struct`s with at least one field
--> $DIR/deriving-coerce-pointee-neg.rs:19:10
error[E0802]: `CoercePointee` can only be derived on `struct`s with at least one field
--> $DIR/deriving-coerce-pointee-neg.rs:22:10
|
LL | #[derive(CoercePointee)]
| ^^^^^^^^^^^^^
|
= note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `CoercePointee` can only be derived on `struct`s that are generic over at least one type
--> $DIR/deriving-coerce-pointee-neg.rs:26:10
error[E0802]: `CoercePointee` can only be derived on `struct`s that are generic over at least one type
--> $DIR/deriving-coerce-pointee-neg.rs:29:10
|
LL | #[derive(CoercePointee)]
| ^^^^^^^^^^^^^
|
= note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
error: exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits
--> $DIR/deriving-coerce-pointee-neg.rs:31:10
error[E0802]: exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits
--> $DIR/deriving-coerce-pointee-neg.rs:34:10
|
LL | #[derive(CoercePointee)]
| ^^^^^^^^^^^^^
|
= note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
error: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits
--> $DIR/deriving-coerce-pointee-neg.rs:40:39
error[E0802]: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits
--> $DIR/deriving-coerce-pointee-neg.rs:43:39
|
LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
| ^ - here another type parameter is marked as `#[pointee]`
error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
--> $DIR/deriving-coerce-pointee-neg.rs:43:10
error[E0802]: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
--> $DIR/deriving-coerce-pointee-neg.rs:46:10
|
LL | #[derive(CoercePointee)]
| ^^^^^^^^^^^^^
|
= note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `derive(CoercePointee)` requires `T` to be marked `?Sized`
--> $DIR/deriving-coerce-pointee-neg.rs:51:36
error[E0802]: `derive(CoercePointee)` requires `T` to be marked `?Sized`
--> $DIR/deriving-coerce-pointee-neg.rs:54:36
|
LL | struct NoMaybeSized<'a, #[pointee] T> {
| ^
error: the `#[pointee]` attribute may only be used on generic parameters
--> $DIR/deriving-coerce-pointee-neg.rs:59:5
--> $DIR/deriving-coerce-pointee-neg.rs:62:5
|
LL | #[pointee]
| ^^^^^^^^^^
error: the `#[pointee]` attribute may only be used on generic parameters
--> $DIR/deriving-coerce-pointee-neg.rs:69:33
--> $DIR/deriving-coerce-pointee-neg.rs:72:33
|
LL | struct UhOh<#[pointee] T>(T);
| ^^^^^^^^^^
error: the `#[pointee]` attribute may only be used on generic parameters
--> $DIR/deriving-coerce-pointee-neg.rs:83:21
--> $DIR/deriving-coerce-pointee-neg.rs:86:21
|
LL | struct UhOh<#[pointee] T>(T);
| ^^^^^^^^^^
error: the `#[pointee]` attribute may only be used on generic parameters
--> $DIR/deriving-coerce-pointee-neg.rs:98:25
--> $DIR/deriving-coerce-pointee-neg.rs:101:25
|
LL | struct UhOh<#[pointee] T>(T);
| ^^^^^^^^^^
error[E0392]: lifetime parameter `'a` is never used
--> $DIR/deriving-coerce-pointee-neg.rs:15:16
--> $DIR/deriving-coerce-pointee-neg.rs:18:16
|
LL | struct NoField<'a, #[pointee] T: ?Sized> {}
| ^^ unused lifetime parameter
@ -91,7 +91,7 @@ LL | struct NoField<'a, #[pointee] T: ?Sized> {}
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
error[E0392]: type parameter `T` is never used
--> $DIR/deriving-coerce-pointee-neg.rs:15:31
--> $DIR/deriving-coerce-pointee-neg.rs:18:31
|
LL | struct NoField<'a, #[pointee] T: ?Sized> {}
| ^ unused type parameter
@ -99,7 +99,7 @@ LL | struct NoField<'a, #[pointee] T: ?Sized> {}
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
error[E0392]: lifetime parameter `'a` is never used
--> $DIR/deriving-coerce-pointee-neg.rs:22:20
--> $DIR/deriving-coerce-pointee-neg.rs:25:20
|
LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
| ^^ unused lifetime parameter
@ -107,13 +107,23 @@ LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
error[E0392]: type parameter `T` is never used
--> $DIR/deriving-coerce-pointee-neg.rs:22:35
--> $DIR/deriving-coerce-pointee-neg.rs:25:35
|
LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
| ^ unused type parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
error: aborting due to 16 previous errors
error[E0802]: `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout
--> $DIR/deriving-coerce-pointee-neg.rs:140:1
|
LL | / struct TryToWipeRepr<'a, #[pointee] T: ?Sized> {
LL | |
LL | | ptr: &'a T,
LL | | }
| |_^
For more information about this error, try `rustc --explain E0392`.
error: aborting due to 17 previous errors
Some errors have detailed explanations: E0392, E0802.
For more information about an error, try `rustc --explain E0392`.