Skip to content
4 changes: 0 additions & 4 deletions compiler/rustc_builtin_macros/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,6 @@ builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a l
builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified
builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified

builtin_macros_coerce_pointee_requires_maybe_sized = `derive(CoercePointee)` requires `{$name}` to be marked `?Sized`

builtin_macros_coerce_pointee_requires_one_field = `CoercePointee` can only be derived on `struct`s with at least one field

builtin_macros_coerce_pointee_requires_one_generic = `CoercePointee` can only be derived on `struct`s that are generic over at least one type

builtin_macros_coerce_pointee_requires_one_pointee = exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits
Expand Down
119 changes: 72 additions & 47 deletions compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
TraitBoundModifiers, VariantData, WherePredicate,
self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind, MetaItem,
TraitBoundModifiers, TyAlias, 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};
Expand All @@ -30,25 +30,8 @@ pub(crate) fn expand_deriving_coerce_pointee(
item.visit_with(&mut DetectNonGenericPointeeAttr { cx });

let (name_ident, generics) = if let Annotatable::Item(aitem) = item
&& let ItemKind::Struct(struct_data, g) = &aitem.kind
&& 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, _)
if !fields.is_empty())
{
cx.dcx().emit_err(RequireOneField { span });
return;
}
(aitem.ident, g)
} else {
cx.dcx().emit_err(RequireTransparent { span });
Expand Down Expand Up @@ -88,8 +71,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, _) => {
Expand All @@ -102,6 +84,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
}
}
};
let pointee_ty_ident = generics.params[pointee_param_idx].ident;

// Create the type of `self`.
let path = cx.path_all(span, false, vec![name_ident], self_params.clone());
Expand All @@ -110,6 +93,67 @@ 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
// This 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);
let pointee_assoc_item = cx.assoc_item(
span,
Ident::new(sym::Pointee, span),
thin_vec![],
ast::AssocItemKind::Type(Box::new(TyAlias {
defaultness: ast::Defaultness::Final,
generics: ast::Generics::default(),
where_clauses: ast::TyAliasWhereClauses::default(),
bounds: vec![],
ty: Some(
cx.ty(span, ast::TyKind::Path(None, cx.path_ident(span, pointee_ty_ident))),
),
})),
);
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: thin_vec![pointee_assoc_item],
})),
),
));
}
let mut add_impl_block = |generics, trait_symbol, trait_args| {
let mut parts = path!(span, core::ops);
parts.push(Ident::new(trait_symbol, span));
Expand Down Expand Up @@ -144,7 +188,6 @@ pub(crate) fn expand_deriving_coerce_pointee(
//
// Find the `#[pointee]` parameter and add an `Unsize<__S>` bound to it.
let mut impl_generics = generics.clone();
let pointee_ty_ident = generics.params[pointee_param_idx].ident;
let mut self_bounds;
{
let pointee = &mut impl_generics.params[pointee_param_idx];
Expand All @@ -155,10 +198,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
pointee_ty_ident.name,
)
{
cx.dcx().emit_err(RequiresMaybeSized {
span: pointee_ty_ident.span,
name: pointee_ty_ident,
});
cx.dcx().span_delayed_bug(pointee_ty_ident.span, "?Sized should be checked");
return;
}
let arg = GenericArg::Type(s_ty.clone());
Expand Down Expand Up @@ -430,46 +470,31 @@ 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)]
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,
#[label]
another: Span,
}

#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_maybe_sized)]
struct RequiresMaybeSized {
#[primary_span]
span: Span,
name: Ident,
}
7 changes: 7 additions & 0 deletions compiler/rustc_codegen_cranelift/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ pub trait Unsize<T: ?Sized> {}
#[lang = "coerce_unsized"]
pub trait CoerceUnsized<T> {}

#[lang = "coerce_pointee_validated"]
pub trait CoercePointeeValidated {
/* compiler built-in */
#[lang = "coerce_pointee_validated_pointee"]
type Pointee: ?Sized;
}

impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
Expand Down
53 changes: 39 additions & 14 deletions compiler/rustc_codegen_gcc/example/mini_core.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
#![feature(
no_core, lang_items, intrinsics, unboxed_closures, extern_types,
decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls,
no_core,
lang_items,
intrinsics,
unboxed_closures,
extern_types,
decl_macro,
rustc_attrs,
transparent_unions,
auto_traits,
freeze_impls,
thread_local
)]
#![no_core]
Expand All @@ -26,6 +34,13 @@ pub trait Unsize<T: ?Sized> {}
#[lang = "coerce_unsized"]
pub trait CoerceUnsized<T> {}

#[lang = "coerce_pointee_validated"]
pub trait CoercePointeeValidated {
/* compiler built-in */
#[lang = "coerce_pointee_validated_pointee"]
type Pointee: ?Sized;
}

impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
Expand All @@ -35,13 +50,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
pub trait DispatchFromDyn<T> {}

// &T -> &U
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
// &mut T -> &mut U
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
// *const T -> *const U
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
// *mut T -> *mut U
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}

#[lang = "legacy_receiver"]
Expand Down Expand Up @@ -289,7 +304,6 @@ impl PartialEq for u32 {
}
}


impl PartialEq for u64 {
fn eq(&self, other: &u64) -> bool {
(*self) == (*other)
Expand Down Expand Up @@ -476,7 +490,11 @@ fn panic_in_cleanup() -> ! {
#[track_caller]
fn panic_bounds_check(index: usize, len: usize) -> ! {
unsafe {
libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
libc::printf(
"index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8,
len,
index,
);
intrinsics::abort();
}
}
Expand Down Expand Up @@ -504,8 +522,7 @@ pub trait Deref {
fn deref(&self) -> &Self::Target;
}

pub trait Allocator {
}
pub trait Allocator {}

impl Allocator for () {}

Expand Down Expand Up @@ -699,19 +716,27 @@ pub struct VaList<'a>(&'a mut VaListImpl);

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro stringify($($t:tt)*) { /* compiler built-in */ }
pub macro stringify($($t:tt)*) {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro file() { /* compiler built-in */ }
pub macro file() {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro line() { /* compiler built-in */ }
pub macro line() {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro cfg() { /* compiler built-in */ }
pub macro cfg() {
/* compiler built-in */
}

pub static A_STATIC: u8 = 42;

Expand Down
Loading
Loading