Skip to content

Commit 41ef5b5

Browse files
redact coerced type away
1 parent a3d4bd3 commit 41ef5b5

File tree

8 files changed

+382
-69
lines changed

8 files changed

+382
-69
lines changed

compiler/rustc_codegen_gcc/example/mini_core.rs

+32-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]
@@ -35,13 +43,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
3543
pub trait DispatchFromDyn<T> {}
3644

3745
// &T -> &U
38-
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
46+
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
3947
// &mut T -> &mut U
40-
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
48+
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
4149
// *const T -> *const U
42-
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
50+
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
4351
// *mut T -> *mut U
44-
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
52+
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
4553
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}
4654

4755
#[lang = "legacy_receiver"]
@@ -292,7 +300,6 @@ impl PartialEq for u32 {
292300
}
293301
}
294302

295-
296303
impl PartialEq for u64 {
297304
fn eq(&self, other: &u64) -> bool {
298305
(*self) == (*other)
@@ -479,7 +486,11 @@ fn panic_in_cleanup() -> ! {
479486
#[track_caller]
480487
fn panic_bounds_check(index: usize, len: usize) -> ! {
481488
unsafe {
482-
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);
489+
libc::printf(
490+
"index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8,
491+
len,
492+
index,
493+
);
483494
intrinsics::abort();
484495
}
485496
}
@@ -507,8 +518,7 @@ pub trait Deref {
507518
fn deref(&self) -> &Self::Target;
508519
}
509520

510-
pub trait Allocator {
511-
}
521+
pub trait Allocator {}
512522

513523
impl Allocator for () {}
514524

@@ -702,19 +712,27 @@ pub struct VaList<'a>(&'a mut VaListImpl);
702712

703713
#[rustc_builtin_macro]
704714
#[rustc_macro_transparency = "semitransparent"]
705-
pub macro stringify($($t:tt)*) { /* compiler built-in */ }
715+
pub macro stringify($($t:tt)*) {
716+
/* compiler built-in */
717+
}
706718

707719
#[rustc_builtin_macro]
708720
#[rustc_macro_transparency = "semitransparent"]
709-
pub macro file() { /* compiler built-in */ }
721+
pub macro file() {
722+
/* compiler built-in */
723+
}
710724

711725
#[rustc_builtin_macro]
712726
#[rustc_macro_transparency = "semitransparent"]
713-
pub macro line() { /* compiler built-in */ }
727+
pub macro line() {
728+
/* compiler built-in */
729+
}
714730

715731
#[rustc_builtin_macro]
716732
#[rustc_macro_transparency = "semitransparent"]
717-
pub macro cfg() { /* compiler built-in */ }
733+
pub macro cfg() {
734+
/* compiler built-in */
735+
}
718736

719737
pub static A_STATIC: u8 = 42;
720738

compiler/rustc_hir_analysis/messages.ftl

+13
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,19 @@ hir_analysis_cmse_output_stack_spill =
8585
.note1 = functions with the `{$abi}` 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_cannot_coerce_unsize = `{$ty}` cannot be coerced to an unsized type
89+
.note = `derive(CoercePointee)` demands that `{$ty}` can be coerced to an unsized type
90+
.help = the standard pointers such as `Arc`, `Rc`, `Box`, and other types with `derive(CoercePointee)` can be coerced to their corresponding unsized types
91+
92+
hir_analysis_coerce_pointee_cannot_unsize = `{$ty}` cannot be coerced to any unsized value
93+
.note = `derive(CoercePointee)` demands that `{$ty}` can be coerced to an unsized type
94+
.help = `derive(CoercePointee)` requires exactly one copy of `#[pointee]` type at the end of the `struct` definition, without any further pointer or reference indirection
95+
96+
hir_analysis_coerce_pointee_multiple_targets = `derive(CoercePointee)` only admits exactly one data field, {$diag_trait ->
97+
[DispatchFromDyn] to which `dyn` methods shall be dispatched
98+
*[CoerceUnsized] on which unsize coercion shall be performed
99+
}
100+
88101
hir_analysis_coerce_pointee_no_field = `CoercePointee` can only be derived on `struct`s with at least one field
89102
90103
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

+116-33
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,9 +364,31 @@ 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() {
349-
res = Err(infcx.err_ctxt().report_fulfillment_errors(errors));
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+
372+
errors = errors
373+
.into_iter()
374+
.filter_map(|err| {
375+
redact_fulfillment_err_for_coerce_pointee(
376+
tcx,
377+
err,
378+
target_pointee,
379+
span,
380+
)
381+
})
382+
.collect();
383+
}
384+
if errors.is_empty() {
385+
res = Err(tcx.dcx().span_delayed_bug(
386+
span,
387+
"a specialised CoercePointee error is expected",
388+
));
389+
} else {
390+
res = Err(infcx.err_ctxt().report_fulfillment_errors(errors));
391+
}
350392
}
351393

