Skip to content

Commit

Permalink
redact coerced types away
Browse files Browse the repository at this point in the history
  • Loading branch information
dingxiangfei2009 committed Feb 17, 2025
1 parent 2162e9d commit 51fc2ea
Show file tree
Hide file tree
Showing 7 changed files with 383 additions and 43 deletions.
46 changes: 32 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 Down Expand Up @@ -35,13 +43,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 @@ -292,7 +300,6 @@ impl PartialEq for u32 {
}
}


impl PartialEq for u64 {
fn eq(&self, other: &u64) -> bool {
(*self) == (*other)
Expand Down Expand Up @@ -479,7 +486,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 @@ -507,8 +518,7 @@ pub trait Deref {
fn deref(&self) -> &Self::Target;
}

pub trait Allocator {
}
pub trait Allocator {}

impl Allocator for () {}

Expand Down Expand Up @@ -702,19 +712,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
13 changes: 13 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ hir_analysis_cmse_output_stack_spill =
.note1 = functions with the `{$abi}` 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_cannot_coerce_unsize = `{$ty}` cannot be coerced to an unsized type
.note = `derive(CoercePointee)` demands that `{$ty}` can be coerced to an unsized type
.help = the standard pointers such as `Arc`, `Rc`, `Box`, and other types with `derive(CoercePointee)` can be coerced to their corresponding unsized types
hir_analysis_coerce_pointee_cannot_unsize = `{$ty}` cannot be coerced to any unsized value
.note = `derive(CoercePointee)` demands that `{$ty}` can be coerced to an unsized type
.help = `derive(CoercePointee)` requires exactly one copy of `#[pointee]` type at the end of the `struct` definition, without any further pointer or reference indirection
hir_analysis_coerce_pointee_multiple_targets = `derive(CoercePointee)` only admits exactly one data field, {$diag_trait ->
[DispatchFromDyn] to which `dyn` methods shall be dispatched
*[CoerceUnsized] on which unsize coercion shall be performed
}
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
Expand Down
137 changes: 110 additions & 27 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
//! Check properties that are required by built-in traits and set
//! up data structures required by type-checking/codegen.
mod diagnostics;

use std::assert_matches::assert_matches;
use std::collections::BTreeMap;

use diagnostics::{extract_coerce_pointee_data, redact_fulfillment_err_for_coerce_pointee};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
Expand All @@ -12,6 +15,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::bug;
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::print::PrintTraitRefExt as _;
use rustc_middle::ty::{
Expand Down Expand Up @@ -307,29 +311,45 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
.collect::<Vec<_>>();

if coerced_fields.is_empty() {
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
span,
trait_name: "DispatchFromDyn",
note: true,
}));
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
res = Err(tcx.dcx().span_delayed_bug(
span,
"a specialised message for CoercePointee is expected",
));
} else {
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
span,
trait_name: "DispatchFromDyn",
note: true,
}));
}
} else if coerced_fields.len() > 1 {
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti {
span,
coercions_note: true,
number: coerced_fields.len(),
coercions: coerced_fields
.iter()
.map(|field| {
format!(
"`{}` (`{}` to `{}`)",
field.name,
field.ty(tcx, args_a),
field.ty(tcx, args_b),
)
})
.collect::<Vec<_>>()
.join(", "),
}));
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
let spans =
coerced_fields.iter().map(|field| tcx.def_span(field.did)).collect();
res = Err(tcx.dcx().emit_err(errors::CoercePointeeMultipleTargets {
spans,
diag_trait: "DispatchFromDyn",
}));
} else {
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti {
span,
coercions_note: true,
number: coerced_fields.len(),
coercions: coerced_fields
.iter()
.map(|field| {
format!(
"`{}` (`{}` to `{}`)",
field.name,
field.ty(tcx, args_a),
field.ty(tcx, args_b),
)
})
.collect::<Vec<_>>()
.join(", "),
}));
}
} else {
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
for field in coerced_fields {
Expand All @@ -344,9 +364,31 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
),
));
}
let errors = ocx.select_all_or_error();
let mut errors = ocx.select_all_or_error();
if !errors.is_empty() {
res = Err(infcx.err_ctxt().report_fulfillment_errors(errors));
if let Some((pointee_idx, _)) = extract_coerce_pointee_data(tcx, def_a.did()) {
let target_pointee = args_b.type_at(pointee_idx);

errors = errors
.into_iter()
.filter_map(|err| {
redact_fulfillment_err_for_coerce_pointee(
tcx,
err,
target_pointee,
span,
)
})
.collect();
}
if errors.is_empty() {
res = Err(tcx.dcx().span_delayed_bug(
span,
"a specialised CoercePointee error is expected",
));
} else {
res = Err(infcx.err_ctxt().report_fulfillment_errors(errors));
}
}

// Finally, resolve all regions.
Expand All @@ -372,9 +414,11 @@ pub(crate) fn coerce_unsized_info<'tcx>(
let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));

let source = tcx.type_of(impl_did).instantiate_identity();
let self_ty = source;
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
let target = trait_ref.args.type_at(1);
let coerced_ty = target;
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);

let param_env = tcx.param_env(impl_did);
Expand Down Expand Up @@ -509,12 +553,28 @@ pub(crate) fn coerce_unsized_info<'tcx>(
.collect::<Vec<_>>();

if diff_fields.is_empty() {
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
return Err(tcx.dcx().span_delayed_bug(
span,
"a specialised message for CoercePointee is expected",
));
}
return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
span,
trait_name: "CoerceUnsized",
note: true,
}));
} else if diff_fields.len() > 1 {
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
let spans = diff_fields
.iter()
.map(|&(idx, _, _)| tcx.def_span(fields[idx].did))
.collect();
return Err(tcx.dcx().emit_err(errors::CoercePointeeMultipleTargets {
spans,
diag_trait: "CoerceUnsized",
}));
}
let item = tcx.hir().expect_item(impl_did);
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
t.path.span
Expand Down Expand Up @@ -547,18 +607,41 @@ pub(crate) fn coerce_unsized_info<'tcx>(
};

// Register an obligation for `A: Trait<B>`.
let coerce_pointee_data = if let ty::Adt(def, _) = self_ty.kind() {
extract_coerce_pointee_data(tcx, def.did())
} else {
None
};
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let cause = traits::ObligationCause::misc(span, impl_did);
let cause = traits::ObligationCause::misc(
span,
coerce_pointee_data.map_or(impl_did, |(_, impl_did)| impl_did.expect_local()),
);
let obligation = Obligation::new(
tcx,
cause,
param_env,
ty::TraitRef::new(tcx, trait_def_id, [source, target]),
);
ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
let mut errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(errors);
if let Some((pointee, _)) = coerce_pointee_data {
let ty::Adt(_def, args) = coerced_ty.kind() else { bug!() };
let target_pointee = args.type_at(pointee);
let ty::Adt(_def, _) = self_ty.kind() else { bug!() };
errors = errors
.into_iter()
.filter_map(|err| {
redact_fulfillment_err_for_coerce_pointee(tcx, err, target_pointee, span)
})
.collect();
}
if errors.is_empty() {
tcx.dcx().span_delayed_bug(span, "a specialised CoercePointee error is expected");
} else {
infcx.err_ctxt().report_fulfillment_errors(errors);
}
}

// Finally, resolve all regions.
Expand Down
Loading

0 comments on commit 51fc2ea

Please sign in to comment.