Skip to content

Commit 8e48d60

Browse files
redact coerced type away
1 parent c182ce9 commit 8e48d60

File tree

10 files changed

+416
-69
lines changed

10 files changed

+416
-69
lines changed

compiler/rustc_codegen_cranelift/example/mini_core.rs

+5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ pub trait Unsize<T: ?Sized> {}
2929
#[lang = "coerce_unsized"]
3030
pub trait CoerceUnsized<T> {}
3131

32+
#[lang = "coerce_pointee_validated"]
33+
pub trait CoercePointeeValidated {
34+
/* compiler built-in */
35+
}
36+
3237
impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
3338
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
3439
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}

compiler/rustc_codegen_gcc/example/mini_core.rs

+37-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
#![feature(
2-
no_core, lang_items, intrinsics, unboxed_closures, extern_types,
3-
decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls,
2+
no_core,
3+
lang_items,
4+
intrinsics,
5+
unboxed_closures,
6+
extern_types,
7+
decl_macro,
8+
rustc_attrs,
9+
transparent_unions,
10+
auto_traits,
11+
freeze_impls,
412
thread_local
513
)]
614
#![no_core]
@@ -26,6 +34,11 @@ pub trait Unsize<T: ?Sized> {}
2634
#[lang = "coerce_unsized"]
2735
pub trait CoerceUnsized<T> {}
2836

37+
#[lang = "coerce_pointee_validated"]
38+
pub trait CoercePointeeValidated {
39+
/* compiler built-in */
40+
}
41+
2942
impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
3043
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
3144
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
@@ -35,13 +48,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
3548
pub trait DispatchFromDyn<T> {}
3649

3750
// &T -> &U
38-
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
51+
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
3952
// &mut T -> &mut U
40-
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
53+
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
4154
// *const T -> *const U
42-
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
55+
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
4356
// *mut T -> *mut U
44-
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
57+
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
4558
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}
4659

4760
#[lang = "legacy_receiver"]
@@ -289,7 +302,6 @@ impl PartialEq for u32 {
289302
}
290303
}
291304

292-
293305
impl PartialEq for u64 {
294306
fn eq(&self, other: &u64) -> bool {
295307
(*self) == (*other)
@@ -476,7 +488,11 @@ fn panic_in_cleanup() -> ! {
476488
#[track_caller]
477489
fn panic_bounds_check(index: usize, len: usize) -> ! {
478490
unsafe {
479-
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);
491+
libc::printf(
492+
"index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8,
493+
len,
494+
index,
495+
);
480496
intrinsics::abort();
481497
}
482498
}
@@ -504,8 +520,7 @@ pub trait Deref {
504520
fn deref(&self) -> &Self::Target;
505521
}
506522

507-
pub trait Allocator {
508-
}
523+
pub trait Allocator {}
509524

510525
impl Allocator for () {}
511526

@@ -699,19 +714,27 @@ pub struct VaList<'a>(&'a mut VaListImpl);
699714

700715
#[rustc_builtin_macro]
701716
#[rustc_macro_transparency = "semitransparent"]
702-
pub macro stringify($($t:tt)*) { /* compiler built-in */ }
717+
pub macro stringify($($t:tt)*) {
718+
/* compiler built-in */
719+
}
703720

704721
#[rustc_builtin_macro]
705722
#[rustc_macro_transparency = "semitransparent"]
706-
pub macro file() { /* compiler built-in */ }
723+
pub macro file() {
724+
/* compiler built-in */
725+
}
707726

708727
#[rustc_builtin_macro]
709728
#[rustc_macro_transparency = "semitransparent"]
710-
pub macro line() { /* compiler built-in */ }
729+
pub macro line() {
730+
/* compiler built-in */
731+
}
711732

712733
#[rustc_builtin_macro]
713734
#[rustc_macro_transparency = "semitransparent"]
714-
pub macro cfg() { /* compiler built-in */ }
735+
pub macro cfg() {
736+
/* compiler built-in */
737+
}
715738

716739
pub static A_STATIC: u8 = 42;
717740

compiler/rustc_hir_analysis/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ hir_analysis_cmse_output_stack_spill =
8585
.note1 = functions with the `"{$abi_name}"` ABI must pass their result via the available return registers
8686
.note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
8787
88+
hir_analysis_coerce_pointee_multiple_targets = `derive(CoercePointee)` only admits exactly one data field, {$diag_trait ->
89+
[DispatchFromDyn] to which `dyn` methods shall be dispatched
90+
*[CoerceUnsized] on which unsize coercion shall be performed
91+
}
92+
8893
hir_analysis_coerce_pointee_no_field = `CoercePointee` can only be derived on `struct`s with at least one field
8994
9095
hir_analysis_coerce_pointee_no_user_validity_assertion = asserting applicability of `derive(CoercePointee)` on a target data is forbidden

compiler/rustc_hir_analysis/src/coherence/builtin.rs

+108-31
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
//! Check properties that are required by built-in traits and set
22
//! up data structures required by type-checking/codegen.
33
4+
mod diagnostics;
5+
46
use std::assert_matches::assert_matches;
57
use std::collections::BTreeMap;
68

9+
use diagnostics::{extract_coerce_pointee_data, redact_fulfillment_err_for_coerce_pointee};
710
use rustc_data_structures::fx::FxHashSet;
811
use rustc_errors::{ErrorGuaranteed, MultiSpan};
912
use rustc_hir as hir;
@@ -12,6 +15,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
1215
use rustc_hir::lang_items::LangItem;
1316
use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt};
1417
use rustc_infer::traits::Obligation;
18+
use rustc_middle::bug;
1519
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
1620
use rustc_middle::ty::print::PrintTraitRefExt as _;
1721
use rustc_middle::ty::{
@@ -24,7 +28,7 @@ use rustc_trait_selection::traits::misc::{
2428
type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
2529
};
2630
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
27-
use tracing::debug;
31+
use tracing::{debug, instrument};
2832

2933
use crate::errors;
3034

@@ -187,10 +191,10 @@ fn visit_implementation_of_const_param_ty(
187191
}
188192
}
189193

