Rollup merge of #136107 - dingxiangfei2009:coerce-pointee-wellformed, r=compiler-errors
Introduce CoercePointeeWellformed for coherence checks at typeck stage Fix #135206 This is the first PR to introduce the "wellformedness" check for `derive(CoercePointee)`. This patch introduces a new error code to cover all the prerequisites of the said macro. The checks that is enforced with this patch is whether the data is indeed `struct` and whether the layout is set to `repr(transparent)`. A following series of patch will arrive later to address the following concern. 1. #135217 so that we would only admit one single coercion on one type parameter, and leave the rest for future consideration in tandem of development of other coercion rules. 1. Enforcement of data field requirements. **An open question** is whether there is a good schema to encode the `#[pointee]` as well, so that we could also check if the `#[pointee]` type parameter is indeed `?Sized`. ``@rustbot`` label F-derive_coerce_pointee
This commit is contained in:
commit
af3c51d849
15 changed files with 385 additions and 54 deletions
|
@ -3,11 +3,11 @@ 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};
|
||||
|
@ -32,15 +32,6 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
let (name_ident, generics) = if let Annotatable::Item(aitem) = item
|
||||
&& let ItemKind::Struct(struct_data, g) = &aitem.kind
|
||||
{
|
||||
let is_transparent = aitem.attrs.iter().any(|attr| {
|
||||
attr::find_repr_attrs(cx.sess, attr)
|
||||
.into_iter()
|
||||
.any(|r| matches!(r, attr::ReprTransparent))
|
||||
});
|
||||
if !is_transparent {
|
||||
cx.dcx().emit_err(RequireTransparent { span });
|
||||
return;
|
||||
}
|
||||
if !matches!(
|
||||
struct_data,
|
||||
VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _)
|
||||
|
@ -88,8 +79,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 +100,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),];
|
||||
// # Validity assertion which will be checked later in `rustc_hir_analysis::coherence::builtins`.
|
||||
{
|
||||
let trait_path =
|
||||
cx.path_all(span, true, path!(span, core::marker::CoercePointeeValidated), 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 +466,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 +503,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,
|
||||
|
|
94
compiler/rustc_error_codes/src/error_codes/E0802.md
Normal file
94
compiler/rustc_error_codes/src/error_codes/E0802.md
Normal file
|
@ -0,0 +1,94 @@
|
|||
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
|
||||
#![feature(coerce_pointee)]
|
||||
use std::marker::CoercePointee;
|
||||
#[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
|
||||
#![feature(coerce_pointee)]
|
||||
use std::marker::CoercePointee;
|
||||
#[derive(CoercePointee)]
|
||||
struct NotTransparent<'a, #[pointee] T: ?Sized> {
|
||||
ptr: &'a T,
|
||||
}
|
||||
```
|
||||
|
||||
The target data has no data field.
|
||||
|
||||
```compile_fail,E0802
|
||||
#![feature(coerce_pointee)]
|
||||
use std::marker::CoercePointee;
|
||||
#[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
|
||||
#![feature(coerce_pointee)]
|
||||
use std::marker::CoercePointee;
|
||||
#[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
|
||||
#![feature(coerce_pointee)]
|
||||
use std::marker::CoercePointee;
|
||||
#[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
|
||||
#![feature(coerce_pointee)]
|
||||
use std::marker::CoercePointee;
|
||||
#[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
|
||||
#![feature(coerce_pointee)]
|
||||
use std::marker::CoercePointee;
|
||||
#[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`.
|
|
@ -545,6 +545,7 @@ E0798: 0798,
|
|||
E0799: 0799,
|
||||
E0800: 0800,
|
||||
E0801: 0801,
|
||||
E0802: 0802,
|
||||
);
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
@ -370,6 +370,8 @@ language_item_table! {
|
|||
|
||||
PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0);
|
||||
|
||||
CoercePointeeValidated, sym::coerce_pointee_validated, coerce_pointee_validated_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),
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,16 @@ 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_no_field = `CoercePointee` can only be derived on `struct`s with at least one field
|
||||
|
||||
hir_analysis_coerce_pointee_no_user_validity_assertion = asserting applicability of `derive(CoercePointee)` on a target data is forbidden
|
||||
|
||||
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
|
||||
|
|
|
@ -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_validated_trait(),
|
||||
visit_implementation_of_coerce_pointee_validity,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -783,3 +787,32 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
|
|||
.with_note(why_disqualified)
|
||||
.emit())
|
||||
}
|
||||
|
||||
fn visit_implementation_of_coerce_pointee_validity(
|
||||
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 span = tcx.def_span(checker.impl_def_id);
|
||||
if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
|
||||
return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
|
||||
}
|
||||
let ty::Adt(def, _args) = self_ty.kind() else {
|
||||
return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));
|
||||
};
|
||||
let did = def.did();
|
||||
// Now get a more precise span of the `struct`.
|
||||
let span = 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 }));
|
||||
}
|
||||
if def.all_fields().next().is_none() {
|
||||
return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span }));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1180,6 +1180,42 @@ 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_no_user_validity_assertion, code = E0802)]
|
||||
pub(crate) struct CoercePointeeNoUserValidityAssertion {
|
||||
#[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_coerce_pointee_no_field, code = E0802)]
|
||||
pub(crate) struct CoercePointeeNoField {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_inherent_ty_outside_relevant, code = E0390)]
|
||||
#[help]
|
||||
|
|
|
@ -193,6 +193,7 @@ symbols! {
|
|||
Cleanup,
|
||||
Clone,
|
||||
CoercePointee,
|
||||
CoercePointeeValidated,
|
||||
CoerceUnsized,
|
||||
Command,
|
||||
ConstParamTy,
|
||||
|
@ -619,6 +620,7 @@ symbols! {
|
|||
cmp_partialord_lt,
|
||||
cmpxchg16b_target_feature,
|
||||
cmse_nonsecure_entry,
|
||||
coerce_pointee_validated,
|
||||
coerce_unsized,
|
||||
cold,
|
||||
cold_path,
|
||||
|
|
|
@ -1284,8 +1284,22 @@ pub trait FnPtr: Copy + Clone {
|
|||
/// }
|
||||
/// ```
|
||||
#[rustc_builtin_macro(CoercePointee, attributes(pointee))]
|
||||
#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)]
|
||||
#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize, coerce_pointee_validated)]
|
||||
#[unstable(feature = "derive_coerce_pointee", issue = "123430")]
|
||||
pub macro CoercePointee($item:item) {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
/// A trait that is implemented for ADTs with `derive(CoercePointee)` so that
|
||||
/// the compiler can enforce the derive impls are valid post-expansion, since
|
||||
/// the derive has stricter requirements than if the impls were written by hand.
|
||||
///
|
||||
/// This trait is not intended to be implemented by users or used other than
|
||||
/// validation, so it should never be stabilized.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[lang = "coerce_pointee_validated"]
|
||||
#[unstable(feature = "coerce_pointee_validated", issue = "none")]
|
||||
#[doc(hidden)]
|
||||
pub trait CoercePointeeValidated {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
|
31
tests/ui/deriving/auxiliary/malicious-macro.rs
Normal file
31
tests/ui/deriving/auxiliary/malicious-macro.rs
Normal 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()
|
||||
}
|
|
@ -20,6 +20,8 @@ pub struct Ptr<'a, #[pointee] T: ?Sized> {
|
|||
data: &'a mut T,
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl<'a, T: ?Sized> ::core::marker::CoercePointeeValidated 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> {
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@ struct MyPointer<'a, #[pointee] T: ?Sized> {
|
|||
ptr: &'a T,
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl<'a, T: ?Sized> ::core::marker::CoercePointeeValidated 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::CoercePointeeValidated 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::CoercePointeeValidated 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> {
|
||||
|
|
|
@ -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)]
|
||||
|
@ -41,8 +44,8 @@ struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &
|
|||
//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits
|
||||
|
||||
#[derive(CoercePointee)]
|
||||
//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
|
||||
struct NotTransparent<'a, #[pointee] T: ?Sized> {
|
||||
//~^ ERROR: `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout
|
||||
ptr: &'a T,
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
||||
|
|
|
@ -1,89 +1,81 @@
|
|||
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
|
||||
|
|
||||
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 +83,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 +91,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 +99,26 @@ 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:47:1
|
||||
|
|
||||
LL | struct NotTransparent<'a, #[pointee] T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For more information about this error, try `rustc --explain E0392`.
|
||||
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> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0392, E0802.
|
||||
For more information about an error, try `rustc --explain E0392`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue