Skip to content

Commit

Permalink
move maybe sized check into coherence
Browse files Browse the repository at this point in the history
  • Loading branch information
dingxiangfei2009 committed Feb 9, 2025
1 parent e55e437 commit 9aabb55
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 125 deletions.
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
32 changes: 3 additions & 29 deletions compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::visit::BoundKind;
use rustc_ast::{
self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind, MetaItem,
TraitBoundModifiers, TyAlias, VariantData, WherePredicate,
TraitBoundModifiers, TyAlias, WherePredicate,
};
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_errors::E0802;
Expand All @@ -30,16 +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
{
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 @@ -206,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 @@ -487,13 +476,6 @@ struct RequireTransparent {
span: Span,
}

#[derive(Diagnostic)]
#[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, code = E0802)]
struct RequireOneGeneric {
Expand All @@ -516,11 +498,3 @@ struct TooManyPointees {
#[label]
another: Span,
}

#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_maybe_sized, code = E0802)]
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
2 changes: 2 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ 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_missing_maybe_sized = `derive(CoercePointee)` requires the `#[pointee]` to be `?Sized`
hir_analysis_coerce_pointee_multiple_derive = `derive(CoercePointee)` is derived multiple times
.label = another derivation originates from here
Expand Down
109 changes: 76 additions & 33 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,12 +328,19 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
.collect::<Vec<_>>();

if coerced_fields.is_empty() {
// `CoercePointeeValidated` will report a more specific error
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
span,
trait_name: "DispatchFromDyn",
note: true,
}));
if coerce_pointee_data.is_some() {
// `CoercePointeeValidated` will report a more specific error
res = Err(tcx.dcx().span_delayed_bug(
span,
"a more specific error from CoercePointee is expected",
))
} else {
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
span,
trait_name: "DispatchFromDyn",
note: true,
}));
}
} else if coerced_fields.len() > 1 {
if coerce_pointee_data.is_some() {
let spans =
Expand Down Expand Up @@ -405,6 +412,9 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
}
res
}
(&Adt(def, _), _) if tcx.coerce_pointee_data(()).contains_key(&def.did()) => {
Err(tcx.dcx().span_delayed_bug(span, "a specific error for CoercePointee is expected"))
}
_ => Err(tcx
.dcx()
.emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" })),
Expand Down Expand Up @@ -898,23 +908,44 @@ 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()) {
let impl_did = checker.impl_def_id;
let self_ty = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity().self_ty();
let span = tcx.def_span(impl_did);
if !tcx.is_builtin_derived(impl_did.into()) {
return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
}
let ty::Adt(def, _args) = self_ty.kind() else {
let ty::Adt(def, args) = self_ty.kind() else {
return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));
};
let did = def.did();
let Some(info) = tcx.coerce_pointee_data(()).get(&did) else {
return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
};
if let &ty::CoercePointeeInfo::Duplicated { impls } = info {
return Err(tcx.dcx().emit_err(errors::CoercePointeePointeeMultipleDerive {
spans: impls.iter().copied().map(|did| tcx.def_span(did)).collect(),
}));
}
let pointee_idx = match info {
&ty::CoercePointeeInfo::Validated { pointee_index_in_args, .. } => pointee_index_in_args,
ty::CoercePointeeInfo::PointeeUnnormalized { ty, .. } => {
return Err(tcx.dcx().emit_err(errors::CoercePointeePointeeNotGenericPointee {
span,
got: ty.to_string(),
}));
}
ty::CoercePointeeInfo::PointeeIsConst { konst, .. } => {
return Err(tcx.dcx().emit_err(errors::CoercePointeePointeeNotGenericPointee {
span,
got: konst.to_string(),
}));
}
ty::CoercePointeeInfo::Duplicated { impls } => {
return Err(tcx.dcx().emit_err(errors::CoercePointeePointeeMultipleDerive {
spans: impls.iter().copied().map(|did| tcx.def_span(did)).collect(),
}));
}
ty::CoercePointeeInfo::PointeeNotFound { ty, .. } => {
return Err(tcx
.dcx()
.emit_err(errors::CoercePointeeNoPointee { span, ty: ty.to_string() }));
}
};
// Now get a more precise span of the `struct`.
let span = tcx.def_span(did);
if !def.is_struct() {
Expand All @@ -926,8 +957,28 @@ fn visit_implementation_of_coerce_pointee_validity(
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 }));
return Err(tcx.dcx().span_delayed_bug(
span,
"a specific error from CoercePointee is expected in CoerceUnsized coherence check",
));
}

let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let param_env = tcx.param_env(impl_did);
let ocx = ObligationCtxt::new(&infcx);
let cause = ObligationCause::misc(span, impl_did);
let pointee_ty = args.type_at(pointee_idx);
let obligation = Obligation::new(
tcx,
cause,
param_env,
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [pointee_ty]),
);
ocx.register_obligation(obligation);
if ocx.select_all_or_error().is_empty() {
return Err(tcx.dcx().emit_err(errors::CoercePointeePointeeMissingMaybeSized { span }));
}

Ok(())
}

Expand All @@ -937,24 +988,16 @@ fn try_extract_coerce_pointee_data<'tcx>(
info: &ty::CoercePointeeInfo<'tcx>,
) -> Result<(usize, DefId), ErrorGuaranteed> {
match info {
ty::CoercePointeeInfo::PointeeUnnormalized { ty, .. } => Err(tcx
.dcx()
.emit_err(errors::CoercePointeePointeeNotGenericPointee { span, got: ty.to_string() })),
ty::CoercePointeeInfo::PointeeIsConst { konst, .. } => {
Err(tcx.dcx().emit_err(errors::CoercePointeePointeeNotGenericPointee {
span,
got: konst.to_string(),
}))
}
ty::CoercePointeeInfo::Validated { pointee_index_in_args, impl_def_id } => {
Ok((*pointee_index_in_args, *impl_def_id))
}
ty::CoercePointeeInfo::Duplicated { .. } => Err(tcx
.dcx()
.span_delayed_bug(span, "a special error for duplicated CoercePointee is expected")),
ty::CoercePointeeInfo::PointeeNotFound { ty, .. } => {
Err(tcx.dcx().emit_err(errors::CoercePointeeNoPointee { span, ty: ty.to_string() }))
&ty::CoercePointeeInfo::Validated { pointee_index_in_args, impl_def_id } => {
Ok((pointee_index_in_args, impl_def_id))
}
ty::CoercePointeeInfo::PointeeUnnormalized { .. }
| ty::CoercePointeeInfo::PointeeIsConst { .. }
| ty::CoercePointeeInfo::PointeeNotFound { .. }
| ty::CoercePointeeInfo::Duplicated { .. } => Err(tcx.dcx().span_delayed_bug(
span,
"a more specific error for malformed CoercePointee is expected",
)),
}
}

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,13 @@ pub(crate) struct CoercePointeePointeeMultipleDerive {
pub spans: Vec<Span>,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_coerce_pointee_missing_maybe_sized, code = E0802)]
pub(crate) struct CoercePointeePointeeMissingMaybeSized {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_ty_outside_relevant, code = E0390)]
#[help]
Expand Down
Loading

0 comments on commit 9aabb55

Please sign in to comment.