194+
#[instrument(level = "debug", skip(checker), fields(impl_did = ?checker.impl_def_id))]
190195
fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
191196
let tcx = checker.tcx;
192197
let impl_did = checker.impl_def_id;
193-
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
194198

195199
// Just compute this for the side-effects, in particular reporting
196200
// errors; other parts of the code may demand it for the info of
@@ -199,11 +203,11 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E
199203
tcx.at(span).ensure_ok().coerce_unsized_info(impl_did)
200204
}
201205

206+
#[instrument(level = "debug", skip(checker), fields(impl_did = ?checker.impl_def_id))]
202207
fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
203208
let tcx = checker.tcx;
204209
let impl_did = checker.impl_def_id;
205210
let trait_ref = checker.impl_header.trait_ref.instantiate_identity();
206-
debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
207211

208212
let span = tcx.def_span(impl_did);
209213

@@ -307,29 +311,45 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
307311
.collect::<Vec<_>>();
308312

309313
if coerced_fields.is_empty() {
310-
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
311-
span,
312-
trait_name: "DispatchFromDyn",
313-
note: true,
314-
}));
314+
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
315+
res = Err(tcx.dcx().span_delayed_bug(
316+
span,
317+
"a specialised message for CoercePointee is expected",
318+
));
319+
} else {
320+
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
321+
span,
322+
trait_name: "DispatchFromDyn",
323+
note: true,
324+
}));
325+
}
315326
} else if coerced_fields.len() > 1 {
316-
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti {
317-
span,
318-
coercions_note: true,
319-
number: coerced_fields.len(),
320-
coercions: coerced_fields
321-
.iter()
322-
.map(|field| {
323-
format!(
324-
"`{}` (`{}` to `{}`)",
325-
field.name,
326-
field.ty(tcx, args_a),
327-
field.ty(tcx, args_b),
328-
)
329-
})
330-
.collect::<Vec<_>>()
331-
.join(", "),
332-
}));
327+
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
328+
let spans =
329+
coerced_fields.iter().map(|field| tcx.def_span(field.did)).collect();
330+
res = Err(tcx.dcx().emit_err(errors::CoercePointeeMultipleTargets {
331+
spans,
332+
diag_trait: "DispatchFromDyn",
333+
}));
334+
} else {
335+
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti {
336+
span,
337+
coercions_note: true,
338+
number: coerced_fields.len(),
339+
coercions: coerced_fields
340+
.iter()
341+
.map(|field| {
342+
format!(
343+
"`{}` (`{}` to `{}`)",
344+
field.name,
345+
field.ty(tcx, args_a),
346+
field.ty(tcx, args_b),
347+
)
348+
})
349+
.collect::<Vec<_>>()
350+
.join(", "),
351+
}));
352+
}
333353
} else {
334354
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
335355
for field in coerced_fields {
@@ -344,8 +364,26 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
344364
),
345365
));
346366
}
347-
let errors = ocx.select_all_or_error();
367+
let mut errors = ocx.select_all_or_error();
348368
if !errors.is_empty() {
369+
if let Some((pointee_idx, _)) = extract_coerce_pointee_data(tcx, def_a.did()) {
370+
let target_pointee = args_b.type_at(pointee_idx);
371+
let source_pointee = args_a.type_at(pointee_idx);
372+
let new_pointee =
373+
diagnostics::unsized_type_for_coerce_pointee(tcx, source_pointee);
374+
375+
errors = errors
376+
.into_iter()
377+
.map(|err| {
378+
redact_fulfillment_err_for_coerce_pointee(
379+
tcx,
380+
err,
381+
target_pointee,
382+
new_pointee,
383+
)
384+
})
385+
.collect();
386+
}
349387
res = Err(infcx.err_ctxt().report_fulfillment_errors(errors));
350388
}
351389