352394
// Finally, resolve all regions.
@@ -360,27 +402,29 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
360402
}
361403
}
362404

405+
#[instrument(level = "debug", skip(tcx))]
363406
pub(crate) fn coerce_unsized_info<'tcx>(
364407
tcx: TyCtxt<'tcx>,
365408
impl_did: LocalDefId,
366409
) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
367-
debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
368410
let span = tcx.def_span(impl_did);
369411

370412
let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
371413

372414
let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
373415

374416
let source = tcx.type_of(impl_did).instantiate_identity();
417+
let self_ty = source;
375418
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
376419
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
377420
let target = trait_ref.args.type_at(1);
378-
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
421+
let coerced_ty = target;
422+
debug!("{:?} -> {:?} (bound)", source, target);
379423

380424
let param_env = tcx.param_env(impl_did);
381425
assert!(!source.has_escaping_bound_vars());
382426

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

385429
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
386430
let cause = ObligationCause::misc(span, impl_did);
@@ -509,12 +553,28 @@ pub(crate) fn coerce_unsized_info<'tcx>(
509553
.collect::<Vec<_>>();
510554

511555
if diff_fields.is_empty() {
556+
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
557+
return Err(tcx.dcx().span_delayed_bug(
558+
span,
559+
"a specialised message for CoercePointee is expected",
560+
));
561+
}
512562
return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
513563
span,
514564
trait_name: "CoerceUnsized",
515565
note: true,
516566
}));
517567
} else if diff_fields.len() > 1 {
568+
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
569+
let spans = diff_fields
570+
.iter()
571+
.map(|&(idx, _, _)| tcx.def_span(fields[idx].did))
572+
.collect();
573+
return Err(tcx.dcx().emit_err(errors::CoercePointeeMultipleTargets {
574+
spans,
575+
diag_trait: "CoerceUnsized",
576+
}));
577+
}
518578
let item = tcx.hir().expect_item(impl_did);
519579
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
520580
t.path.span
@@ -547,18 +607,41 @@ pub(crate) fn coerce_unsized_info<'tcx>(
547607
};
548608

549609
// Register an obligation for `A: Trait<B>`.
610+
let coerce_pointee_data = if let ty::Adt(def, _) = self_ty.kind() {
611+
extract_coerce_pointee_data(tcx, def.did())
612+
} else {
613+
None
614+
};
550615
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
551-
let cause = traits::ObligationCause::misc(span, impl_did);
616+
let cause = traits::ObligationCause::misc(
617+
span,
618+
coerce_pointee_data.map_or(impl_did, |(_, impl_did)| impl_did.expect_local()),
619+
);
552620
let obligation = Obligation::new(
553621
tcx,
554622
cause,
555623
param_env,
556624
ty::TraitRef::new(tcx, trait_def_id, [source, target]),
557625
);
558626
ocx.register_obligation(obligation);
559-
let errors = ocx.select_all_or_error();
627+
let mut errors = ocx.select_all_or_error();
560628
if !errors.is_empty() {
561-
infcx.err_ctxt().report_fulfillment_errors(errors);
629+
if let Some((pointee, _)) = coerce_pointee_data {
630+
let ty::Adt(_def, args) = coerced_ty.kind() else { bug!() };
631+
let target_pointee = args.type_at(pointee);
632+
let ty::Adt(_def, _) = self_ty.kind() else { bug!() };
633+
errors = errors
634+
.into_iter()
635+
.filter_map(|err| {
636+
redact_fulfillment_err_for_coerce_pointee(tcx, err, target_pointee, span)
637+
})
638+
.collect();
639+
}
640+
if errors.is_empty() {
641+
tcx.dcx().span_delayed_bug(span, "a specialised CoercePointee error is expected");
642+
} else {
643+
infcx.err_ctxt().report_fulfillment_errors(errors);
644+
}
562645
}
563646

564647
// Finally, resolve all regions.

0 commit comments

Comments
 (0)