@@ -360,27 +398,29 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
360398
}
361399
}
362400

401+
#[instrument(level = "debug", skip(tcx))]
363402
pub(crate) fn coerce_unsized_info<'tcx>(
364403
tcx: TyCtxt<'tcx>,
365404
impl_did: LocalDefId,
366405
) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
367-
debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
368406
let span = tcx.def_span(impl_did);
369407

370408
let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
371409

372410
let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
373411

374412
let source = tcx.type_of(impl_did).instantiate_identity();
413+
let self_ty = source;
375414
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
376415
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
377416
let target = trait_ref.args.type_at(1);
378-
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
417+
let coerced_ty = target;
418+
debug!("{:?} -> {:?} (bound)", source, target);
379419

380420
let param_env = tcx.param_env(impl_did);
381421
assert!(!source.has_escaping_bound_vars());
382422

383-
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
423+
debug!("{:?} -> {:?} (free)", source, target);
384424

385425
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
386426
let cause = ObligationCause::misc(span, impl_did);
@@ -509,12 +549,28 @@ pub(crate) fn coerce_unsized_info<'tcx>(
509549
.collect::<Vec<_>>();
510550

511551
if diff_fields.is_empty() {
552+
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
553+
return Err(tcx.dcx().span_delayed_bug(
554+
span,
555+
"a specialised message for CoercePointee is expected",
556+
));
557+
}
512558
return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
513559
span,
514560
trait_name: "CoerceUnsized",
515561
note: true,
516562
}));
517563
} else if diff_fields.len() > 1 {
564+
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
565+
let spans = diff_fields
566+
.iter()
567+
.map(|&(idx, _, _)| tcx.def_span(fields[idx].did))
568+
.collect();
569+
return Err(tcx.dcx().emit_err(errors::CoercePointeeMultipleTargets {
570+
spans,
571+
diag_trait: "CoerceUnsized",
572+
}));
573+
}
518574
let item = tcx.hir().expect_item(impl_did);
519575
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
520576
t.path.span
@@ -547,17 +603,38 @@ pub(crate) fn coerce_unsized_info<'tcx>(
547603
};
548604

549605
// Register an obligation for `A: Trait<B>`.
606+
let coerce_pointee_data = if let ty::Adt(def, _) = self_ty.kind() {
607+
extract_coerce_pointee_data(tcx, def.did())
608+
} else {
609+
None
610+
};
550611
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
551-
let cause = traits::ObligationCause::misc(span, impl_did);
612+
let cause = traits::ObligationCause::misc(
613+
span,
614+
coerce_pointee_data.map_or(impl_did, |(_, impl_did)| impl_did.expect_local()),
615+
);
552616
let obligation = Obligation::new(
553617
tcx,
554618
cause,
555619
param_env,
556620
ty::TraitRef::new(tcx, trait_def_id, [source, target]),
557621
);
558622
ocx.register_obligation(obligation);
559-
let errors = ocx.select_all_or_error();
623+
let mut errors = ocx.select_all_or_error();
560624
if !errors.is_empty() {
625+
if let Some((pointee, _)) = coerce_pointee_data {
626+
let ty::Adt(_def, args) = coerced_ty.kind() else { bug!() };
627+
let target_pointee = args.type_at(pointee);
628+
let ty::Adt(_def, args) = self_ty.kind() else { bug!() };
629+
let source_pointee = args.type_at(pointee);
630+
let new_pointee = diagnostics::unsized_type_for_coerce_pointee(tcx, source_pointee);
631+
errors = errors
632+
.into_iter()
633+
.map(|err| {
634+
redact_fulfillment_err_for_coerce_pointee(tcx, err, target_pointee, new_pointee)
635+
})
636+
.collect();
637+
}
561638
infcx.err_ctxt().report_fulfillment_errors(errors);
562639
}
563640

0 commit comments

Comments
 (0)